]> git.decadent.org.uk Git - ion3.git/blob - ioncore/group-ws.c
48ee838cb4a5a7dccdd00b83ae175ebf2f82847c
[ion3.git] / ioncore / group-ws.c
1 /*
2  * ion/ioncore/group-ws.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <string.h>
13
14 #include <libtu/minmax.h>
15 #include <libtu/objp.h>
16
17 #include "common.h"
18 #include "global.h"
19 #include "region.h"
20 #include "focus.h"
21 #include "group.h"
22 #include "regbind.h"
23 #include "bindmaps.h"
24 #include "xwindow.h"
25 #include "group-ws.h"
26 #include "group-cw.h"
27 #include "grouppholder.h"
28 #include "groupedpholder.h"
29 #include "framedpholder.h"
30 #include "float-placement.h"
31 #include "resize.h"
32 #include "conf.h"
33
34
35 /*{{{ Settings */
36
37
38 void ioncore_groupws_set(ExtlTab tab)
39 {
40     char *method=NULL;
41     ExtlTab t;
42     
43     if(extl_table_gets_s(tab, "float_placement_method", &method)){
44         if(strcmp(method, "udlr")==0)
45             ioncore_placement_method=PLACEMENT_UDLR;
46         else if(strcmp(method, "lrud")==0)
47             ioncore_placement_method=PLACEMENT_LRUD;
48         else if(strcmp(method, "random")==0)
49             ioncore_placement_method=PLACEMENT_RANDOM;
50         else
51             warn(TR("Unknown placement method \"%s\"."), method);
52         free(method);
53     }
54 }
55
56
57 void ioncore_groupws_get(ExtlTab t)
58 {
59     extl_table_sets_s(t, "float_placement_method", 
60                       (ioncore_placement_method==PLACEMENT_UDLR
61                        ? "udlr" 
62                        : (ioncore_placement_method==PLACEMENT_LRUD
63                           ? "lrud" 
64                           : "random")));
65 }
66
67
68 /*}}}*/
69
70
71 /*{{{ Attach stuff */
72
73
74 static bool groupws_attach_framed(WGroupWS *ws, 
75                                   WGroupAttachParams *ap,
76                                   WFramedParam *fp,
77                                   WRegion *reg)
78 {
79     WRegionAttachData data;
80     
81     data.type=REGION_ATTACH_REPARENT;
82     data.u.reg=reg;
83     
84     return (region_attach_framed((WRegion*)ws, fp,
85                                  (WRegionAttachFn*)group_do_attach,
86                                  ap, &data)!=NULL);
87 }
88
89
90 bool groupws_handle_drop(WGroupWS *ws, int x, int y,
91                          WRegion *dropped)
92 {
93     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
94     WFramedParam fp=FRAMEDPARAM_INIT;
95     
96     ap.switchto_set=TRUE;
97     ap.switchto=TRUE;
98     
99     fp.inner_geom_gravity_set=TRUE;
100     fp.inner_geom.x=x;
101     fp.inner_geom.y=y;
102     fp.inner_geom.w=REGION_GEOM(dropped).w;
103     fp.inner_geom.h=REGION_GEOM(dropped).h;
104     fp.gravity=NorthWestGravity;
105     
106     return groupws_attach_framed(ws, &ap, &fp, dropped);
107 }
108
109
110 /*EXTL_DOC
111  * Attach region \var{reg} on \var{ws}.
112  * At least the following fields in \var{t} are supported:
113  * 
114  * \begin{tabularx}{\linewidth}{lX}
115  *  \tabhead{Field & Description}
116  *  \var{switchto} & Should the region be switched to (boolean)? Optional. \\
117  *  \var{geom} & Geometry; \var{x} and \var{y}, if set, indicates top-left of 
118  *   the frame to be created while \var{width} and \var{height}, if set, indicate
119  *   the size of the client window within that frame. Optional.
120  * \end{tabularx}
121  */
122 EXTL_EXPORT_AS(WGroupWS, attach_framed)
123 bool groupws_attach_framed_extl(WGroupWS *ws, WRegion *reg, ExtlTab t)
124 {
125     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
126     WFramedParam fp=FRAMEDPARAM_INIT;
127     ExtlTab gt;
128     
129     if(reg==NULL)
130         return FALSE;
131     
132     fp.gravity=ForgetGravity;
133     
134     if(extl_table_is_bool_set(t, "switchto")){
135         ap.switchto_set=TRUE;
136         ap.switchto=TRUE;
137     }
138     
139     if(extl_table_gets_t(t, "geom", &gt)){
140         int pos=0, size=0;
141         
142         fp.inner_geom.x=0;
143         fp.inner_geom.y=0;
144
145         if(extl_table_gets_i(gt, "x", &(ap.geom.x)))
146             pos++;
147         if(extl_table_gets_i(gt, "y", &(ap.geom.y)))
148             pos++;
149     
150         if(extl_table_gets_i(gt, "w", &(ap.geom.w)))
151             size++;
152         if(extl_table_gets_i(gt, "h", &(ap.geom.h)))
153             size++;
154         
155         fp.inner_geom.w=maxof(fp.inner_geom.w, 1);
156         fp.inner_geom.h=maxof(fp.inner_geom.h, 1);
157         
158         fp.inner_geom_gravity_set=(size==2 && pos==2);
159         
160         extl_unref_table(gt);
161     }
162     
163     return groupws_attach_framed(ws, &ap, &fp, reg);
164 }
165
166
167 /*}}}*/
168
169
170 /*{{{ groupws_prepare_manage */
171
172
173 static WPHolder *groupws_do_prepare_manage(WGroupWS *ws, 
174                                            const WClientWin *cwin,
175                                            const WManageParams *param, 
176                                            int redir, int geom_weak)
177 {
178     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
179     WFramedParam fp=FRAMEDPARAM_INIT;
180     WPHolder *ph;
181     
182     if(redir==MANAGE_REDIR_PREFER_YES){
183         WRegion *r=(ws->grp.current_managed!=NULL 
184                     ? ws->grp.current_managed->reg 
185                     : NULL);
186         WGroupIterTmp tmp;
187         WPHolder *ph=NULL;
188         
189         if(r!=NULL)
190             ph=region_prepare_manage(r, cwin, param, MANAGE_REDIR_PREFER_YES);
191         
192         if(ph==NULL){
193             FOR_ALL_MANAGED_BY_GROUP(&ws->grp, r, tmp){
194                 ph=region_prepare_manage(r, cwin, param, 
195                                          MANAGE_REDIR_PREFER_YES);
196                 if(ph!=NULL)
197                     break;
198             }
199         }
200     }
201     
202     if(redir==MANAGE_REDIR_STRICT_YES)
203         return NULL;
204
205     fp.inner_geom_gravity_set=TRUE;
206     fp.inner_geom=param->geom;
207     fp.gravity=param->gravity;
208     
209     ap.geom_weak_set=1;
210     ap.geom_weak=geom_weak;
211
212     ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
213     
214     if(ph!=NULL)
215         ph=pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
216     
217     if(ph!=NULL)
218         ph=pholder_either((WPHolder*)create_groupedpholder((WPHolder*)ph), ph);
219     
220     return ph;
221 }
222
223
224 WPHolder *groupws_prepare_manage(WGroupWS *ws, const WClientWin *cwin,
225                                  const WManageParams *param,
226                                  int redir)
227 {
228     WRegion *b=(ws->grp.bottom!=NULL ? ws->grp.bottom->reg : NULL);
229     WPHolder *ph=NULL;
230     bool act_b=(ws->grp.bottom==ws->grp.current_managed);
231     bool use_bottom;
232     int weak=0;
233     
234     if(param->maprq && ioncore_g.opmode!=IONCORE_OPMODE_INIT
235        && !param->userpos){
236         /* When the window is mapped by application request, position
237          * request is only honoured if the position was given by the user
238          * and in case of a transient (the app may know better where to 
239          * place them) or if we're initialising.
240          */
241         weak=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
242     }
243
244     if(b!=NULL && !HAS_DYN(b, region_prepare_manage))
245         b=NULL;
246     
247     use_bottom=(act_b
248                 ? !extl_table_is_bool_set(cwin->proptab, "float")
249                 : act_b);
250     
251     if(b!=NULL && use_bottom)
252         ph=region_prepare_manage(b, cwin, param, redir);
253     
254     if(ph==NULL)
255         ph=groupws_do_prepare_manage(ws, cwin, param, redir, weak);
256
257     if(ph==NULL && b!=NULL && !use_bottom)
258         ph=region_prepare_manage(b, cwin, param, redir);
259     
260     return ph;
261 }
262
263
264 WPHolder *groupws_prepare_manage_transient(WGroupWS *ws, const WClientWin *cwin,
265                                            const WManageParams *param,
266                                            int unused)
267 {
268     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
269     WFramedParam fp=FRAMEDPARAM_INIT;
270     WPHolder *ph;
271     
272     ap.stack_above=OBJ_CAST(REGION_PARENT(param->tfor), WRegion);
273     if(ap.stack_above==NULL)
274         return NULL;
275     
276     fp.inner_geom_gravity_set=TRUE;
277     fp.inner_geom=param->geom;
278     fp.gravity=param->gravity;
279     fp.mode=FRAME_MODE_TRANSIENT;
280     
281     ap.geom_weak_set=1;
282     ap.geom_weak=0;
283
284     ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
285     
286     return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
287 }
288
289
290 WPHolder *groupws_get_rescue_pholder_for(WGroupWS *ws, 
291                                          WRegion *forwhat)
292 {
293     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
294     WFramedParam fp=FRAMEDPARAM_INIT;
295     WPHolder *ph;
296     
297     ap.geom_set=TRUE;
298     ap.geom=REGION_GEOM(forwhat);
299
300     ap.geom_weak_set=1;
301     ap.geom_weak=(REGION_PARENT(forwhat)!=REGION_PARENT(ws)
302                   ? REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y
303                   : 0);
304
305     ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
306     
307     return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
308 }
309
310
311 /*}}}*/
312
313
314 /*{{{ WGroupWS class */
315
316
317 bool groupws_init(WGroupWS *ws, WWindow *parent, const WFitParams *fp)
318 {
319     if(!group_init(&(ws->grp), parent, fp))
320         return FALSE;
321
322     ((WRegion*)ws)->flags|=REGION_GRAB_ON_PARENT;
323     
324     region_add_bindmap((WRegion*)ws, ioncore_groupws_bindmap);
325     
326     return TRUE;
327 }
328
329
330 WGroupWS *create_groupws(WWindow *parent, const WFitParams *fp)
331 {
332     CREATEOBJ_IMPL(WGroupWS, groupws, (p, parent, fp));
333 }
334
335
336 void groupws_deinit(WGroupWS *ws)
337 {    
338     group_deinit(&(ws->grp));
339 }
340
341
342 WRegion *groupws_load(WWindow *par, const WFitParams *fp, 
343                       ExtlTab tab)
344 {
345     WGroupWS *ws;
346     
347     ws=create_groupws(par, fp);
348     
349     if(ws==NULL)
350         return NULL;
351
352     group_do_load(&ws->grp, tab);
353     
354     return (WRegion*)ws;
355 }
356
357
358 static DynFunTab groupws_dynfuntab[]={
359     {(DynFun*)region_prepare_manage, 
360      (DynFun*)groupws_prepare_manage},
361     
362     {(DynFun*)region_prepare_manage_transient,
363      (DynFun*)groupws_prepare_manage_transient},
364     
365     {(DynFun*)region_handle_drop,
366      (DynFun*)groupws_handle_drop},
367     
368     {(DynFun*)region_get_rescue_pholder_for,
369      (DynFun*)groupws_get_rescue_pholder_for},
370     
371     {region_manage_stdisp,
372      group_manage_stdisp},
373     
374     END_DYNFUNTAB
375 };
376
377
378 EXTL_EXPORT
379 IMPLCLASS(WGroupWS, WGroup, groupws_deinit, groupws_dynfuntab);
380
381
382 /*}}}*/
383