]> git.decadent.org.uk Git - ion3.git/blob - ioncore/group-cw.c
48f234a2939aba3b0645192b33b613c962d73bf0
[ion3.git] / ioncore / group-cw.c
1 /*
2  * ion/ioncore/group-cw.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2008. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10
11 #include <libtu/objp.h>
12 #include <libmainloop/defer.h>
13
14 #include "common.h"
15 #include "group-cw.h"
16 #include "clientwin.h"
17 #include "regbind.h"
18 #include "bindmaps.h"
19 #include "frame.h"
20 #include "resize.h"
21 #include "pholder.h"
22 #include "names.h"
23 #include "framedpholder.h"
24 #include "grouppholder.h"
25 #include "return.h"
26 #include "saveload.h"
27
28
29 #define DFLT_SZPLCY SIZEPOLICY_FREE_GLUE__SOUTH
30
31
32 /*{{{ Add/remove managed */
33
34
35 static WPHolder *groupcw_transient_pholder(WGroupCW *cwg, 
36                                            const WClientWin *cwin,
37                                            const WManageParams *mp)
38 {
39     WGroupAttachParams param=GROUPATTACHPARAMS_INIT;
40     WFramedParam fp=FRAMEDPARAM_INIT;
41     WPHolder *ph;
42     
43     param.level_set=1;
44     param.level=STACKING_LEVEL_MODAL1;
45     
46     param.szplcy_set=1;
47     param.szplcy=cwg->transient_szplcy;
48     
49     param.switchto_set=1;
50     param.switchto=1;
51
52     param.geom_weak_set=1;
53     param.geom_weak=REGION_RQGEOM_WEAK_ALL;
54     
55     if(!ioncore_g.framed_transients){
56         param.geom_set=TRUE;
57         param.geom=mp->geom;
58         
59         return (WPHolder*)create_grouppholder(&cwg->grp, NULL, &param);
60     }else{
61         fp.inner_geom_gravity_set=1;
62         fp.inner_geom=mp->geom;
63         fp.gravity=ForgetGravity;
64         fp.mode=FRAME_MODE_TRANSIENT;
65         
66         ph=(WPHolder*)create_grouppholder(&cwg->grp, NULL, &param);
67         
68         return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
69     }
70 }
71
72
73 WPHolder *groupcw_prepare_manage(WGroupCW *cwg, const WClientWin *cwin,
74                                  const WManageParams *param, int priority)
75 {
76     if(!MANAGE_PRIORITY_OK(priority, MANAGE_PRIORITY_GROUP))
77         return NULL;
78     
79     /* Only catch windows with transient mode set to current here. */
80     if(clientwin_get_transient_mode(cwin)!=TRANSIENT_MODE_CURRENT)
81         return NULL;
82     
83     return groupcw_transient_pholder(cwg, cwin, param);
84 }
85
86
87 static bool groupcw_should_manage_transient(WGroupCW *cwg, 
88                                             WClientWin *tfor)
89 {
90     WRegion *mgr;
91     
92     if(group_find_stacking(&cwg->grp, (WRegion*)tfor))
93         return TRUE;
94  
95     mgr=REGION_MANAGER(tfor);
96     
97     if(mgr!=NULL && ioncore_g.framed_transients && OBJ_IS(mgr, WFrame))
98         return (group_find_stacking(&cwg->grp, mgr)!=NULL);
99     
100     return FALSE;
101 }
102
103
104 WPHolder *groupcw_prepare_manage_transient(WGroupCW *cwg, 
105                                            const WClientWin *transient,
106                                            const WManageParams *param,
107                                            int unused)
108 {
109     WPHolder *ph=region_prepare_manage_transient_default((WRegion*)cwg,
110                                                          transient,
111                                                          param,
112                                                          unused);
113     
114     if(ph==NULL && groupcw_should_manage_transient(cwg, param->tfor))
115         ph=groupcw_transient_pholder(cwg, transient, param);
116
117     return ph;
118 }
119
120
121 static WRegion *groupcw_managed_disposeroot(WGroupCW *ws, WRegion *reg)
122 {
123     WGroupIterTmp tmp;
124     WStacking *st;
125     WRegion *tmpr;
126     
127     FOR_ALL_NODES_IN_GROUP(&ws->grp, st, tmp){
128         if(st!=ws->grp.managed_stdisp && st->reg!=reg){
129             return reg;
130         }
131     }
132     
133     tmpr=region_disposeroot((WRegion*)ws);
134     return (tmpr!=NULL ? tmpr : reg);
135 }
136
137
138 /*}}}*/
139
140
141 /*{{{ Misc. */
142
143
144 /*_EXTL_DOC
145  * Toggle transients managed by \var{cwin} between top/bottom
146  * of the window.
147  */
148 EXTL_EXPORT_MEMBER
149 void groupcw_toggle_transients_pos(WGroupCW *cwg)
150 {
151     WStacking *st;
152     WGroupIterTmp tmp;
153     
154     if((cwg->transient_szplcy&SIZEPOLICY_VERT_MASK)==SIZEPOLICY_VERT_TOP){
155         cwg->transient_szplcy&=~SIZEPOLICY_VERT_MASK;
156         cwg->transient_szplcy|=SIZEPOLICY_VERT_BOTTOM;
157     }else{
158         cwg->transient_szplcy&=~SIZEPOLICY_VERT_MASK;
159         cwg->transient_szplcy|=SIZEPOLICY_VERT_TOP;
160     }
161
162     FOR_ALL_NODES_IN_GROUP(&cwg->grp, st, tmp){
163         st->szplcy&=~SIZEPOLICY_VERT_MASK;
164         st->szplcy|=(cwg->transient_szplcy&SIZEPOLICY_VERT_MASK);
165         
166         if(st->reg!=NULL){
167             WFitParams fp;
168             
169             fp.mode=0;
170             fp.g=REGION_GEOM(cwg);
171             
172             sizepolicy(&st->szplcy, st->reg, NULL, 
173                        REGION_RQGEOM_WEAK_ALL, &fp);
174             region_fitrep(st->reg, NULL, &fp);
175         }
176     }
177 }
178
179
180 const char *groupcw_displayname(WGroupCW *cwg)
181 {
182     const char *name=NULL;
183     
184     if(cwg->grp.bottom!=NULL && cwg->grp.bottom->reg!=NULL)
185         name=region_name(cwg->grp.bottom->reg);
186     
187     if(name==NULL)
188         name=region_name((WRegion*)cwg);
189     
190     return name;
191 }
192
193
194 void groupcw_managed_notify(WGroupCW *cwg, WRegion *reg, WRegionNotify how)
195 {
196     if(group_bottom(&cwg->grp)==reg && how==ioncore_g.notifies.name){
197         /* Title has changed */
198         region_notify_change((WRegion*)cwg, how);
199     }
200     
201     group_managed_notify(&cwg->grp, reg, how);
202 }
203
204
205 void groupcw_bottom_set(WGroupCW *cwg)
206 {
207     region_notify_change((WRegion*)cwg, ioncore_g.notifies.name);
208 }
209
210
211 /*}}}*/
212
213
214 /*{{{ Rescue */
215
216
217 static void group_migrate_phs_to_ph(WGroup *group, WPHolder *rph)
218 {
219     WGroupPHolder *phs, *ph;
220     
221     phs=group->phs;
222     group->phs=NULL;
223     
224     phs->recreate_pholder=rph;
225     
226     for(ph=phs; ph!=NULL; ph=ph->next)
227         ph->group=NULL;
228 }
229
230
231 bool groupcw_rescue_clientwins(WGroupCW *cwg, WRescueInfo *info)
232 {
233     bool ret=group_rescue_clientwins(&cwg->grp, info);
234     
235     /* If this group can be recreated, arrange remaining placeholders
236      * to do so. This takes care of e.g. recreating client window groups
237      * when recreating layout delayedly under a session manager.
238      */
239     if(cwg->grp.phs!=NULL){
240         WPHolder *rph=region_make_return_pholder((WRegion*)cwg);
241         
242         if(rph!=NULL)
243             group_migrate_phs_to_ph(&cwg->grp, rph);
244     }
245     
246     return ret;
247 }
248
249
250 /*}}}*/
251
252
253
254 /*{{{ WGroupCW class */
255
256
257 bool groupcw_init(WGroupCW *cwg, WWindow *parent, const WFitParams *fp)
258 {
259     cwg->transient_szplcy=DFLT_SZPLCY;
260     
261     if(!group_init(&(cwg->grp), parent, fp))
262         return FALSE;
263     
264     region_add_bindmap((WRegion*)cwg, ioncore_groupcw_bindmap);
265     
266     return TRUE;
267 }
268
269
270 WGroupCW *create_groupcw(WWindow *parent, const WFitParams *fp)
271 {
272     CREATEOBJ_IMPL(WGroupCW, groupcw, (p, parent, fp));
273 }
274
275
276 void groupcw_deinit(WGroupCW *cwg)
277 {    
278     group_deinit(&(cwg->grp));
279 }
280
281
282 WRegion *groupcw_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
283 {
284     WGroupCW *cwg;
285     ExtlTab substab, subtab;
286     int i, n;
287     
288     cwg=create_groupcw(par, fp);
289     
290     if(cwg==NULL)
291         return NULL;
292
293     group_do_load(&cwg->grp, tab);
294     
295     if(cwg->grp.managed_list==NULL){
296         if(cwg->grp.phs!=NULL){
297             /* Session management hack */
298             WPHolder *ph=ioncore_get_load_pholder();
299             if(ph!=NULL)
300                 group_migrate_phs_to_ph(&cwg->grp, ph);
301         }
302         destroy_obj((Obj*)cwg);
303         return NULL;
304     }
305
306     return (WRegion*)cwg;
307 }
308
309
310 static DynFunTab groupcw_dynfuntab[]={
311     {(DynFun*)region_prepare_manage, 
312      (DynFun*)groupcw_prepare_manage},
313     
314     {(DynFun*)region_prepare_manage_transient,
315      (DynFun*)groupcw_prepare_manage_transient},
316     
317     /*
318     {(DynFun*)region_handle_drop,
319      (DynFun*)groupcw_handle_drop},
320     
321     {(DynFun*)group_do_add_managed,
322      (DynFun*)groupcw_do_add_managed},
323     */
324     
325     /*
326     {(DynFun*)region_get_rescue_pholder_for,
327      (DynFun*)groupcw_get_rescue_pholder_for},
328      */
329     
330     {(DynFun*)region_prepare_manage,
331      (DynFun*)groupcw_prepare_manage},
332
333     {(DynFun*)region_prepare_manage_transient,
334      (DynFun*)groupcw_prepare_manage_transient},
335      
336     {(DynFun*)region_managed_disposeroot,
337      (DynFun*)groupcw_managed_disposeroot},
338     
339     {(DynFun*)region_displayname,
340      (DynFun*)groupcw_displayname},
341     
342     {region_managed_notify,
343      groupcw_managed_notify},
344      
345     {group_bottom_set,
346      groupcw_bottom_set},
347      
348     {(DynFun*)region_rescue_clientwins,
349      (DynFun*)groupcw_rescue_clientwins},
350     
351     END_DYNFUNTAB
352 };
353
354
355 EXTL_EXPORT
356 IMPLCLASS(WGroupCW, WGroup, groupcw_deinit, groupcw_dynfuntab);
357
358
359 /*}}}*/
360