]> git.decadent.org.uk Git - ion3.git/blob - ioncore/grouppholder.c
[svn-upgrade] Integrating new upstream version, ion3 (20071220)
[ion3.git] / ioncore / grouppholder.c
1 /*
2  * ion/ioncore/grouppholder.c
3  *
4  * Copyright (c) Tuomo Valkonen 2005-2007. 
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{
76         WGroupPHolder *next=ph->next;
77         
78         if(ph->prev!=NULL)
79             ph->prev->next=next;
80
81         if(next==NULL){
82             next=get_head(ph);
83             assert(next->prev==ph);
84         }
85         next->prev=ph->prev;
86     }
87     
88     ph->group=NULL;
89     ph->next=NULL;
90     ph->prev=NULL;
91 }
92
93
94 /*}}}*/
95
96
97 /*{{{ Init/deinit */
98
99 static WGroupAttachParams dummy_param=GROUPATTACHPARAMS_INIT;
100
101
102 bool grouppholder_init(WGroupPHolder *ph, WGroup *ws,
103                        const WStacking *st,
104                        const WGroupAttachParams *param)
105 {
106     WRegion *stack_above=NULL;
107     
108     pholder_init(&(ph->ph));
109
110     watch_init(&(ph->stack_above_watch));
111     ph->next=NULL;
112     ph->prev=NULL;
113     ph->group=NULL;
114     ph->recreate_pholder=NULL;
115     ph->param=(param==NULL ? dummy_param : *param);
116
117     if(st!=NULL){
118         /* TODO? Just link to the stacking structure to remember 
119          * stacking order? 
120          */
121         
122         ph->param.szplcy_set=TRUE;
123         ph->param.szplcy=st->szplcy;
124         ph->param.level_set=TRUE;
125         ph->param.level=st->level;
126         
127         if(st->reg!=NULL){
128             ph->param.geom_set=TRUE;
129             ph->param.geom=REGION_GEOM(st->reg);
130         }
131         
132         if(st->above!=NULL && st->above->reg!=NULL)
133             ph->param.stack_above=st->above->reg;
134         
135         ph->param.bottom=(st==ws->bottom);
136     }
137     
138     ph->param.switchto_set=FALSE;
139     
140     stack_above=ph->param.stack_above;
141     ph->param.stack_above=NULL;
142     
143     grouppholder_do_link(ph, ws, stack_above);
144     
145     return TRUE;
146 }
147
148
149 WGroupPHolder *create_grouppholder(WGroup *ws,
150                                    const WStacking *st,
151                                    const WGroupAttachParams *param)
152 {
153     CREATEOBJ_IMPL(WGroupPHolder, grouppholder, (p, ws, st, param));
154 }
155
156
157 void grouppholder_deinit(WGroupPHolder *ph)
158 {
159     grouppholder_do_unlink(ph);
160     
161     pholder_deinit(&(ph->ph));
162 }
163
164
165 /*}}}*/
166
167
168 /*{{{ Dynfuns */
169
170
171 static WPHolder *get_recreate_ph(WGroupPHolder *ph)
172 {
173     return get_head(ph)->recreate_pholder;
174 }
175
176
177 typedef struct{
178     WGroupPHolder *ph, *ph_head;
179     WRegionAttachData *data;
180     WRegion *reg_ret;
181 } RP;
182
183
184 static WRegion *recreate_handler(WWindow *par, 
185                                  const WFitParams *fp, 
186                                  void *rp_)
187 {
188     WGroupPHolder *phtmp;
189     RP *rp=(RP*)rp_;
190     WGroup *grp;
191     
192     grp=(WGroup*)create_groupcw(par, fp);
193     
194     if(grp==NULL)
195         return NULL;
196     
197     rp->reg_ret=group_do_attach(grp, &rp->ph->param, rp->data);
198     
199     if(rp->reg_ret==NULL){
200         destroy_obj((Obj*)grp);
201         return NULL;
202     }else{
203         grp->phs=rp->ph_head;
204         
205         for(phtmp=grp->phs; phtmp!=NULL; phtmp=phtmp->next)
206             phtmp->group=grp;
207     }
208     
209     return (WRegion*)grp;
210 }
211
212
213
214 static WRegion *grouppholder_attach_recreate(WGroupPHolder *ph, int flags,
215                                              WRegionAttachData *data)
216 {
217     WRegionAttachData data2;
218     WPHolder *root, *rph;
219     WGroup *grp;
220     RP rp;
221     
222     rp.ph_head=get_head(ph);
223     
224     assert(rp.ph_head!=NULL);
225     
226     rph=rp.ph_head->recreate_pholder;
227     
228     if(rph==NULL)
229         return NULL;
230     
231     rp.ph=ph;
232     rp.data=data;
233     rp.reg_ret=NULL;
234     
235     data2.type=REGION_ATTACH_NEW;
236     data2.u.n.fn=recreate_handler;
237     data2.u.n.param=&rp;
238     
239     grp=(WGroup*)pholder_do_attach(rph, flags, &data2);
240     
241     if(grp!=NULL){
242         assert(OBJ_IS(grp, WGroup));
243         rp.ph_head->recreate_pholder=NULL;
244         /* It might be in use in attach chain! So defer. */
245         mainloop_defer_destroy((Obj*)rph);
246     }
247
248     return rp.reg_ret;
249 }
250
251
252 WRegion *grouppholder_do_attach(WGroupPHolder *ph, int flags,
253                                 WRegionAttachData *data)
254 {
255     WGroup *ws=ph->group;
256     WRegion *reg;
257
258     if(ws==NULL)
259         return grouppholder_attach_recreate(ph, flags, data);
260     
261     ph->param.switchto_set=1;
262     ph->param.switchto=(flags&PHOLDER_ATTACH_SWITCHTO ? 1 : 0);
263     
264     /* Get stack_above from Watch. */
265     ph->param.stack_above=(WRegion*)ph->stack_above_watch.obj;
266     
267     reg=group_do_attach(ws, &ph->param, data);
268     
269     ph->param.stack_above=NULL;
270
271     return reg;
272 }
273
274
275 bool grouppholder_do_goto(WGroupPHolder *ph)
276 {
277     WGroup *ws=ph->group;
278     
279     if(ws!=NULL)
280         return region_goto((WRegion*)ws);
281     
282     return FALSE;
283 }
284
285
286 WRegion *grouppholder_do_target(WGroupPHolder *ph)
287 {
288     return (WRegion*)ph->group;
289 }
290
291
292 /*}}}*/
293
294
295 /*{{{ WGroup stuff */
296
297
298 WGroupPHolder *group_managed_get_pholder(WGroup *ws, WRegion *mgd)
299 {
300     WStacking *st=group_find_stacking(ws, mgd);
301     
302     if(mgd==NULL)
303         return NULL;
304     else
305         return create_grouppholder(ws, st, NULL);
306 }
307
308
309 /*}}}*/
310
311
312 /*{{{ Class information */
313
314
315 static DynFunTab grouppholder_dynfuntab[]={
316     {(DynFun*)pholder_do_attach, 
317      (DynFun*)grouppholder_do_attach},
318
319     {(DynFun*)pholder_do_goto, 
320      (DynFun*)grouppholder_do_goto},
321
322     {(DynFun*)pholder_do_target, 
323      (DynFun*)grouppholder_do_target},
324     
325     END_DYNFUNTAB
326 };
327
328 IMPLCLASS(WGroupPHolder, WPHolder, grouppholder_deinit, 
329           grouppholder_dynfuntab);
330
331
332 /*}}}*/
333