]> git.decadent.org.uk Git - ion3.git/blob - ioncore/grouppholder.c
[svn-upgrade] Integrating new upstream version, ion3 (20080411)
[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->reg_ret=group_do_attach(grp, &rp->ph->param, rp->data);
202     
203     if(rp->reg_ret==NULL){
204         destroy_obj((Obj*)grp);
205         return NULL;
206     }else{
207         grp->phs=rp->ph_head;
208         
209         for(phtmp=grp->phs; phtmp!=NULL; phtmp=phtmp->next)
210             phtmp->group=grp;
211     }
212     
213     return (WRegion*)grp;
214 }
215
216
217
218 static WRegion *grouppholder_attach_recreate(WGroupPHolder *ph, int flags,
219                                              WRegionAttachData *data)
220 {
221     WRegionAttachData data2;
222     WPHolder *root, *rph;
223     WGroup *grp;
224     RP rp;
225     
226     rp.ph_head=get_head(ph);
227     
228     assert(rp.ph_head!=NULL);
229     
230     rph=rp.ph_head->recreate_pholder;
231     
232     if(rph==NULL)
233         return NULL;
234     
235     rp.ph=ph;
236     rp.data=data;
237     rp.reg_ret=NULL;
238     
239     data2.type=REGION_ATTACH_NEW;
240     data2.u.n.fn=recreate_handler;
241     data2.u.n.param=&rp;
242     
243     grp=(WGroup*)pholder_do_attach(rph, flags, &data2);
244     
245     if(grp!=NULL){
246         assert(OBJ_IS(grp, WGroup));
247         rp.ph_head->recreate_pholder=NULL;
248         /* It might be in use in attach chain! So defer. */
249         mainloop_defer_destroy((Obj*)rph);
250     }
251
252     return rp.reg_ret;
253 }
254
255
256 WRegion *grouppholder_do_attach(WGroupPHolder *ph, int flags,
257                                 WRegionAttachData *data)
258 {
259     WGroup *ws=ph->group;
260     WRegion *reg;
261
262     if(ws==NULL)
263         return grouppholder_attach_recreate(ph, flags, data);
264     
265     ph->param.switchto_set=1;
266     ph->param.switchto=(flags&PHOLDER_ATTACH_SWITCHTO ? 1 : 0);
267     
268     /* Get stack_above from Watch. */
269     ph->param.stack_above=(WRegion*)ph->stack_above_watch.obj;
270     
271     reg=group_do_attach(ws, &ph->param, data);
272     
273     ph->param.stack_above=NULL;
274
275     return reg;
276 }
277
278
279 bool grouppholder_do_goto(WGroupPHolder *ph)
280 {
281     return (ph->group!=NULL
282             ? region_goto((WRegion*)ph->group)
283             : (ph->recreate_pholder!=NULL
284                ? pholder_do_goto(ph->recreate_pholder)
285                : FALSE));
286 }
287
288
289 WRegion *grouppholder_do_target(WGroupPHolder *ph)
290 {
291     return (ph->group!=NULL
292             ? (WRegion*)ph->group
293             : (ph->recreate_pholder!=NULL
294                ? pholder_do_target(ph->recreate_pholder)
295                : NULL));
296 }
297
298
299 /*}}}*/
300
301
302 /*{{{ WGroup stuff */
303
304
305 WGroupPHolder *group_managed_get_pholder(WGroup *ws, WRegion *mgd)
306 {
307     WStacking *st=group_find_stacking(ws, mgd);
308     
309     if(mgd==NULL)
310         return NULL;
311     else
312         return create_grouppholder(ws, st, NULL);
313 }
314
315
316 /*}}}*/
317
318
319 /*{{{ Class information */
320
321
322 static DynFunTab grouppholder_dynfuntab[]={
323     {(DynFun*)pholder_do_attach, 
324      (DynFun*)grouppholder_do_attach},
325
326     {(DynFun*)pholder_do_goto, 
327      (DynFun*)grouppholder_do_goto},
328
329     {(DynFun*)pholder_do_target, 
330      (DynFun*)grouppholder_do_target},
331     
332     END_DYNFUNTAB
333 };
334
335 IMPLCLASS(WGroupPHolder, WPHolder, grouppholder_deinit, 
336           grouppholder_dynfuntab);
337
338
339 /*}}}*/
340