]> git.decadent.org.uk Git - ion3.git/blob - ioncore/group-ws.c
[svn-inject] Installing original source of ion3
[ion3.git] / ioncore / group-ws.c
1 /*
2  * ion/ioncore/group-ws.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2006. 
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
33
34 /*{{{ Settings */
35
36
37 static bool default_ws_params_set=FALSE;
38 static ExtlTab default_ws_params;
39
40
41 /*EXTL_DOC
42  * Set module basic settings. Currently only the \code{placement_method} 
43  * parameter is supported.
44  *
45  * The method can be one  of ''udlr'', ''lrud'' (default) and ''random''. 
46  * The ''udlr'' method looks for free space starting from top the top left
47  * corner of the workspace moving first down keeping the x coordinate fixed.
48  * If it find no free space, it start looking similarly at next x coordinate
49  * unoccupied by other objects and so on. ''lrud' is the same but with the 
50  * role of coordinates changed and both fall back to ''random'' placement 
51  * if no free area was found.
52  */
53
54 void ioncore_groupws_set(ExtlTab tab)
55 {
56     char *method=NULL;
57     ExtlTab t;
58     
59     if(extl_table_gets_s(tab, "float_placement_method", &method)){
60         if(strcmp(method, "udlr")==0)
61             ioncore_placement_method=PLACEMENT_UDLR;
62         else if(strcmp(method, "lrud")==0)
63             ioncore_placement_method=PLACEMENT_LRUD;
64         else if(strcmp(method, "random")==0)
65             ioncore_placement_method=PLACEMENT_RANDOM;
66         else
67             warn(TR("Unknown placement method \"%s\"."), method);
68         free(method);
69     }
70     
71     if(extl_table_gets_t(tab, "default_ws_params", &t)){
72         if(default_ws_params_set)
73             extl_unref_table(default_ws_params);
74         default_ws_params=t;
75         default_ws_params_set=TRUE;
76     }
77 }
78
79
80 void ioncore_groupws_get(ExtlTab t)
81 {
82     extl_table_sets_s(t, "float_placement_method", 
83                       (ioncore_placement_method==PLACEMENT_UDLR
84                        ? "udlr" 
85                        : (ioncore_placement_method==PLACEMENT_LRUD
86                           ? "lrud" 
87                           : "random")));
88     
89     if(default_ws_params_set)
90         extl_table_sets_t(t, "default_ws_params", default_ws_params);
91 }
92
93
94 /*}}}*/
95
96
97 /*{{{ Attach stuff */
98
99
100 static bool groupws_attach_framed(WGroupWS *ws, 
101                                   WGroupAttachParams *ap,
102                                   WFramedParam *fp,
103                                   WRegion *reg)
104 {
105     WRegionAttachData data;
106     
107     data.type=REGION_ATTACH_REPARENT;
108     data.u.reg=reg;
109     
110     return (region_attach_framed((WRegion*)ws, fp,
111                                  (WRegionAttachFn*)group_do_attach,
112                                  ap, &data)!=NULL);
113 }
114
115
116 bool groupws_handle_drop(WGroupWS *ws, int x, int y,
117                          WRegion *dropped)
118 {
119     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
120     WFramedParam fp=FRAMEDPARAM_INIT;
121     
122     ap.switchto_set=TRUE;
123     ap.switchto=TRUE;
124     
125     fp.inner_geom_gravity_set=TRUE;
126     fp.inner_geom.x=x;
127     fp.inner_geom.y=y;
128     fp.inner_geom.w=REGION_GEOM(dropped).w;
129     fp.inner_geom.h=REGION_GEOM(dropped).h;
130     fp.gravity=NorthWestGravity;
131     
132     return groupws_attach_framed(ws, &ap, &fp, dropped);
133 }
134
135
136 /*EXTL_DOC
137  * Attach region \var{reg} on \var{ws}.
138  * At least the following fields in \var{t} are supported:
139  * 
140  * \begin{tabularx}{\linewidth}{lX}
141  *  \tabhead{Field & Description}
142  *  \var{switchto} & Should the region be switched to (boolean)? Optional. \\
143  *  \var{geom} & Geometry; \var{x} and \var{y}, if set, indicates top-left of 
144  *   the frame to be created while \var{width} and \var{height}, if set, indicate
145  *   the size of the client window within that frame. Optional.
146  * \end{tabularx}
147  */
148 EXTL_EXPORT_AS(WGroupWS, attach_framed)
149 bool groupws_attach_framed_extl(WGroupWS *ws, WRegion *reg, ExtlTab t)
150 {
151     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
152     WFramedParam fp=FRAMEDPARAM_INIT;
153     ExtlTab gt;
154     
155     if(reg==NULL)
156         return FALSE;
157     
158     fp.gravity=ForgetGravity;
159     
160     if(extl_table_is_bool_set(t, "switchto")){
161         ap.switchto_set=TRUE;
162         ap.switchto=TRUE;
163     }
164     
165     if(extl_table_gets_t(t, "geom", &gt)){
166         int pos=0, size=0;
167         
168         fp.inner_geom.x=0;
169         fp.inner_geom.y=0;
170
171         if(extl_table_gets_i(gt, "x", &(ap.geom.x)))
172             pos++;
173         if(extl_table_gets_i(gt, "y", &(ap.geom.y)))
174             pos++;
175     
176         if(extl_table_gets_i(gt, "w", &(ap.geom.w)))
177             size++;
178         if(extl_table_gets_i(gt, "h", &(ap.geom.h)))
179             size++;
180         
181         fp.inner_geom.w=maxof(fp.inner_geom.w, 1);
182         fp.inner_geom.h=maxof(fp.inner_geom.h, 1);
183         
184         fp.inner_geom_gravity_set=(size==2 && pos==2);
185         
186         extl_unref_table(gt);
187     }
188     
189     return groupws_attach_framed(ws, &ap, &fp, reg);
190 }
191
192
193 /*}}}*/
194
195
196 /*{{{ groupws_prepare_manage */
197
198
199 #define REG_OK(R) OBJ_IS(R, WMPlex)
200
201
202 static WMPlex *find_existing(WGroupWS *ws)
203 {
204     WGroupIterTmp tmp;
205     WRegion *r=(ws->grp.current_managed!=NULL 
206                 ? ws->grp.current_managed->reg 
207                 : NULL);
208     
209     if(r!=NULL && REG_OK(r))
210         return (WMPlex*)r;
211     
212     FOR_ALL_MANAGED_BY_GROUP(&ws->grp, r, tmp){
213         if(REG_OK(r))
214             return (WMPlex*)r;
215     }
216     
217     return NULL;
218 }
219
220
221 static WPHolder *groupws_do_prepare_manage(WGroupWS *ws, 
222                                            const WClientWin *cwin,
223                                            const WManageParams *param, 
224                                            int redir, int geom_weak)
225 {
226     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
227     WFramedParam fp=FRAMEDPARAM_INIT;
228     WPHolder *ph;
229     
230     if(redir==MANAGE_REDIR_PREFER_YES){
231         WMPlex *m=find_existing(ws);
232         if(m!=NULL){
233             WPHolder *ph;
234             ph=region_prepare_manage((WRegion*)m, cwin, param,
235                                      MANAGE_REDIR_STRICT_YES);
236             if(ph!=NULL)
237                 return ph;
238         }
239     }
240     
241     if(redir==MANAGE_REDIR_STRICT_YES)
242         return NULL;
243
244     fp.inner_geom_gravity_set=TRUE;
245     fp.inner_geom=param->geom;
246     fp.gravity=param->gravity;
247     
248     ap.geom_weak_set=1;
249     ap.geom_weak=geom_weak;
250
251     ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
252     
253     if(ph!=NULL)
254         ph=pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
255     
256     if(ph!=NULL)
257         ph=pholder_either((WPHolder*)create_groupedpholder((WPHolder*)ph), ph);
258     
259     return ph;
260 }
261
262
263 WPHolder *groupws_prepare_manage(WGroupWS *ws, const WClientWin *cwin,
264                                  const WManageParams *param,
265                                  int redir)
266 {
267     WRegion *b=(ws->grp.bottom!=NULL ? ws->grp.bottom->reg : NULL);
268     WPHolder *ph=NULL;
269     bool act_b=(ws->grp.bottom==ws->grp.current_managed);
270     bool always_float, use_bottom;
271     int weak=0;
272     
273     if(param->maprq && ioncore_g.opmode!=IONCORE_OPMODE_INIT
274        && !param->userpos){
275         /* When the window is mapped by application request, position
276          * request is only honoured if the position was given by the user
277          * and in case of a transient (the app may know better where to 
278          * place them) or if we're initialising.
279          */
280         weak=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
281     }
282
283     if(b!=NULL && !HAS_DYN(b, region_prepare_manage))
284         b=NULL;
285     
286     use_bottom=(act_b
287                 ? !extl_table_is_bool_set(cwin->proptab, "float")
288                 : act_b);
289     
290     if(b!=NULL && use_bottom)
291         ph=region_prepare_manage(b, cwin, param, redir);
292     
293     if(ph==NULL)
294         ph=groupws_do_prepare_manage(ws, cwin, param, redir, weak);
295
296     if(ph==NULL && b!=NULL && !use_bottom)
297         ph=region_prepare_manage(b, cwin, param, redir);
298     
299     return ph;
300 }
301
302
303 WPHolder *groupws_prepare_manage_transient(WGroupWS *ws, const WClientWin *cwin,
304                                            const WManageParams *param,
305                                            int unused)
306 {
307     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
308     WFramedParam fp=FRAMEDPARAM_INIT;
309     WPHolder *ph;
310     
311     ap.stack_above=OBJ_CAST(REGION_PARENT(param->tfor), WRegion);
312     if(ap.stack_above==NULL)
313         return NULL;
314     
315     fp.inner_geom_gravity_set=TRUE;
316     fp.inner_geom=param->geom;
317     fp.gravity=param->gravity;
318     fp.mkframe=create_transient_frame;
319     
320     ap.geom_weak_set=1;
321     ap.geom_weak=0;
322
323     ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
324     
325     return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
326 }
327
328
329 WPHolder *groupws_get_rescue_pholder_for(WGroupWS *ws, 
330                                          WRegion *forwhat)
331 {
332     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
333     WFramedParam fp=FRAMEDPARAM_INIT;
334     WPHolder *ph;
335     
336     ap.geom_set=TRUE;
337     ap.geom=REGION_GEOM(forwhat);
338
339     ap.geom_weak_set=1;
340     ap.geom_weak=(REGION_PARENT(forwhat)!=REGION_PARENT(ws)
341                   ? REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y
342                   : 0);
343
344     ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
345     
346     return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
347 }
348
349
350 /*}}}*/
351
352
353 /*{{{ WGroupWS class */
354
355
356 bool groupws_init(WGroupWS *ws, WWindow *parent, const WFitParams *fp)
357 {
358     if(!group_init(&(ws->grp), parent, fp))
359         return FALSE;
360
361     ((WRegion*)ws)->flags|=REGION_GRAB_ON_PARENT;
362     
363     region_add_bindmap((WRegion*)ws, ioncore_groupws_bindmap);
364     
365     return TRUE;
366 }
367
368
369 WGroupWS *create_groupws(WWindow *parent, const WFitParams *fp)
370 {
371     CREATEOBJ_IMPL(WGroupWS, groupws, (p, parent, fp));
372 }
373
374
375 void groupws_deinit(WGroupWS *ws)
376 {    
377     group_deinit(&(ws->grp));
378 }
379
380
381 WRegion *groupws_load(WWindow *par, const WFitParams *fp, 
382                        ExtlTab tab)
383 {
384     WGroupWS *ws;
385     
386     ws=create_groupws(par, fp);
387     
388     if(ws==NULL)
389         return NULL;
390
391     group_do_load(&ws->grp, tab);
392     
393     return (WRegion*)ws;
394 }
395
396
397 WRegion *groupws_load_default(WWindow *par, const WFitParams *fp)
398 {
399     return groupws_load(par, fp, (default_ws_params_set
400                                   ? default_ws_params
401                                   : extl_table_none()));
402 }
403
404
405 static DynFunTab groupws_dynfuntab[]={
406     {(DynFun*)region_prepare_manage, 
407      (DynFun*)groupws_prepare_manage},
408     
409     {(DynFun*)region_prepare_manage_transient,
410      (DynFun*)groupws_prepare_manage_transient},
411     
412     {(DynFun*)region_handle_drop,
413      (DynFun*)groupws_handle_drop},
414     
415     {(DynFun*)region_get_rescue_pholder_for,
416      (DynFun*)groupws_get_rescue_pholder_for},
417     
418     {region_manage_stdisp,
419      group_manage_stdisp},
420     
421     END_DYNFUNTAB
422 };
423
424
425 EXTL_EXPORT
426 IMPLCLASS(WGroupWS, WGroup, groupws_deinit, groupws_dynfuntab);
427
428
429 /*}}}*/
430