Update contrib
[notion/jeffpc.git] / ioncore / mplexpholder.c
blobc8143f2e350ad8e6f29188d93617dda3b815ef33
1 /*
2 * ion/ioncore/mplexpholder.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 "common.h"
15 #include "mplex.h"
16 #include "mplexpholder.h"
17 #include "llist.h"
18 #include "framedpholder.h"
19 #include "basicpholder.h"
22 /*{{{ Primitives */
25 static bool on_ph_list(WMPlexPHolder *ll, WMPlexPHolder *ph)
27 return ph->prev!=NULL;
31 static void mplexpholder_do_link(WMPlexPHolder *ph,
32 WMPlex *mplex,
33 WMPlexPHolder *after,
34 WLListNode *or_after)
36 assert(mplex==ph->mplex && mplex!=NULL);
38 if(after!=NULL){
39 assert(after->after==or_after);
41 if(after->after!=NULL){
42 LINK_ITEM_AFTER(after->after->phs, after, ph, next, prev);
43 }else{
44 assert(on_ph_list(mplex->misc_phs, after));
45 LINK_ITEM_AFTER(mplex->misc_phs, after, ph, next, prev);
47 ph->after=after->after;
48 }else if(or_after!=NULL){
49 LINK_ITEM_FIRST(or_after->phs, ph, next, prev);
50 ph->after=or_after;
51 }else{
52 LINK_ITEM_FIRST(mplex->misc_phs, ph, next, prev);
53 ph->after=NULL;
58 static WMPlexPHolder *get_head(WMPlexPHolder *ph)
60 while(1){
61 /* ph->prev==NULL should not happen.. */
62 if(ph->prev==NULL || ph->prev->next==NULL)
63 break;
64 ph=ph->prev;
67 return ph;
71 void mplexpholder_do_unlink(WMPlexPHolder *ph, WMPlex *mplex)
73 if(ph->recreate_pholder!=NULL){
74 if(ph->next!=NULL){
75 ph->next->recreate_pholder=ph->recreate_pholder;
76 }else{
77 /* It might be in use in attach chain! So defer. */
78 mainloop_defer_destroy((Obj*)ph->recreate_pholder);
80 ph->recreate_pholder=NULL;
83 if(ph->after!=NULL){
84 UNLINK_ITEM(ph->after->phs, ph, next, prev);
85 }else if(mplex!=NULL && on_ph_list(mplex->misc_phs, ph)){
86 UNLINK_ITEM(mplex->misc_phs, ph, next, prev);
87 }else if(ph->prev!=NULL){
88 WMPlexPHolder *next=ph->next;
90 ph->prev->next=next;
92 if(next==NULL){
93 next=get_head(ph);
94 assert(next->prev==ph);
96 next->prev=ph->prev;
97 }else{
98 /* ph should not be on a list, if prev pointer is NULL (whereas
99 * next alone can be NULL in our semi-doubly-linked lists).
101 assert(ph->next==NULL);
104 ph->after=NULL;
105 ph->next=NULL;
106 ph->prev=NULL;
110 /*}}}*/
113 /*{{{ Init/deinit */
116 static void mplex_get_attach_params(WMPlex *mplex, WStacking *st,
117 WMPlexAttachParams *param)
119 param->flags=(MPLEX_ATTACH_SIZEPOLICY|
120 MPLEX_ATTACH_GEOM|
121 MPLEX_ATTACH_LEVEL|
122 (st->hidden ? MPLEX_ATTACH_HIDDEN : 0)|
123 (st->lnode==NULL ? MPLEX_ATTACH_UNNUMBERED : 0));
124 param->szplcy=st->szplcy;
125 param->geom=REGION_GEOM(st->reg);
126 param->level=st->level;
130 bool mplexpholder_init(WMPlexPHolder *ph, WMPlex *mplex, WStacking *st,
131 WMPlexAttachParams *param)
133 WLListNode *or_after=NULL;
134 WMPlexPHolder *after=NULL;
136 pholder_init(&(ph->ph));
138 ph->mplex=mplex;
139 ph->after=NULL;
140 ph->next=NULL;
141 ph->prev=NULL;
142 ph->param.flags=0;
143 ph->recreate_pholder=NULL;
145 if(st!=NULL){
146 mplex_get_attach_params(mplex, st, &ph->param);
148 if(st->lnode!=NULL){
149 after=LIST_LAST(st->lnode->phs, next, prev);
150 or_after=st->lnode;
152 }else{
153 static WMPlexAttachParams dummy_param={0, 0, {0, 0, 0, 0}, 0, 0};
155 if(param==NULL)
156 param=&dummy_param;
158 ph->param=*param;
160 if(!(param->flags&MPLEX_ATTACH_UNNUMBERED)){
161 int index=(param->flags&MPLEX_ATTACH_INDEX
162 ? param->index
163 : mplex_default_index(mplex));
164 or_after=llist_index_to_after(mplex->mx_list,
165 mplex->mx_current, index);
166 after=(index==LLIST_INDEX_LAST
167 ? (or_after!=NULL
168 ? LIST_LAST(or_after->phs, next, prev)
169 : LIST_LAST(mplex->misc_phs, next, prev))
170 : NULL);
174 mplexpholder_do_link(ph, mplex, after, or_after);
176 return TRUE;
180 WMPlexPHolder *create_mplexpholder(WMPlex *mplex,
181 WStacking *st,
182 WMPlexAttachParams *param)
184 CREATEOBJ_IMPL(WMPlexPHolder, mplexpholder, (p, mplex, st, param));
188 void mplexpholder_deinit(WMPlexPHolder *ph)
190 mplexpholder_do_unlink(ph, ph->mplex);
191 pholder_deinit(&(ph->ph));
195 /*}}}*/
198 /*{{{ Move, attach */
201 typedef struct{
202 WMPlexPHolder *ph, *ph_head;
203 WRegionAttachData *data;
204 WFramedParam *param;
205 WRegion *reg_ret;
206 } RP;
209 static WRegion *recreate_handler(WWindow *par,
210 const WFitParams *fp,
211 void *rp_)
213 RP *rp=(RP*)rp_;
214 WMPlexPHolder *ph=rp->ph, *ph_head=rp->ph_head, *phtmp;
215 WFramedParam *param=rp->param;
216 WFrame *frame;
218 frame=create_frame(par, fp, param->mode);
220 if(frame==NULL)
221 return NULL;
223 /* Move pholders to frame */
224 frame->mplex.misc_phs=ph_head;
226 for(phtmp=frame->mplex.misc_phs; phtmp!=NULL; phtmp=phtmp->next)
227 phtmp->mplex=&frame->mplex;
229 /* Attach */
230 if(fp->mode&(REGION_FIT_BOUNDS|REGION_FIT_WHATEVER))
231 ph->param.flags|=MPLEX_ATTACH_WHATEVER;
233 rp->reg_ret=mplex_do_attach_pholder(&frame->mplex, ph, rp->data);
235 ph->param.flags&=~MPLEX_ATTACH_WHATEVER;
237 if(rp->reg_ret==NULL){
238 /* Try to recover */
239 for(phtmp=frame->mplex.misc_phs; phtmp!=NULL; phtmp=phtmp->next)
240 phtmp->mplex=NULL;
242 frame->mplex.misc_phs=NULL;
244 destroy_obj((Obj*)frame);
246 return NULL;
247 }else{
248 frame_adjust_to_initial(frame, fp, param, rp->reg_ret);
250 return (WRegion*)frame;
255 static WFramedPHolder *get_recreate_ph(WMPlexPHolder *ph)
257 return get_head(ph)->recreate_pholder;
261 static WRegion *mplexpholder_attach_recreate(WMPlexPHolder *ph, int flags,
262 WRegionAttachData *data)
264 WRegionAttachData data2;
265 WFramedPHolder *fph;
266 WPHolder *root;
267 WRegion *res;
268 RP rp;
270 rp.ph_head=get_head(ph);
272 assert(rp.ph_head!=NULL);
274 fph=rp.ph_head->recreate_pholder;
276 if(fph==NULL)
277 return NULL;
279 rp.ph=ph;
280 rp.data=data;
281 rp.param=&fph->param;
282 rp.reg_ret=NULL;
284 data2.type=REGION_ATTACH_NEW;
285 data2.u.n.fn=recreate_handler;
286 data2.u.n.param=&rp;
288 res=pholder_do_attach(fph->cont, flags, &data2);
290 if(res!=NULL){
291 rp.ph_head->recreate_pholder=NULL;
292 /* It might be in use in attach chain! So defer. */
293 mainloop_defer_destroy((Obj*)fph);
296 return (flags&PHOLDER_ATTACH_RETURN_CREATEROOT
297 ? (WRegion*)res
298 : rp.reg_ret);
302 WRegion *mplexpholder_do_attach(WMPlexPHolder *ph, int flags,
303 WRegionAttachData *data)
305 WMPlex *mplex=ph->mplex;
307 if(mplex==NULL)
308 return mplexpholder_attach_recreate(ph, flags, data);
310 if(flags&PHOLDER_ATTACH_SWITCHTO)
311 ph->param.flags|=MPLEX_ATTACH_SWITCHTO;
312 else
313 ph->param.flags&=~MPLEX_ATTACH_SWITCHTO;
315 return mplex_do_attach_pholder(mplex, ph, data);
319 bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex,
320 WMPlexPHolder *after,
321 WLListNode *or_after)
323 mplexpholder_do_unlink(ph, ph->mplex);
325 ph->mplex=mplex;
327 if(mplex==NULL)
328 return TRUE;
330 mplexpholder_do_link(ph, mplex, after, or_after);
332 return TRUE;
336 bool mplexpholder_do_goto(WMPlexPHolder *ph)
338 WRegion *reg=(WRegion*)ph->mplex;
340 if(reg!=NULL){
341 return region_goto(reg);
342 }else{
343 WFramedPHolder *fph=get_recreate_ph(ph);
345 return (fph!=NULL
346 ? pholder_do_goto((WPHolder*)fph)
347 : FALSE);
352 WRegion *mplexpholder_do_target(WMPlexPHolder *ph)
354 WRegion *reg=(WRegion*)ph->mplex;
356 if(reg!=NULL){
357 return reg;
358 }else{
359 WFramedPHolder *fph=get_recreate_ph(ph);
361 return (fph!=NULL
362 ? pholder_do_target((WPHolder*)fph)
363 : NULL);
368 bool mplexpholder_stale(WMPlexPHolder *ph)
370 WRegion *reg=(WRegion*)ph->mplex;
372 if(reg!=NULL){
373 return FALSE;
374 }else{
375 WFramedPHolder *fph=get_recreate_ph(ph);
377 return (fph==NULL || pholder_stale((WPHolder*)fph));
382 /*}}}*/
385 /*{{{ WMPlex routines */
388 void mplex_move_phs(WMPlex *mplex, WLListNode *node,
389 WMPlexPHolder *after,
390 WLListNode *or_after)
392 WMPlexPHolder *ph;
394 assert(node!=or_after);
396 while(node->phs!=NULL){
397 ph=node->phs;
399 mplexpholder_do_unlink(ph, mplex);
400 mplexpholder_do_link(ph, mplex, after, or_after);
402 after=ph;
406 void mplex_move_phs_before(WMPlex *mplex, WLListNode *node)
408 WMPlexPHolder *after=NULL;
409 WLListNode *or_after;
411 or_after=LIST_PREV(mplex->mx_list, node, next, prev);
413 after=(or_after!=NULL
414 ? LIST_LAST(or_after->phs, next, prev)
415 : LIST_LAST(mplex->misc_phs, next, prev));
417 mplex_move_phs(mplex, node, after, or_after);
421 WMPlexPHolder *mplex_managed_get_pholder(WMPlex *mplex, WRegion *mgd)
423 WStacking *st=mplex_find_stacking(mplex, mgd);
425 if(st==NULL)
426 return NULL;
427 else
428 return create_mplexpholder(mplex, st, NULL);
432 void mplex_flatten_phs(WMPlex *mplex)
434 WLListNode *node;
435 WLListIterTmp tmp;
437 FOR_ALL_NODES_ON_LLIST(node, mplex->mx_list, tmp){
438 WMPlexPHolder *last=(mplex->misc_phs==NULL ? NULL : mplex->misc_phs->prev);
439 mplex_move_phs(mplex, node, last, NULL);
444 void mplex_migrate_phs(WMPlex *src, WMPlex *dst)
446 WLListNode *or_after=LIST_LAST(dst->mx_list, next, prev);
447 WMPlexPHolder *after=(or_after!=NULL
448 ? LIST_LAST(or_after->phs, next, prev)
449 : LIST_LAST(dst->misc_phs, next, prev));
451 while(src->misc_phs!=NULL){
452 WMPlexPHolder *ph=src->misc_phs;
453 mplexpholder_move(ph, dst, after, or_after);
454 after=ph;
459 /*}}}*/
462 /*{{ Rescue */
465 WRegion *mplex_rescue_attach(WMPlex *mplex, int flags, WRegionAttachData *data)
467 WMPlexAttachParams param;
469 param.flags=0;
471 /* Improved attach parametrisation hack for WMPlex source */
472 if(data->type==REGION_ATTACH_REPARENT){
473 WRegion *reg=data->u.reg;
474 WMPlex *src_mplex=REGION_MANAGER_CHK(reg, WMPlex);
475 if(src_mplex!=NULL){
476 WStacking *st=ioncore_find_stacking(reg);
477 if(st!=NULL)
478 mplex_get_attach_params(src_mplex, st, &param);
482 param.flags|=(MPLEX_ATTACH_INDEX|
483 (flags&PHOLDER_ATTACH_SWITCHTO ? MPLEX_ATTACH_SWITCHTO : 0));
484 param.index=LLIST_INDEX_LAST;
486 return mplex_do_attach(mplex, &param, data);
490 WPHolder *mplex_get_rescue_pholder_for(WMPlex *mplex, WRegion *mgd)
492 #if 0
493 WStacking *st=mplex_find_stacking(mplex, mgd);
494 WMPlexAttachParams param;
496 param.flags=MPLEX_ATTACH_INDEX;
497 param.index=LLIST_INDEX_LAST;
499 return create_mplexpholder(mplex, st, &param);
500 #else
501 return (WPHolder*)create_basicpholder((WRegion*)mplex,
502 (WBasicPHolderHandler*)mplex_rescue_attach);
503 #endif
507 /*}}}*/
510 /*{{{ Class information */
513 static DynFunTab mplexpholder_dynfuntab[]={
514 {(DynFun*)pholder_do_attach,
515 (DynFun*)mplexpholder_do_attach},
517 {(DynFun*)pholder_do_goto,
518 (DynFun*)mplexpholder_do_goto},
520 {(DynFun*)pholder_do_target,
521 (DynFun*)mplexpholder_do_target},
523 {(DynFun*)pholder_stale,
524 (DynFun*)mplexpholder_stale},
526 END_DYNFUNTAB
530 IMPLCLASS(WMPlexPHolder, WPHolder, mplexpholder_deinit,
531 mplexpholder_dynfuntab);
534 /*}}}*/