]> git.decadent.org.uk Git - ion3.git/blob - ioncore/mplexpholder.c
51166f77edbbc478a41368f20d77e73e20ac4588
[ion3.git] / ioncore / mplexpholder.c
1 /*
2  * ion/ioncore/mplexpholder.c
3  *
4  * Copyright (c) Tuomo Valkonen 2005-2006. 
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
21
22 static void mplex_watch_handler(Watch *watch, Obj *mplex);
23
24
25 /*{{{ Primitives */
26
27
28 static bool on_ph_list(WMPlexPHolder *ll, WMPlexPHolder *ph)
29 {
30     return ph->prev!=NULL;
31 }
32
33
34 static void mplexpholder_do_link(WMPlexPHolder *ph, 
35                                  WMPlex *mplex,
36                                  WMPlexPHolder *after,
37                                  WLListNode *or_after)
38 {
39     assert(mplex==(WMPlex*)ph->mplex_watch.obj && mplex!=NULL);
40     
41     if(after!=NULL){
42         assert(after->after==or_after);
43         
44         if(after->after!=NULL){
45             LINK_ITEM_AFTER(after->after->phs, after, ph, next, prev);
46         }else{
47             assert(on_ph_list(mplex->mx_phs, after));
48             LINK_ITEM_AFTER(mplex->mx_phs, after, ph, next, prev);
49         }
50         ph->after=after->after;
51     }else if(or_after!=NULL){
52         LINK_ITEM_FIRST(or_after->phs, ph, next, prev);
53         ph->after=or_after;
54     }else{
55         LINK_ITEM_FIRST(mplex->mx_phs, ph, next, prev);
56         ph->after=NULL;
57     }
58 }
59
60
61 void mplexpholder_do_unlink(WMPlexPHolder *ph, WMPlex *mplex)
62 {
63     if(ph->after!=NULL){
64         UNLINK_ITEM(ph->after->phs, ph, next, prev);
65     }else if(mplex!=NULL && on_ph_list(mplex->mx_phs, ph)){
66         UNLINK_ITEM(mplex->mx_phs, ph, next, prev);
67     }else{
68         assert(ph->next==NULL && ph->prev==NULL);
69     }
70     
71     ph->after=NULL;
72     ph->next=NULL;
73     ph->prev=NULL;
74 }
75
76
77 /*}}}*/
78
79
80 /*{{{ Init/deinit */
81
82
83 static void mplex_watch_handler(Watch *watch, Obj *mplex)
84 {
85     WMPlexPHolder *ph=FIELD_TO_STRUCT(WMPlexPHolder, mplex_watch, watch);
86     mplexpholder_do_unlink(ph, (WMPlex*)mplex);
87     pholder_redirect(&(ph->ph), (WRegion*)mplex);
88 }
89
90
91 static WMPlexAttachParams dummy_param={0, 0, {0, 0, 0, 0}, 0, 0};
92
93
94 bool mplexpholder_init(WMPlexPHolder *ph, WMPlex *mplex, WStacking *st,
95                        WMPlexAttachParams *param)
96 {
97     pholder_init(&(ph->ph));
98
99     watch_init(&(ph->mplex_watch));
100     ph->after=NULL;
101     ph->next=NULL;
102     ph->prev=NULL;
103     ph->param.flags=0;
104     
105     if(!watch_setup(&(ph->mplex_watch), (Obj*)mplex, mplex_watch_handler)){
106         pholder_deinit(&(ph->ph));
107         return FALSE;
108     }
109
110     if(param==NULL)
111         param=&dummy_param;
112     
113     if(st!=NULL){
114         if(st->lnode!=NULL)
115             mplexpholder_do_link(ph, mplex, 
116                                  LIST_LAST(st->lnode->phs, next, prev), 
117                                  st->lnode);
118         else
119             ph->param.flags|=MPLEX_ATTACH_UNNUMBERED;
120         
121         ph->param.flags|=(MPLEX_ATTACH_SIZEPOLICY|
122                           MPLEX_ATTACH_GEOM|
123                           MPLEX_ATTACH_LEVEL|
124                           (st->hidden ? MPLEX_ATTACH_HIDDEN : 0));
125         ph->param.szplcy=st->szplcy;
126         ph->param.geom=REGION_GEOM(st->reg);
127         ph->param.level=st->level;
128     }else{
129         ph->param=*param;
130         
131         if(!(param->flags&MPLEX_ATTACH_UNNUMBERED)){
132             int index=(param->flags&MPLEX_ATTACH_INDEX
133                        ? param->index
134                        : mplex_default_index(mplex));
135             WLListNode *or_after=llist_index_to_after(mplex->mx_list, 
136                                                       mplex->mx_current, 
137                                                       index);
138             WMPlexPHolder *after=(index==LLIST_INDEX_LAST
139                                   ? (or_after!=NULL
140                                      ? LIST_LAST(or_after->phs, next, prev) 
141                                      : LIST_LAST(mplex->mx_phs, next, prev))
142                                   : NULL);
143
144             mplexpholder_do_link(ph, mplex, after, or_after);
145         }
146     }
147     
148     return TRUE;
149 }
150  
151
152 WMPlexPHolder *create_mplexpholder(WMPlex *mplex,
153                                    WStacking *st,
154                                    WMPlexAttachParams *param)
155 {
156     CREATEOBJ_IMPL(WMPlexPHolder, mplexpholder, (p, mplex, st, param));
157 }
158
159
160 void mplexpholder_deinit(WMPlexPHolder *ph)
161 {
162     mplexpholder_do_unlink(ph, (WMPlex*)ph->mplex_watch.obj);
163     watch_reset(&(ph->mplex_watch));
164     pholder_deinit(&(ph->ph));
165 }
166
167
168 /*}}}*/
169
170
171 /*{{{ Move, attach, layer */
172
173
174 WRegion *mplexpholder_do_attach(WMPlexPHolder *ph, int flags,
175                                 WRegionAttachData *data)
176 {
177     WMPlex *mplex=(WMPlex*)ph->mplex_watch.obj;
178     WRegion *reg=NULL;
179     
180     if(mplex==NULL)
181         return FALSE;
182     
183     if(flags&PHOLDER_ATTACH_SWITCHTO)
184         ph->param.flags|=MPLEX_ATTACH_SWITCHTO;
185     else
186         ph->param.flags&=~MPLEX_ATTACH_SWITCHTO;
187     
188     return mplex_do_attach_pholder(mplex, ph, data);
189 }
190
191
192 bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex, 
193                        WMPlexPHolder *after,
194                        WLListNode *or_after)
195
196 {
197     mplexpholder_do_unlink(ph, (WMPlex*)ph->mplex_watch.obj);
198
199     watch_reset(&(ph->mplex_watch));
200     
201     if(mplex==NULL)
202         return TRUE;
203     
204     if(!watch_setup(&(ph->mplex_watch), (Obj*)mplex, mplex_watch_handler))
205         return FALSE;
206
207     mplexpholder_do_link(ph, mplex, after, or_after);
208     
209     return TRUE;
210 }
211
212
213 bool mplexpholder_do_goto(WMPlexPHolder *ph)
214 {
215     WMPlex *mplex=(WMPlex*)ph->mplex_watch.obj;
216     
217     if(mplex!=NULL)
218         return region_goto((WRegion*)mplex);
219     
220     return FALSE;
221 }
222
223
224 WRegion *mplexpholder_do_target(WMPlexPHolder *ph)
225 {
226     return (WRegion*)ph->mplex_watch.obj;
227 }
228
229
230 /*}}}*/
231
232
233 /*{{{ WMPlex routines */
234
235
236 void mplex_move_phs(WMPlex *mplex, WLListNode *node,
237                     WMPlexPHolder *after,
238                     WLListNode *or_after)
239 {
240     WMPlexPHolder *ph;
241     
242     assert(node!=or_after);
243     
244     while(node->phs!=NULL){
245         ph=node->phs;
246         
247         mplexpholder_do_unlink(ph, mplex);
248         mplexpholder_do_link(ph, mplex, after, or_after);
249         
250         after=ph;
251     }
252 }
253
254 void mplex_move_phs_before(WMPlex *mplex, WLListNode *node)
255 {
256     WMPlexPHolder *after=NULL;
257     WLListNode *or_after;
258     
259     or_after=LIST_PREV(mplex->mx_list, node, next, prev);
260                          
261     after=(or_after!=NULL
262            ? LIST_LAST(or_after->phs, next, prev)
263            : LIST_LAST(mplex->mx_phs, next, prev));
264         
265     mplex_move_phs(mplex, node, after, or_after);
266 }
267
268
269 WMPlexPHolder *mplex_managed_get_pholder(WMPlex *mplex, WRegion *mgd)
270 {
271     WStacking *st=mplex_find_stacking(mplex, mgd);
272     
273     if(st==NULL)
274         return NULL;
275     else
276         return create_mplexpholder(mplex, st, NULL);
277 }
278
279
280 WMPlexPHolder *mplex_get_rescue_pholder_for(WMPlex *mplex, WRegion *mgd)
281 {
282     WStacking *st=mplex_find_stacking(mplex, mgd);
283     
284     return create_mplexpholder(mplex, st, NULL);
285 }
286
287
288 /*}}}*/
289
290
291 /*{{{ Class information */
292
293
294 static DynFunTab mplexpholder_dynfuntab[]={
295     {(DynFun*)pholder_do_attach, 
296      (DynFun*)mplexpholder_do_attach},
297     
298     {(DynFun*)pholder_do_goto, 
299      (DynFun*)mplexpholder_do_goto},
300
301     {(DynFun*)pholder_do_target, 
302      (DynFun*)mplexpholder_do_target},
303
304     END_DYNFUNTAB
305 };
306
307
308 IMPLCLASS(WMPlexPHolder, WPHolder, mplexpholder_deinit, 
309           mplexpholder_dynfuntab);
310
311
312 /*}}}*/
313