]> git.decadent.org.uk Git - ion3.git/blob - ioncore/mplexpholder.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / mplexpholder.c
1 /*
2  * ion/ioncore/mplexpholder.c
3  *
4  * Copyright (c) Tuomo Valkonen 2005-2009. 
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 if(ph->prev!=NULL){
88         WMPlexPHolder *next=ph->next;
89
90         ph->prev->next=next;
91
92         if(next==NULL){
93             next=get_head(ph);
94             assert(next->prev==ph);
95         }
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).
100          */
101         assert(ph->next==NULL);
102     }
103     
104     ph->after=NULL;
105     ph->next=NULL;
106     ph->prev=NULL;
107 }
108
109
110 /*}}}*/
111
112
113 /*{{{ Init/deinit */
114
115
116 static void mplex_get_attach_params(WMPlex *mplex, WStacking *st,
117                                     WMPlexAttachParams *param)
118 {
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;
127 }
128
129
130 bool mplexpholder_init(WMPlexPHolder *ph, WMPlex *mplex, WStacking *st,
131                        WMPlexAttachParams *param)
132 {
133     WLListNode *or_after=NULL;
134     WMPlexPHolder *after=NULL;
135     
136     pholder_init(&(ph->ph));
137
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;
144
145     if(st!=NULL){
146         mplex_get_attach_params(mplex, st, &ph->param);
147         
148         if(st->lnode!=NULL){
149             after=LIST_LAST(st->lnode->phs, next, prev);
150             or_after=st->lnode;
151         }
152     }else{
153         static WMPlexAttachParams dummy_param={0, 0, {0, 0, 0, 0}, 0, 0};
154         
155         if(param==NULL)
156             param=&dummy_param;
157         
158         ph->param=*param;
159         
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);
171         }
172     }
173
174     mplexpholder_do_link(ph, mplex, after, or_after);
175     
176     return TRUE;
177 }
178  
179
180 WMPlexPHolder *create_mplexpholder(WMPlex *mplex,
181                                    WStacking *st,
182                                    WMPlexAttachParams *param)
183 {
184     CREATEOBJ_IMPL(WMPlexPHolder, mplexpholder, (p, mplex, st, param));
185 }
186
187
188 void mplexpholder_deinit(WMPlexPHolder *ph)
189 {
190     mplexpholder_do_unlink(ph, ph->mplex);
191     pholder_deinit(&(ph->ph));
192 }
193
194
195 /*}}}*/
196
197
198 /*{{{ Move, attach */
199
200
201 typedef struct{
202     WMPlexPHolder *ph, *ph_head;
203     WRegionAttachData *data;
204     WFramedParam *param;
205     WRegion *reg_ret;
206 } RP;
207
208
209 static WRegion *recreate_handler(WWindow *par, 
210                                  const WFitParams *fp, 
211                                  void *rp_)
212 {
213     RP *rp=(RP*)rp_;
214     WMPlexPHolder *ph=rp->ph, *ph_head=rp->ph_head, *phtmp;
215     WFramedParam *param=rp->param;
216     WFrame *frame;
217     
218     frame=create_frame(par, fp, param->mode);
219     
220     if(frame==NULL)
221         return NULL;
222     
223     /* Move pholders to frame */
224     frame->mplex.misc_phs=ph_head;
225     
226     for(phtmp=frame->mplex.misc_phs; phtmp!=NULL; phtmp=phtmp->next)
227         phtmp->mplex=&frame->mplex;
228         
229     /* Attach */
230     if(fp->mode&(REGION_FIT_BOUNDS|REGION_FIT_WHATEVER))
231         ph->param.flags|=MPLEX_ATTACH_WHATEVER;
232     
233     rp->reg_ret=mplex_do_attach_pholder(&frame->mplex, ph, rp->data);
234
235     ph->param.flags&=~MPLEX_ATTACH_WHATEVER;
236
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;
241         
242         frame->mplex.misc_phs=NULL;
243     
244         destroy_obj((Obj*)frame);
245         
246         return NULL;
247     }else{
248         frame_adjust_to_initial(frame, fp, param, rp->reg_ret);
249         
250         return (WRegion*)frame;
251     }
252 }
253
254
255 static WFramedPHolder *get_recreate_ph(WMPlexPHolder *ph)
256 {
257     return get_head(ph)->recreate_pholder;
258 }
259
260     
261 static WRegion *mplexpholder_attach_recreate(WMPlexPHolder *ph, int flags,
262                                              WRegionAttachData *data)
263 {
264     WRegionAttachData data2;
265     WFramedPHolder *fph;
266     WPHolder *root;
267     WRegion *res;
268     RP rp;
269     
270     rp.ph_head=get_head(ph);
271     
272     assert(rp.ph_head!=NULL);
273     
274     fph=rp.ph_head->recreate_pholder;
275     
276     if(fph==NULL)
277         return NULL;
278     
279     rp.ph=ph;
280     rp.data=data;
281     rp.param=&fph->param;
282     rp.reg_ret=NULL;
283     
284     data2.type=REGION_ATTACH_NEW;
285     data2.u.n.fn=recreate_handler;
286     data2.u.n.param=&rp;
287     
288     res=pholder_do_attach(fph->cont, flags, &data2);
289     
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);
294     }
295     
296     return (flags&PHOLDER_ATTACH_RETURN_CREATEROOT
297             ? (WRegion*)res
298             : rp.reg_ret);
299 }
300
301
302 WRegion *mplexpholder_do_attach(WMPlexPHolder *ph, int flags,
303                                 WRegionAttachData *data)
304 {
305     WMPlex *mplex=ph->mplex;
306     
307     if(mplex==NULL)
308         return mplexpholder_attach_recreate(ph, flags, data);
309     
310     if(flags&PHOLDER_ATTACH_SWITCHTO)
311         ph->param.flags|=MPLEX_ATTACH_SWITCHTO;
312     else
313         ph->param.flags&=~MPLEX_ATTACH_SWITCHTO;
314     
315     return mplex_do_attach_pholder(mplex, ph, data);
316 }
317
318
319 bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex, 
320                        WMPlexPHolder *after,
321                        WLListNode *or_after)
322 {
323     mplexpholder_do_unlink(ph, ph->mplex);
324
325     ph->mplex=mplex;
326         
327     if(mplex==NULL)
328         return TRUE;
329     
330     mplexpholder_do_link(ph, mplex, after, or_after);
331     
332     return TRUE;
333 }
334
335
336 bool mplexpholder_do_goto(WMPlexPHolder *ph)
337 {
338     WRegion *reg=(WRegion*)ph->mplex;
339     
340     if(reg!=NULL){
341         return region_goto(reg);
342     }else{
343         WFramedPHolder *fph=get_recreate_ph(ph);
344         
345         return (fph!=NULL
346                 ? pholder_do_goto((WPHolder*)fph)
347                 : FALSE);
348     }
349 }
350
351
352 WRegion *mplexpholder_do_target(WMPlexPHolder *ph)
353 {
354     WRegion *reg=(WRegion*)ph->mplex;
355     
356     if(reg!=NULL){
357         return reg;
358     }else{
359         WFramedPHolder *fph=get_recreate_ph(ph);
360         
361         return (fph!=NULL
362                 ? pholder_do_target((WPHolder*)fph)
363                 : NULL);
364     }
365 }
366
367
368 bool mplexpholder_stale(WMPlexPHolder *ph)
369 {
370     WRegion *reg=(WRegion*)ph->mplex;
371     
372     if(reg!=NULL){
373         return FALSE;
374     }else{
375         WFramedPHolder *fph=get_recreate_ph(ph);
376         
377         return (fph==NULL || pholder_stale((WPHolder*)fph));
378     }
379 }
380
381
382 /*}}}*/
383
384
385 /*{{{ WMPlex routines */
386
387
388 void mplex_move_phs(WMPlex *mplex, WLListNode *node,
389                     WMPlexPHolder *after,
390                     WLListNode *or_after)
391 {
392     WMPlexPHolder *ph;
393     
394     assert(node!=or_after);
395     
396     while(node->phs!=NULL){
397         ph=node->phs;
398         
399         mplexpholder_do_unlink(ph, mplex);
400         mplexpholder_do_link(ph, mplex, after, or_after);
401         
402         after=ph;
403     }
404 }
405
406 void mplex_move_phs_before(WMPlex *mplex, WLListNode *node)
407 {
408     WMPlexPHolder *after=NULL;
409     WLListNode *or_after;
410     
411     or_after=LIST_PREV(mplex->mx_list, node, next, prev);
412                          
413     after=(or_after!=NULL
414            ? LIST_LAST(or_after->phs, next, prev)
415            : LIST_LAST(mplex->misc_phs, next, prev));
416         
417     mplex_move_phs(mplex, node, after, or_after);
418 }
419
420
421 WMPlexPHolder *mplex_managed_get_pholder(WMPlex *mplex, WRegion *mgd)
422 {
423     WStacking *st=mplex_find_stacking(mplex, mgd);
424     
425     if(st==NULL)
426         return NULL;
427     else
428         return create_mplexpholder(mplex, st, NULL);
429 }
430
431
432 void mplex_flatten_phs(WMPlex *mplex)
433 {
434     WLListNode *node;
435     WLListIterTmp tmp;
436
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);
440     }
441 }
442
443
444 void mplex_migrate_phs(WMPlex *src, WMPlex *dst)
445 {
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));
450     
451     while(src->misc_phs!=NULL){
452         WMPlexPHolder *ph=src->misc_phs;
453         mplexpholder_move(ph, dst, after, or_after);
454         after=ph;
455     }
456 }
457
458
459 /*}}}*/
460
461
462 /*{{ Rescue */
463
464
465 WRegion *mplex_rescue_attach(WMPlex *mplex, int flags, WRegionAttachData *data)
466 {
467     WMPlexAttachParams param;
468     
469     param.flags=0;
470     
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);
479         }
480     }
481     
482     param.flags|=(MPLEX_ATTACH_INDEX|
483                   (flags&PHOLDER_ATTACH_SWITCHTO ? MPLEX_ATTACH_SWITCHTO : 0));
484     param.index=LLIST_INDEX_LAST;
485
486     return mplex_do_attach(mplex, &param, data);
487 }
488
489
490 WPHolder *mplex_get_rescue_pholder_for(WMPlex *mplex, WRegion *mgd)
491 {
492 #if 0
493     WStacking *st=mplex_find_stacking(mplex, mgd);
494     WMPlexAttachParams param;
495     
496     param.flags=MPLEX_ATTACH_INDEX;
497     param.index=LLIST_INDEX_LAST;
498     
499     return create_mplexpholder(mplex, st, &param);
500 #else
501     return (WPHolder*)create_basicpholder((WRegion*)mplex, 
502                                           (WBasicPHolderHandler*)mplex_rescue_attach);
503 #endif
504 }
505
506
507 /*}}}*/
508
509
510 /*{{{ Class information */
511
512
513 static DynFunTab mplexpholder_dynfuntab[]={
514     {(DynFun*)pholder_do_attach, 
515      (DynFun*)mplexpholder_do_attach},
516     
517     {(DynFun*)pholder_do_goto, 
518      (DynFun*)mplexpholder_do_goto},
519
520     {(DynFun*)pholder_do_target, 
521      (DynFun*)mplexpholder_do_target},
522      
523     {(DynFun*)pholder_stale, 
524      (DynFun*)mplexpholder_stale},
525
526     END_DYNFUNTAB
527 };
528
529
530 IMPLCLASS(WMPlexPHolder, WPHolder, mplexpholder_deinit, 
531           mplexpholder_dynfuntab);
532
533
534 /*}}}*/
535