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