ion->notion
[notion/jeffpc.git] / ioncore / grouppholder.c
blob052f67725941761d643e4f2d1a286054146f607c
1 /*
2 * ion/ioncore/grouppholder.c
4 * Copyright (c) Tuomo Valkonen 2005-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <libtu/objp.h>
10 #include <libtu/obj.h>
11 #include <libtu/pointer.h>
12 #include <libmainloop/defer.h>
14 #include <ioncore/common.h>
15 #include "group.h"
16 #include "group-cw.h"
17 #include "grouppholder.h"
20 static void group_watch_handler(Watch *watch, Obj *ws);
23 /*{{{ Primitives */
26 void grouppholder_do_link(WGroupPHolder *ph, WGroup *group, WRegion *stack_above)
28 ph->group=group;
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;
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);
44 static WGroupPHolder *get_head(WGroupPHolder *ph)
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;
53 return ph;
57 void grouppholder_do_unlink(WGroupPHolder *ph)
59 WGroup *group=ph->group;
61 watch_reset(&(ph->stack_above_watch));
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);
70 ph->recreate_pholder=NULL;
73 if(group!=NULL){
74 UNLINK_ITEM(group->phs, ph, next, prev);
75 }else if(ph->prev!=NULL){
76 WGroupPHolder *next=ph->next;
78 ph->prev->next=next;
80 if(next==NULL){
81 next=get_head(ph);
82 assert(next->prev==ph);
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).
89 assert(ph->next==NULL);
92 ph->group=NULL;
93 ph->next=NULL;
94 ph->prev=NULL;
98 /*}}}*/
101 /*{{{ Init/deinit */
103 static WGroupAttachParams dummy_param=GROUPATTACHPARAMS_INIT;
106 bool grouppholder_init(WGroupPHolder *ph, WGroup *ws,
107 const WStacking *st,
108 const WGroupAttachParams *param)
110 WRegion *stack_above=NULL;
112 pholder_init(&(ph->ph));
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);
121 if(st!=NULL){
122 /* TODO? Just link to the stacking structure to remember
123 * stacking order?
126 ph->param.szplcy_set=TRUE;
127 ph->param.szplcy=st->szplcy;
128 ph->param.level_set=TRUE;
129 ph->param.level=st->level;
131 if(st->reg!=NULL){
132 ph->param.geom_set=TRUE;
133 ph->param.geom=REGION_GEOM(st->reg);
136 if(st->above!=NULL && st->above->reg!=NULL)
137 ph->param.stack_above=st->above->reg;
139 ph->param.bottom=(st==ws->bottom);
142 ph->param.switchto_set=FALSE;
144 stack_above=ph->param.stack_above;
145 ph->param.stack_above=NULL;
147 grouppholder_do_link(ph, ws, stack_above);
149 return TRUE;
153 WGroupPHolder *create_grouppholder(WGroup *ws,
154 const WStacking *st,
155 const WGroupAttachParams *param)
157 CREATEOBJ_IMPL(WGroupPHolder, grouppholder, (p, ws, st, param));
161 void grouppholder_deinit(WGroupPHolder *ph)
163 grouppholder_do_unlink(ph);
165 pholder_deinit(&(ph->ph));
169 /*}}}*/
172 /*{{{ Dynfuns */
175 static WPHolder *get_recreate_ph(WGroupPHolder *ph)
177 return get_head(ph)->recreate_pholder;
181 typedef struct{
182 WGroupPHolder *ph, *ph_head;
183 WRegionAttachData *data;
184 WRegion *reg_ret;
185 } RP;
188 static WRegion *recreate_handler(WWindow *par,
189 const WFitParams *fp,
190 void *rp_)
192 WGroupPHolder *phtmp;
193 RP *rp=(RP*)rp_;
194 WGroup *grp;
196 grp=(WGroup*)create_groupcw(par, fp);
198 if(grp==NULL)
199 return NULL;
201 rp->ph->param.whatever=(fp->mode&REGION_FIT_WHATEVER ? 1 : 0);
203 rp->reg_ret=group_do_attach(grp, &rp->ph->param, rp->data);
205 rp->ph->param.whatever=0;
207 if(rp->reg_ret==NULL){
208 destroy_obj((Obj*)grp);
209 return NULL;
210 }else{
211 grp->phs=rp->ph_head;
213 for(phtmp=grp->phs; phtmp!=NULL; phtmp=phtmp->next)
214 phtmp->group=grp;
217 if(fp->mode&REGION_FIT_WHATEVER)
218 REGION_GEOM(grp)=REGION_GEOM(rp->reg_ret);
220 return (WRegion*)grp;
225 static WRegion *grouppholder_attach_recreate(WGroupPHolder *ph, int flags,
226 WRegionAttachData *data)
228 WRegionAttachData data2;
229 WPHolder *root, *rph;
230 WRegion *res;
231 RP rp;
233 rp.ph_head=get_head(ph);
235 assert(rp.ph_head!=NULL);
237 rph=rp.ph_head->recreate_pholder;
239 if(rph==NULL)
240 return NULL;
242 rp.ph=ph;
243 rp.data=data;
244 rp.reg_ret=NULL;
246 data2.type=REGION_ATTACH_NEW;
247 data2.u.n.fn=recreate_handler;
248 data2.u.n.param=&rp;
250 res=pholder_do_attach(rph, flags, &data2);
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);
258 return (flags&PHOLDER_ATTACH_RETURN_CREATEROOT
259 ? (WRegion*)res
260 : rp.reg_ret);
264 WRegion *grouppholder_do_attach(WGroupPHolder *ph, int flags,
265 WRegionAttachData *data)
267 WGroup *ws=ph->group;
268 WRegion *reg;
270 if(ws==NULL)
271 return grouppholder_attach_recreate(ph, flags, data);
273 ph->param.switchto_set=1;
274 ph->param.switchto=(flags&PHOLDER_ATTACH_SWITCHTO ? 1 : 0);
276 /* Get stack_above from Watch. */
277 ph->param.stack_above=(WRegion*)ph->stack_above_watch.obj;
279 reg=group_do_attach(ws, &ph->param, data);
281 ph->param.stack_above=NULL;
283 return reg;
287 bool grouppholder_do_goto(WGroupPHolder *ph)
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));
297 WRegion *grouppholder_do_target(WGroupPHolder *ph)
299 return (ph->group!=NULL
300 ? (WRegion*)ph->group
301 : (ph->recreate_pholder!=NULL
302 ? pholder_do_target(ph->recreate_pholder)
303 : NULL));
307 /*}}}*/
310 /*{{{ WGroup stuff */
313 WGroupPHolder *group_managed_get_pholder(WGroup *ws, WRegion *mgd)
315 WStacking *st=group_find_stacking(ws, mgd);
317 if(mgd==NULL)
318 return NULL;
319 else
320 return create_grouppholder(ws, st, NULL);
324 /*}}}*/
327 /*{{{ Class information */
330 static DynFunTab grouppholder_dynfuntab[]={
331 {(DynFun*)pholder_do_attach,
332 (DynFun*)grouppholder_do_attach},
334 {(DynFun*)pholder_do_goto,
335 (DynFun*)grouppholder_do_goto},
337 {(DynFun*)pholder_do_target,
338 (DynFun*)grouppholder_do_target},
340 END_DYNFUNTAB
343 IMPLCLASS(WGroupPHolder, WPHolder, grouppholder_deinit,
344 grouppholder_dynfuntab);
347 /*}}}*/