]> git.decadent.org.uk Git - ion3.git/blob - ioncore/grouppholder.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / grouppholder.c
1 /*
2  * ion/ioncore/grouppholder.c
3  *
4  * Copyright (c) Tuomo Valkonen 2005-2009. 
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     WRegion *res;
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     res=pholder_do_attach(rph, flags, &data2);
251     
252     if(res!=NULL){
253         rp.ph_head->recreate_pholder=NULL;
254         /* It might be in use in attach chain! So defer. */
255         mainloop_defer_destroy((Obj*)rph);
256     }
257
258     return (flags&PHOLDER_ATTACH_RETURN_CREATEROOT
259             ? (WRegion*)res
260             : rp.reg_ret);
261 }
262
263
264 WRegion *grouppholder_do_attach(WGroupPHolder *ph, int flags,
265                                 WRegionAttachData *data)
266 {
267     WGroup *ws=ph->group;
268     WRegion *reg;
269
270     if(ws==NULL)
271         return grouppholder_attach_recreate(ph, flags, data);
272     
273     ph->param.switchto_set=1;
274     ph->param.switchto=(flags&PHOLDER_ATTACH_SWITCHTO ? 1 : 0);
275     
276     /* Get stack_above from Watch. */
277     ph->param.stack_above=(WRegion*)ph->stack_above_watch.obj;
278     
279     reg=group_do_attach(ws, &ph->param, data);
280     
281     ph->param.stack_above=NULL;
282
283     return reg;
284 }
285
286
287 bool grouppholder_do_goto(WGroupPHolder *ph)
288 {
289     return (ph->group!=NULL
290             ? region_goto((WRegion*)ph->group)
291             : (ph->recreate_pholder!=NULL
292                ? pholder_do_goto(ph->recreate_pholder)
293                : FALSE));
294 }
295
296
297 WRegion *grouppholder_do_target(WGroupPHolder *ph)
298 {
299     return (ph->group!=NULL
300             ? (WRegion*)ph->group
301             : (ph->recreate_pholder!=NULL
302                ? pholder_do_target(ph->recreate_pholder)
303                : NULL));
304 }
305
306
307 /*}}}*/
308
309
310 /*{{{ WGroup stuff */
311
312
313 WGroupPHolder *group_managed_get_pholder(WGroup *ws, WRegion *mgd)
314 {
315     WStacking *st=group_find_stacking(ws, mgd);
316     
317     if(mgd==NULL)
318         return NULL;
319     else
320         return create_grouppholder(ws, st, NULL);
321 }
322
323
324 /*}}}*/
325
326
327 /*{{{ Class information */
328
329
330 static DynFunTab grouppholder_dynfuntab[]={
331     {(DynFun*)pholder_do_attach, 
332      (DynFun*)grouppholder_do_attach},
333
334     {(DynFun*)pholder_do_goto, 
335      (DynFun*)grouppholder_do_goto},
336
337     {(DynFun*)pholder_do_target, 
338      (DynFun*)grouppholder_do_target},
339     
340     END_DYNFUNTAB
341 };
342
343 IMPLCLASS(WGroupPHolder, WPHolder, grouppholder_deinit, 
344           grouppholder_dynfuntab);
345
346
347 /*}}}*/
348