]> git.decadent.org.uk Git - ion3.git/blob - ioncore/grouppholder.c
2d941e4166bf15d08cd8438b055ec2a5f9f1e31b
[ion3.git] / ioncore / grouppholder.c
1 /*
2  * ion/ioncore/grouppholder.c
3  *
4  * Copyright (c) Tuomo Valkonen 2005-2008. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <libtu/objp.h>
10 #include <libtu/obj.h>
11 #include <libtu/pointer.h>
12 #include <libmainloop/defer.h>
13
14 #include <ioncore/common.h>
15 #include "group.h"
16 #include "group-cw.h"
17 #include "grouppholder.h"
18
19
20 static void group_watch_handler(Watch *watch, Obj *ws);
21
22
23 /*{{{ Primitives */
24
25
26 void grouppholder_do_link(WGroupPHolder *ph, WGroup *group, WRegion *stack_above)
27 {
28     ph->group=group;
29     
30     if(group!=NULL){
31         LINK_ITEM_FIRST(group->phs, ph, next, prev);
32     }else{
33         /* This seems very crucial for detached pholders... */
34         ph->next=NULL;
35         ph->prev=ph;
36     }
37     
38     /* We must move stack_above pointer into a Watch. */
39     if(stack_above!=NULL)
40         watch_setup(&(ph->stack_above_watch), (Obj*)stack_above, NULL);
41 }
42
43
44 static WGroupPHolder *get_head(WGroupPHolder *ph)
45 {
46     while(1){
47         /* ph->prev==NULL should not happen.. */
48         if(ph->prev==NULL || ph->prev->next==NULL)
49             break;
50         ph=ph->prev;
51     }
52     
53     return ph;
54 }
55
56
57 void grouppholder_do_unlink(WGroupPHolder *ph)
58 {
59     WGroup *group=ph->group;
60     
61     watch_reset(&(ph->stack_above_watch));
62     
63     if(ph->recreate_pholder!=NULL){
64         if(ph->next!=NULL){
65             ph->next->recreate_pholder=ph->recreate_pholder;
66         }else{
67             /* It might be in use in attach chain! So defer. */
68             mainloop_defer_destroy((Obj*)ph->recreate_pholder);
69         }
70         ph->recreate_pholder=NULL;
71     }
72     
73     if(group!=NULL){
74         UNLINK_ITEM(group->phs, ph, next, prev);
75     }else if(ph->prev!=NULL){
76         WGroupPHolder *next=ph->next;
77         
78         ph->prev->next=next;
79
80         if(next==NULL){
81             next=get_head(ph);
82             assert(next->prev==ph);
83         }
84         next->prev=ph->prev;
85     }else{
86         /* ph should not be on a list, if prev pointer is NULL (whereas
87          * next alone can be NULL in our semi-doubly-linked lists).
88          */
89         assert(ph->next==NULL);
90     }
91     
92     ph->group=NULL;
93     ph->next=NULL;
94     ph->prev=NULL;
95 }
96
97
98 /*}}}*/
99
100
101 /*{{{ Init/deinit */
102
103 static WGroupAttachParams dummy_param=GROUPATTACHPARAMS_INIT;
104
105
106 bool grouppholder_init(WGroupPHolder *ph, WGroup *ws,
107                        const WStacking *st,
108                        const WGroupAttachParams *param)
109 {
110     WRegion *stack_above=NULL;
111     
112     pholder_init(&(ph->ph));
113
114     watch_init(&(ph->stack_above_watch));
115     ph->next=NULL;
116     ph->prev=NULL;
117     ph->group=NULL;
118     ph->recreate_pholder=NULL;
119     ph->param=(param==NULL ? dummy_param : *param);
120
121     if(st!=NULL){
122         /* TODO? Just link to the stacking structure to remember 
123          * stacking order? 
124          */
125         
126         ph->param.szplcy_set=TRUE;
127         ph->param.szplcy=st->szplcy;
128         ph->param.level_set=TRUE;
129         ph->param.level=st->level;
130         
131         if(st->reg!=NULL){
132             ph->param.geom_set=TRUE;
133             ph->param.geom=REGION_GEOM(st->reg);
134         }
135         
136         if(st->above!=NULL && st->above->reg!=NULL)
137             ph->param.stack_above=st->above->reg;
138         
139         ph->param.bottom=(st==ws->bottom);
140     }
141     
142     ph->param.switchto_set=FALSE;
143     
144     stack_above=ph->param.stack_above;
145     ph->param.stack_above=NULL;
146     
147     grouppholder_do_link(ph, ws, stack_above);
148     
149     return TRUE;
150 }
151
152
153 WGroupPHolder *create_grouppholder(WGroup *ws,
154                                    const WStacking *st,
155                                    const WGroupAttachParams *param)
156 {
157     CREATEOBJ_IMPL(WGroupPHolder, grouppholder, (p, ws, st, param));
158 }
159
160
161 void grouppholder_deinit(WGroupPHolder *ph)
162 {
163     grouppholder_do_unlink(ph);
164     
165     pholder_deinit(&(ph->ph));
166 }
167
168
169 /*}}}*/
170
171
172 /*{{{ Dynfuns */
173
174
175 static WPHolder *get_recreate_ph(WGroupPHolder *ph)
176 {
177     return get_head(ph)->recreate_pholder;
178 }
179
180
181 typedef struct{
182     WGroupPHolder *ph, *ph_head;
183     WRegionAttachData *data;
184     WRegion *reg_ret;
185 } RP;
186
187
188 static WRegion *recreate_handler(WWindow *par, 
189                                  const WFitParams *fp, 
190                                  void *rp_)
191 {
192     WGroupPHolder *phtmp;
193     RP *rp=(RP*)rp_;
194     WGroup *grp;
195     
196     grp=(WGroup*)create_groupcw(par, fp);
197     
198     if(grp==NULL)
199         return NULL;
200         
201     rp->ph->param.whatever=(fp->mode&REGION_FIT_WHATEVER ? 1 : 0);
202     
203     rp->reg_ret=group_do_attach(grp, &rp->ph->param, rp->data);
204     
205     rp->ph->param.whatever=0;
206     
207     if(rp->reg_ret==NULL){
208         destroy_obj((Obj*)grp);
209         return NULL;
210     }else{
211         grp->phs=rp->ph_head;
212         
213         for(phtmp=grp->phs; phtmp!=NULL; phtmp=phtmp->next)
214             phtmp->group=grp;
215     }
216     
217     if(fp->mode&REGION_FIT_WHATEVER)
218         REGION_GEOM(grp)=REGION_GEOM(rp->reg_ret);
219     
220     return (WRegion*)grp;
221 }
222
223
224
225 static WRegion *grouppholder_attach_recreate(WGroupPHolder *ph, int flags,
226                                              WRegionAttachData *data)
227 {
228     WRegionAttachData data2;
229     WPHolder *root, *rph;
230     WGroup *grp;
231     RP rp;
232     
233     rp.ph_head=get_head(ph);
234     
235     assert(rp.ph_head!=NULL);
236     
237     rph=rp.ph_head->recreate_pholder;
238     
239     if(rph==NULL)
240         return NULL;
241     
242     rp.ph=ph;
243     rp.data=data;
244     rp.reg_ret=NULL;
245     
246     data2.type=REGION_ATTACH_NEW;
247     data2.u.n.fn=recreate_handler;
248     data2.u.n.param=&rp;
249     
250     grp=(WGroup*)pholder_do_attach(rph, flags, &data2);
251     
252     if(grp!=NULL){
253         assert(OBJ_IS(grp, WGroup));
254         rp.ph_head->recreate_pholder=NULL;
255         /* It might be in use in attach chain! So defer. */
256         mainloop_defer_destroy((Obj*)rph);
257     }
258
259     return rp.reg_ret;
260 }
261
262
263 WRegion *grouppholder_do_attach(WGroupPHolder *ph, int flags,
264                                 WRegionAttachData *data)
265 {
266     WGroup *ws=ph->group;
267     WRegion *reg;
268
269     if(ws==NULL)
270         return grouppholder_attach_recreate(ph, flags, data);
271     
272     ph->param.switchto_set=1;
273     ph->param.switchto=(flags&PHOLDER_ATTACH_SWITCHTO ? 1 : 0);
274     
275     /* Get stack_above from Watch. */
276     ph->param.stack_above=(WRegion*)ph->stack_above_watch.obj;
277     
278     reg=group_do_attach(ws, &ph->param, data);
279     
280     ph->param.stack_above=NULL;
281
282     return reg;
283 }
284
285
286 bool grouppholder_do_goto(WGroupPHolder *ph)
287 {
288     return (ph->group!=NULL
289             ? region_goto((WRegion*)ph->group)
290             : (ph->recreate_pholder!=NULL
291                ? pholder_do_goto(ph->recreate_pholder)
292                : FALSE));
293 }
294
295
296 WRegion *grouppholder_do_target(WGroupPHolder *ph)
297 {
298     return (ph->group!=NULL
299             ? (WRegion*)ph->group
300             : (ph->recreate_pholder!=NULL
301                ? pholder_do_target(ph->recreate_pholder)
302                : NULL));
303 }
304
305
306 /*}}}*/
307
308
309 /*{{{ WGroup stuff */
310
311
312 WGroupPHolder *group_managed_get_pholder(WGroup *ws, WRegion *mgd)
313 {
314     WStacking *st=group_find_stacking(ws, mgd);
315     
316     if(mgd==NULL)
317         return NULL;
318     else
319         return create_grouppholder(ws, st, NULL);
320 }
321
322
323 /*}}}*/
324
325
326 /*{{{ Class information */
327
328
329 static DynFunTab grouppholder_dynfuntab[]={
330     {(DynFun*)pholder_do_attach, 
331      (DynFun*)grouppholder_do_attach},
332
333     {(DynFun*)pholder_do_goto, 
334      (DynFun*)grouppholder_do_goto},
335
336     {(DynFun*)pholder_do_target, 
337      (DynFun*)grouppholder_do_target},
338     
339     END_DYNFUNTAB
340 };
341
342 IMPLCLASS(WGroupPHolder, WPHolder, grouppholder_deinit, 
343           grouppholder_dynfuntab);
344
345
346 /*}}}*/
347