]> git.decadent.org.uk Git - ion3.git/blob - ioncore/mplexpholder.c
[svn-upgrade] Integrating new upstream version, ion3 (20070506)
[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
19
20 static void mplex_watch_handler(Watch *watch, Obj *mplex);
21
22
23 /*{{{ Primitives */
24
25
26 static bool on_ph_list(WMPlexPHolder *ll, WMPlexPHolder *ph)
27 {
28     return ph->prev!=NULL;
29 }
30
31
32 static void mplexpholder_do_link(WMPlexPHolder *ph, 
33                                  WMPlex *mplex,
34                                  WMPlexPHolder *after,
35                                  WLListNode *or_after)
36 {
37     assert(mplex==(WMPlex*)ph->mplex_watch.obj && mplex!=NULL);
38     
39     if(after!=NULL){
40         assert(after->after==or_after);
41         
42         if(after->after!=NULL){
43             LINK_ITEM_AFTER(after->after->phs, after, ph, next, prev);
44         }else{
45             assert(on_ph_list(mplex->mx_phs, after));
46             LINK_ITEM_AFTER(mplex->mx_phs, after, ph, next, prev);
47         }
48         ph->after=after->after;
49     }else if(or_after!=NULL){
50         LINK_ITEM_FIRST(or_after->phs, ph, next, prev);
51         ph->after=or_after;
52     }else{
53         LINK_ITEM_FIRST(mplex->mx_phs, ph, next, prev);
54         ph->after=NULL;
55     }
56 }
57
58
59 void mplexpholder_do_unlink(WMPlexPHolder *ph, WMPlex *mplex)
60 {
61     if(ph->recreate_pholder!=NULL){
62         if(ph->prev!=NULL)
63             ph->prev->recreate_pholder=ph->recreate_pholder;
64         else
65             destroy_obj((Obj*)ph->recreate_pholder);
66         ph->recreate_pholder=NULL;
67     }
68     
69     if(ph->after!=NULL){
70         UNLINK_ITEM(ph->after->phs, ph, next, prev);
71     }else if(mplex!=NULL && on_ph_list(mplex->mx_phs, ph)){
72         UNLINK_ITEM(mplex->mx_phs, ph, next, prev);
73     }else{
74         WMPlexPHolder *next=ph->next;
75     
76         assert((ph->next==NULL && ph->prev==NULL)
77                || ph->mplex_watch.obj==NULL);
78         
79         if(ph->next!=NULL)
80             ph->next->prev=ph->prev;
81         if(ph->prev!=NULL)
82             ph->prev->next=next;
83     }
84     
85     ph->after=NULL;
86     ph->next=NULL;
87     ph->prev=NULL;
88 }
89
90
91 /*}}}*/
92
93
94 /*{{{ Init/deinit */
95
96
97 static void mplex_watch_handler(Watch *watch, Obj *mplex)
98 {
99     WMPlexPHolder *ph=FIELD_TO_STRUCT(WMPlexPHolder, mplex_watch, watch);
100     mplexpholder_do_unlink(ph, (WMPlex*)mplex);
101     pholder_redirect(&(ph->ph), (WRegion*)mplex);
102 }
103
104
105 static WMPlexAttachParams dummy_param={0, 0, {0, 0, 0, 0}, 0, 0};
106
107
108 bool mplexpholder_init(WMPlexPHolder *ph, WMPlex *mplex, WStacking *st,
109                        WMPlexAttachParams *param)
110 {
111     pholder_init(&(ph->ph));
112
113     watch_init(&(ph->mplex_watch));
114     ph->after=NULL;
115     ph->next=NULL;
116     ph->prev=NULL;
117     ph->param.flags=0;
118     ph->recreate_pholder=NULL;
119     
120     if(!watch_setup(&(ph->mplex_watch), (Obj*)mplex, mplex_watch_handler)){
121         pholder_deinit(&(ph->ph));
122         return FALSE;
123     }
124
125     if(param==NULL)
126         param=&dummy_param;
127     
128     if(st!=NULL){
129         if(st->lnode!=NULL)
130             mplexpholder_do_link(ph, mplex, 
131                                  LIST_LAST(st->lnode->phs, next, prev), 
132                                  st->lnode);
133         else
134             ph->param.flags|=MPLEX_ATTACH_UNNUMBERED;
135         
136         ph->param.flags|=(MPLEX_ATTACH_SIZEPOLICY|
137                           MPLEX_ATTACH_GEOM|
138                           MPLEX_ATTACH_LEVEL|
139                           (st->hidden ? MPLEX_ATTACH_HIDDEN : 0));
140         ph->param.szplcy=st->szplcy;
141         ph->param.geom=REGION_GEOM(st->reg);
142         ph->param.level=st->level;
143     }else{
144         ph->param=*param;
145         
146         if(!(param->flags&MPLEX_ATTACH_UNNUMBERED)){
147             int index=(param->flags&MPLEX_ATTACH_INDEX
148                        ? param->index
149                        : mplex_default_index(mplex));
150             WLListNode *or_after=llist_index_to_after(mplex->mx_list, 
151                                                       mplex->mx_current, 
152                                                       index);
153             WMPlexPHolder *after=(index==LLIST_INDEX_LAST
154                                   ? (or_after!=NULL
155                                      ? LIST_LAST(or_after->phs, next, prev) 
156                                      : LIST_LAST(mplex->mx_phs, next, prev))
157                                   : NULL);
158
159             mplexpholder_do_link(ph, mplex, after, or_after);
160         }
161     }
162     
163     return TRUE;
164 }
165  
166
167 WMPlexPHolder *create_mplexpholder(WMPlex *mplex,
168                                    WStacking *st,
169                                    WMPlexAttachParams *param)
170 {
171     CREATEOBJ_IMPL(WMPlexPHolder, mplexpholder, (p, mplex, st, param));
172 }
173
174
175 void mplexpholder_deinit(WMPlexPHolder *ph)
176 {
177     mplexpholder_do_unlink(ph, (WMPlex*)ph->mplex_watch.obj);
178     watch_reset(&(ph->mplex_watch));
179     pholder_deinit(&(ph->ph));
180 }
181
182
183 /*}}}*/
184
185
186 /*{{{ Move, attach, layer */
187
188
189 typedef struct{
190     WMPlexPHolder *ph, *ph_head;
191     WRegionAttachData *data;
192     WFramedParam *param;
193 } RP;
194
195
196 WRegion *recreate_handler(WWindow *par, 
197                           const WFitParams *fp, 
198                           void *rp_)
199 {
200     RP *rp=(RP*)rp_;
201     WMPlexPHolder *ph=rp->ph, *ph_head=rp->ph_head, *phtmp;
202     WFramedParam *param=rp->param;
203     WFrame *frame;
204     WRegion *reg;
205     
206     frame=create_frame(par, fp, param->mode);
207     
208     if(frame==NULL)
209         return NULL;
210     
211     /* Move pholders to frame */
212     frame->mplex.mx_phs=ph_head;
213     
214     for(phtmp=frame->mplex.mx_phs; phtmp!=NULL; phtmp=phtmp->next)
215         watch_setup(&(phtmp->mplex_watch), (Obj*)frame, mplex_watch_handler);
216         
217     /* Attach */
218     if(fp->mode&(REGION_FIT_BOUNDS|REGION_FIT_WHATEVER))
219         ph->param.flags|=MPLEX_ATTACH_WHATEVER;
220     
221     reg=mplex_do_attach_pholder(&frame->mplex, ph, rp->data);
222
223     ph->param.flags&=~MPLEX_ATTACH_WHATEVER;
224
225     if(reg==NULL){
226         /* Try to recover */
227         for(phtmp=frame->mplex.mx_phs; phtmp!=NULL; phtmp=phtmp->next)
228             watch_reset(&(phtmp->mplex_watch));
229         frame->mplex.mx_phs=NULL;
230     
231         destroy_obj((Obj*)frame);
232         
233         return NULL;
234     }else{
235         frame_adjust_to_initial(frame, fp, param, reg);
236         
237         return (WRegion*)frame;
238     }
239 }
240
241
242 static WMPlexPHolder *get_head(WMPlexPHolder *ph)
243 {
244     while(1){
245         /* ph->prev==NULL should not happen.. */
246         if(ph->prev==NULL || ph->prev->next==NULL)
247             break;
248         ph=ph->prev;
249     }
250     
251     return ph;
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 *reg;
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     
283     data2.type=REGION_ATTACH_NEW;
284     data2.u.n.fn=recreate_handler;
285     data2.u.n.param=&rp;
286     
287     reg=pholder_do_attach(fph->cont, flags, &data2); /* == frame */
288     
289     if(reg!=NULL){
290         destroy_obj((Obj*)fph);
291         rp.ph_head->recreate_pholder=NULL;
292     }
293
294     return reg;
295 }
296
297
298 WRegion *mplexpholder_do_attach(WMPlexPHolder *ph, int flags,
299                                 WRegionAttachData *data)
300 {
301     WMPlex *mplex=(WMPlex*)ph->mplex_watch.obj;
302     
303     if(mplex==NULL)
304         return mplexpholder_attach_recreate(ph, flags, data);
305     
306     if(flags&PHOLDER_ATTACH_SWITCHTO)
307         ph->param.flags|=MPLEX_ATTACH_SWITCHTO;
308     else
309         ph->param.flags&=~MPLEX_ATTACH_SWITCHTO;
310     
311     return mplex_do_attach_pholder(mplex, ph, data);
312 }
313
314
315 bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex, 
316                        WMPlexPHolder *after,
317                        WLListNode *or_after)
318
319 {
320     mplexpholder_do_unlink(ph, (WMPlex*)ph->mplex_watch.obj);
321
322     watch_reset(&(ph->mplex_watch));
323     
324     if(mplex==NULL)
325         return TRUE;
326     
327     if(!watch_setup(&(ph->mplex_watch), (Obj*)mplex, mplex_watch_handler))
328         return FALSE;
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_watch.obj;
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_watch.obj;
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 WPHolder *mplexpholder_do_root(WMPlexPHolder *ph)
369 {
370     WRegion *reg=(WRegion*)ph->mplex_watch.obj;
371     
372     if(reg!=NULL){
373         return &ph->ph;
374     }else{
375         WFramedPHolder *fph=get_recreate_ph(ph);
376         WPHolder *root;
377         
378         if(fph==NULL)
379             return NULL;
380     
381         root=pholder_root((WPHolder*)fph);
382     
383         return (root!=(WPHolder*)fph
384                 ? root
385                 : &ph->ph);
386     }
387 }
388
389
390 /*}}}*/
391
392
393 /*{{{ WMPlex routines */
394
395
396 void mplex_move_phs(WMPlex *mplex, WLListNode *node,
397                     WMPlexPHolder *after,
398                     WLListNode *or_after)
399 {
400     WMPlexPHolder *ph;
401     
402     assert(node!=or_after);
403     
404     while(node->phs!=NULL){
405         ph=node->phs;
406         
407         mplexpholder_do_unlink(ph, mplex);
408         mplexpholder_do_link(ph, mplex, after, or_after);
409         
410         after=ph;
411     }
412 }
413
414 void mplex_move_phs_before(WMPlex *mplex, WLListNode *node)
415 {
416     WMPlexPHolder *after=NULL;
417     WLListNode *or_after;
418     
419     or_after=LIST_PREV(mplex->mx_list, node, next, prev);
420                          
421     after=(or_after!=NULL
422            ? LIST_LAST(or_after->phs, next, prev)
423            : LIST_LAST(mplex->mx_phs, next, prev));
424         
425     mplex_move_phs(mplex, node, after, or_after);
426 }
427
428
429 WMPlexPHolder *mplex_managed_get_pholder(WMPlex *mplex, WRegion *mgd)
430 {
431     WStacking *st=mplex_find_stacking(mplex, mgd);
432     
433     if(st==NULL)
434         return NULL;
435     else
436         return create_mplexpholder(mplex, st, NULL);
437 }
438
439
440 WMPlexPHolder *mplex_get_rescue_pholder_for(WMPlex *mplex, WRegion *mgd)
441 {
442     WStacking *st=mplex_find_stacking(mplex, mgd);
443     
444     return create_mplexpholder(mplex, st, NULL);
445 }
446
447
448 /*}}}*/
449
450
451 /*{{{ Class information */
452
453
454 static DynFunTab mplexpholder_dynfuntab[]={
455     {(DynFun*)pholder_do_attach, 
456      (DynFun*)mplexpholder_do_attach},
457     
458     {(DynFun*)pholder_do_goto, 
459      (DynFun*)mplexpholder_do_goto},
460
461     {(DynFun*)pholder_do_target, 
462      (DynFun*)mplexpholder_do_target},
463      
464     {(DynFun*)pholder_do_root, 
465      (DynFun*)mplexpholder_do_root},
466
467     END_DYNFUNTAB
468 };
469
470
471 IMPLCLASS(WMPlexPHolder, WPHolder, mplexpholder_deinit, 
472           mplexpholder_dynfuntab);
473
474
475 /*}}}*/
476