]> git.decadent.org.uk Git - ion3.git/blob - ioncore/mplexpholder.c
3cbf5fdc2fa46a87471482c2d71502780fcae14a
[ion3.git] / ioncore / mplexpholder.c
1 /*
2  * ion/ioncore/mplexpholder.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 "common.h"
15 #include "mplex.h"
16 #include "mplexpholder.h"
17 #include "llist.h"
18 #include "framedpholder.h"
19 #include "basicpholder.h"
20
21
22 /*{{{ Primitives */
23
24
25 static bool on_ph_list(WMPlexPHolder *ll, WMPlexPHolder *ph)
26 {
27     return ph->prev!=NULL;
28 }
29
30
31 static void mplexpholder_do_link(WMPlexPHolder *ph, 
32                                  WMPlex *mplex,
33                                  WMPlexPHolder *after,
34                                  WLListNode *or_after)
35 {
36     assert(mplex==(WMPlex*)ph->mplex && mplex!=NULL);
37     
38     if(after!=NULL){
39         assert(after->after==or_after);
40         
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);
46         }
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;
54     }
55 }
56
57
58 static WMPlexPHolder *get_head(WMPlexPHolder *ph)
59 {
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;
65     }
66     
67     return ph;
68 }
69
70
71 void mplexpholder_do_unlink(WMPlexPHolder *ph, WMPlex *mplex)
72 {
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);
79         }
80         ph->recreate_pholder=NULL;
81     }
82     
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{
88         WMPlexPHolder *next=ph->next;
89         
90         if(ph->prev!=NULL)
91             ph->prev->next=next;
92
93         if(next==NULL){
94             next=get_head(ph);
95             assert(next->prev==ph);
96         }
97         next->prev=ph->prev;
98     }
99     
100     ph->after=NULL;
101     ph->next=NULL;
102     ph->prev=NULL;
103 }
104
105
106 /*}}}*/
107
108
109 /*{{{ Init/deinit */
110
111
112 static void mplex_get_attach_params(WMPlex *mplex, WStacking *st,
113                                     WMPlexAttachParams *param)
114 {
115     param->flags=(MPLEX_ATTACH_SIZEPOLICY|
116                   MPLEX_ATTACH_GEOM|
117                   MPLEX_ATTACH_LEVEL|
118                   (st->hidden ? MPLEX_ATTACH_HIDDEN : 0)|
119                   (st->lnode==NULL ? MPLEX_ATTACH_UNNUMBERED : 0));
120     param->szplcy=st->szplcy;
121     param->geom=REGION_GEOM(st->reg);
122     param->level=st->level;
123 }
124
125
126 bool mplexpholder_init(WMPlexPHolder *ph, WMPlex *mplex, WStacking *st,
127                        WMPlexAttachParams *param)
128 {
129     WLListNode *or_after=NULL;
130     WMPlexPHolder *after=NULL;
131     
132     pholder_init(&(ph->ph));
133
134     ph->mplex=mplex;
135     ph->after=NULL;
136     ph->next=NULL;
137     ph->prev=NULL;
138     ph->param.flags=0;
139     ph->recreate_pholder=NULL;
140
141     if(st!=NULL){
142         mplex_get_attach_params(mplex, st, &ph->param);
143         
144         if(st->lnode!=NULL){
145             after=LIST_LAST(st->lnode->phs, next, prev);
146             or_after=st->lnode;
147         }
148     }else{
149         static WMPlexAttachParams dummy_param={0, 0, {0, 0, 0, 0}, 0, 0};
150         
151         if(param==NULL)
152             param=&dummy_param;
153         
154         ph->param=*param;
155         
156         if(!(param->flags&MPLEX_ATTACH_UNNUMBERED)){
157             int index=(param->flags&MPLEX_ATTACH_INDEX
158                        ? param->index
159                        : mplex_default_index(mplex));
160             or_after=llist_index_to_after(mplex->mx_list, 
161                                           mplex->mx_current, index);
162             after=(index==LLIST_INDEX_LAST
163                    ? (or_after!=NULL
164                       ? LIST_LAST(or_after->phs, next, prev) 
165                       : LIST_LAST(mplex->misc_phs, next, prev))
166                    : NULL);
167         }
168     }
169
170     mplexpholder_do_link(ph, mplex, after, or_after);
171     
172     return TRUE;
173 }
174  
175
176 WMPlexPHolder *create_mplexpholder(WMPlex *mplex,
177                                    WStacking *st,
178                                    WMPlexAttachParams *param)
179 {
180     CREATEOBJ_IMPL(WMPlexPHolder, mplexpholder, (p, mplex, st, param));
181 }
182
183
184 void mplexpholder_deinit(WMPlexPHolder *ph)
185 {
186     mplexpholder_do_unlink(ph, ph->mplex);
187     pholder_deinit(&(ph->ph));
188 }
189
190
191 /*}}}*/
192
193
194 /*{{{ Move, attach */
195
196
197 typedef struct{
198     WMPlexPHolder *ph, *ph_head;
199     WRegionAttachData *data;
200     WFramedParam *param;
201     WRegion *reg_ret;
202 } RP;
203
204
205 static WRegion *recreate_handler(WWindow *par, 
206                                  const WFitParams *fp, 
207                                  void *rp_)
208 {
209     RP *rp=(RP*)rp_;
210     WMPlexPHolder *ph=rp->ph, *ph_head=rp->ph_head, *phtmp;
211     WFramedParam *param=rp->param;
212     WFrame *frame;
213     
214     frame=create_frame(par, fp, param->mode);
215     
216     if(frame==NULL)
217         return NULL;
218     
219     /* Move pholders to frame */
220     frame->mplex.misc_phs=ph_head;
221     
222     for(phtmp=frame->mplex.misc_phs; phtmp!=NULL; phtmp=phtmp->next)
223         phtmp->mplex=&frame->mplex;
224         
225     /* Attach */
226     if(fp->mode&(REGION_FIT_BOUNDS|REGION_FIT_WHATEVER))
227         ph->param.flags|=MPLEX_ATTACH_WHATEVER;
228     
229     rp->reg_ret=mplex_do_attach_pholder(&frame->mplex, ph, rp->data);
230
231     ph->param.flags&=~MPLEX_ATTACH_WHATEVER;
232
233     if(rp->reg_ret==NULL){
234         /* Try to recover */
235         for(phtmp=frame->mplex.misc_phs; phtmp!=NULL; phtmp=phtmp->next)
236             phtmp->mplex=NULL;
237         
238         frame->mplex.misc_phs=NULL;
239     
240         destroy_obj((Obj*)frame);
241         
242         return NULL;
243     }else{
244         frame_adjust_to_initial(frame, fp, param, rp->reg_ret);
245         
246         return (WRegion*)frame;
247     }
248 }
249
250
251 static WFramedPHolder *get_recreate_ph(WMPlexPHolder *ph)
252 {
253     return get_head(ph)->recreate_pholder;
254 }
255
256     
257 static WRegion *mplexpholder_attach_recreate(WMPlexPHolder *ph, int flags,
258                                              WRegionAttachData *data)
259 {
260     WRegionAttachData data2;
261     WFramedPHolder *fph;
262     WPHolder *root;
263     WRegion *frame;
264     RP rp;
265     
266     rp.ph_head=get_head(ph);
267     
268     assert(rp.ph_head!=NULL);
269     
270     fph=rp.ph_head->recreate_pholder;
271     
272     if(fph==NULL)
273         return NULL;
274     
275     rp.ph=ph;
276     rp.data=data;
277     rp.param=&fph->param;
278     rp.reg_ret=NULL;
279     
280     data2.type=REGION_ATTACH_NEW;
281     data2.u.n.fn=recreate_handler;
282     data2.u.n.param=&rp;
283     
284     frame=pholder_do_attach(fph->cont, flags, &data2);
285     
286     if(frame!=NULL){
287         rp.ph_head->recreate_pholder=NULL;
288         /* It might be in use in attach chain! So defer. */
289         mainloop_defer_destroy((Obj*)fph);
290     }
291     
292     return rp.reg_ret;
293 }
294
295
296 WRegion *mplexpholder_do_attach(WMPlexPHolder *ph, int flags,
297                                 WRegionAttachData *data)
298 {
299     WMPlex *mplex=ph->mplex;
300     
301     if(mplex==NULL)
302         return mplexpholder_attach_recreate(ph, flags, data);
303     
304     if(flags&PHOLDER_ATTACH_SWITCHTO)
305         ph->param.flags|=MPLEX_ATTACH_SWITCHTO;
306     else
307         ph->param.flags&=~MPLEX_ATTACH_SWITCHTO;
308     
309     return mplex_do_attach_pholder(mplex, ph, data);
310 }
311
312
313 bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex, 
314                        WMPlexPHolder *after,
315                        WLListNode *or_after)
316 {
317     mplexpholder_do_unlink(ph, ph->mplex);
318
319     ph->mplex=mplex;
320         
321     if(mplex==NULL)
322         return TRUE;
323     
324     mplexpholder_do_link(ph, mplex, after, or_after);
325     
326     return TRUE;
327 }
328
329
330 bool mplexpholder_do_goto(WMPlexPHolder *ph)
331 {
332     WRegion *reg=(WRegion*)ph->mplex;
333     
334     if(reg!=NULL){
335         return region_goto(reg);
336     }else{
337         WFramedPHolder *fph=get_recreate_ph(ph);
338         
339         return (fph!=NULL
340                 ? pholder_do_goto((WPHolder*)fph)
341                 : FALSE);
342     }
343 }
344
345
346 WRegion *mplexpholder_do_target(WMPlexPHolder *ph)
347 {
348     WRegion *reg=(WRegion*)ph->mplex;
349     
350     if(reg!=NULL){
351         return reg;
352     }else{
353         WFramedPHolder *fph=get_recreate_ph(ph);
354         
355         return (fph!=NULL
356                 ? pholder_do_target((WPHolder*)fph)
357                 : NULL);
358     }
359 }
360
361
362 bool mplexpholder_stale(WMPlexPHolder *ph)
363 {
364     WRegion *reg=(WRegion*)ph->mplex;
365     
366     if(reg!=NULL){
367         return FALSE;
368     }else{
369         WFramedPHolder *fph=get_recreate_ph(ph);
370         
371         return (fph==NULL || pholder_stale((WPHolder*)fph));
372     }
373 }
374
375
376 /*}}}*/
377
378
379 /*{{{ WMPlex routines */
380
381
382 void mplex_move_phs(WMPlex *mplex, WLListNode *node,
383                     WMPlexPHolder *after,
384                     WLListNode *or_after)
385 {
386     WMPlexPHolder *ph;
387     
388     assert(node!=or_after);
389     
390     while(node->phs!=NULL){
391         ph=node->phs;
392         
393         mplexpholder_do_unlink(ph, mplex);
394         mplexpholder_do_link(ph, mplex, after, or_after);
395         
396         after=ph;
397     }
398 }
399
400 void mplex_move_phs_before(WMPlex *mplex, WLListNode *node)
401 {
402     WMPlexPHolder *after=NULL;
403     WLListNode *or_after;
404     
405     or_after=LIST_PREV(mplex->mx_list, node, next, prev);
406                          
407     after=(or_after!=NULL
408            ? LIST_LAST(or_after->phs, next, prev)
409            : LIST_LAST(mplex->misc_phs, next, prev));
410         
411     mplex_move_phs(mplex, node, after, or_after);
412 }
413
414
415 WMPlexPHolder *mplex_managed_get_pholder(WMPlex *mplex, WRegion *mgd)
416 {
417     WStacking *st=mplex_find_stacking(mplex, mgd);
418     
419     if(st==NULL)
420         return NULL;
421     else
422         return create_mplexpholder(mplex, st, NULL);
423 }
424
425
426 void mplex_flatten_phs(WMPlex *mplex)
427 {
428     WLListNode *node;
429     WLListIterTmp tmp;
430
431     FOR_ALL_NODES_ON_LLIST(node, mplex->mx_list, tmp){
432         WMPlexPHolder *last=(mplex->misc_phs==NULL ? NULL : mplex->misc_phs->prev);
433         mplex_move_phs(mplex, node, last, NULL);
434     }
435 }
436
437
438 void mplex_migrate_phs(WMPlex *src, WMPlex *dst)
439 {
440     WLListNode *or_after=LIST_LAST(dst->mx_list, next, prev);
441     WMPlexPHolder *after=(or_after!=NULL
442                           ? LIST_LAST(or_after->phs, next, prev)
443                           : LIST_LAST(dst->misc_phs, next, prev));
444     
445     while(src->misc_phs!=NULL){
446         WMPlexPHolder *ph=src->misc_phs;
447         mplexpholder_move(ph, dst, after, or_after);
448         after=ph;
449     }
450 }
451
452
453 /*}}}*/
454
455
456 /*{{ Rescue */
457
458
459 WRegion *mplex_rescue_attach(WMPlex *mplex, int flags, WRegionAttachData *data)
460 {
461     WMPlexAttachParams param;
462     
463     param.flags=0;
464     
465     /* Improved attach parametrisation hack for WMPlex source */
466     if(data->type==REGION_ATTACH_REPARENT){
467         WRegion *reg=data->u.reg;
468         WMPlex *src_mplex=REGION_MANAGER_CHK(reg, WMPlex);
469         if(src_mplex!=NULL){
470             WStacking *st=ioncore_find_stacking(reg);
471             if(st!=NULL)
472                 mplex_get_attach_params(src_mplex, st, &param);
473         }
474     }
475     
476     param.flags|=(MPLEX_ATTACH_INDEX|
477                   (flags&PHOLDER_ATTACH_SWITCHTO ? MPLEX_ATTACH_SWITCHTO : 0));
478     param.index=LLIST_INDEX_LAST;
479
480     return mplex_do_attach(mplex, &param, data);
481 }
482
483
484 WPHolder *mplex_get_rescue_pholder_for(WMPlex *mplex, WRegion *mgd)
485 {
486 #if 0
487     WStacking *st=mplex_find_stacking(mplex, mgd);
488     WMPlexAttachParams param;
489     
490     param.flags=MPLEX_ATTACH_INDEX;
491     param.index=LLIST_INDEX_LAST;
492     
493     return create_mplexpholder(mplex, st, &param);
494 #else
495     return (WPHolder*)create_basicpholder((WRegion*)mplex, 
496                                           (WBasicPHolderHandler*)mplex_rescue_attach);
497 #endif
498 }
499
500
501 /*}}}*/
502
503
504 /*{{{ Class information */
505
506
507 static DynFunTab mplexpholder_dynfuntab[]={
508     {(DynFun*)pholder_do_attach, 
509      (DynFun*)mplexpholder_do_attach},
510     
511     {(DynFun*)pholder_do_goto, 
512      (DynFun*)mplexpholder_do_goto},
513
514     {(DynFun*)pholder_do_target, 
515      (DynFun*)mplexpholder_do_target},
516      
517     {(DynFun*)pholder_stale, 
518      (DynFun*)mplexpholder_stale},
519
520     END_DYNFUNTAB
521 };
522
523
524 IMPLCLASS(WMPlexPHolder, WPHolder, mplexpholder_deinit, 
525           mplexpholder_dynfuntab);
526
527
528 /*}}}*/
529