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