]> git.decadent.org.uk Git - ion3.git/blob - ioncore/framedpholder.c
Imported Upstream version 20090110
[ion3.git] / ioncore / framedpholder.c
1 /*
2  * ion/ioncore/framedpholder.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/minmax.h>
12
13 #include "frame.h"
14 #include "framedpholder.h"
15 #include "sizehint.h"
16 #include "resize.h"
17
18
19 /*{{{ Init/deinit */
20
21
22 bool framedpholder_init(WFramedPHolder *ph, WPHolder *cont,
23                         const WFramedParam *param)
24 {
25     assert(cont!=NULL);
26     
27     pholder_init(&(ph->ph));
28
29     ph->cont=cont;
30     ph->param=*param;
31     
32     watch_init(&ph->frame_watch);
33     
34     return TRUE;
35 }
36  
37
38 WFramedPHolder *create_framedpholder(WPHolder *cont,
39                                      const WFramedParam *param)
40 {
41     CREATEOBJ_IMPL(WFramedPHolder, framedpholder, (p, cont, param));
42 }
43
44
45 void framedpholder_deinit(WFramedPHolder *ph)
46 {
47     if(ph->cont!=NULL){
48         destroy_obj((Obj*)ph->cont);
49         ph->cont=NULL;
50     }
51     
52     pholder_deinit(&(ph->ph));
53     watch_reset(&ph->frame_watch);
54 }
55
56
57 /*}}}*/
58
59
60 /*{{{ Attach */
61
62
63 typedef struct{
64     WRegionAttachData *data;
65     WFramedParam *param;
66     WRegion *reg_ret;
67 } AP;
68
69
70 void frame_adjust_to_initial(WFrame *frame, const WFitParams *fp, 
71                              const WFramedParam *param, WRegion *reg)
72 {
73     WRectangle rqg, mg;
74     WSizeHints szh;
75     int iw, ih;
76  
77     if(!(fp->mode&(REGION_FIT_BOUNDS|REGION_FIT_WHATEVER)))
78         return;
79
80     mplex_managed_geom((WMPlex*)frame, &mg);
81     
82     /* Adjust geometry */
83     if(!param->inner_geom_gravity_set){
84         iw=REGION_GEOM(reg).w;
85         ih=REGION_GEOM(reg).h;
86         rqg.x=REGION_GEOM(frame).x;
87         rqg.y=REGION_GEOM(frame).y;
88     }else{
89         int bl=mg.x;
90         int br=REGION_GEOM(frame).w-(mg.x+mg.w);
91         int bt=mg.y;
92         int bb=REGION_GEOM(frame).h-(mg.y+mg.h);
93         
94         iw=param->inner_geom.w;
95         ih=param->inner_geom.h;
96         
97         rqg.x=(/*fp->g.x+*/param->inner_geom.x+
98                xgravity_deltax(param->gravity, bl, br));
99         rqg.y=(/*fp->g.y+*/param->inner_geom.y+
100                xgravity_deltay(param->gravity, bt, bb));
101     }
102     
103     /* Some apps seem to request geometries inconsistent with their size hints,
104      * so correct for that here.
105      * Because WGroup(CW) sets no_constrain on the size hints, we have
106      * to set override_no_constrain to force the frame to have the size
107      * of the 'bottom' of the group.
108      */
109     region_size_hints(reg, &szh);
110     sizehints_correct(&szh, &iw, &ih, TRUE, TRUE);
111     rqg.w=maxof(1, iw+(REGION_GEOM(frame).w-mg.w));
112     rqg.h=maxof(1, ih+(REGION_GEOM(frame).h-mg.h));
113     
114     if(!(fp->mode&REGION_FIT_WHATEVER))
115         rectangle_constrain(&rqg, &fp->g);
116     
117     region_fit((WRegion*)frame, &rqg, REGION_FIT_EXACT);
118 }
119
120
121 WRegion *framed_handler(WWindow *par, 
122                         const WFitParams *fp, 
123                         void *ap_)
124 {
125     AP *ap=(AP*)ap_;
126     WMPlexAttachParams mp=MPLEXATTACHPARAMS_INIT;
127     WFramedParam *param=ap->param;
128     WFrame *frame;
129     WRegion *reg;
130     
131     frame=create_frame(par, fp, param->mode);
132     
133     if(frame==NULL)
134         return NULL;
135     
136     if(fp->mode&(REGION_FIT_BOUNDS|REGION_FIT_WHATEVER))
137         mp.flags|=MPLEX_ATTACH_WHATEVER;
138
139     reg=mplex_do_attach(&frame->mplex, &mp, ap->data);
140     
141     ap->reg_ret=reg;
142     
143     if(reg==NULL){
144         destroy_obj((Obj*)frame);
145         return NULL;
146     }
147     
148     frame_adjust_to_initial(frame, fp, param, reg);
149     
150     return (WRegion*)frame;
151 }
152
153
154 WRegion *region_attach_framed(WRegion *reg, WFramedParam *param,
155                               WRegionAttachFn *fn, void *fn_param,
156                               WRegionAttachData *data)
157 {
158     WRegionAttachData data2;
159     AP ap;
160
161     data2.type=REGION_ATTACH_NEW;
162     data2.u.n.fn=framed_handler;
163     data2.u.n.param=&ap;
164     
165     ap.data=data;
166     ap.param=param;
167     ap.reg_ret=NULL;
168     
169     return fn(reg, fn_param, &data2);
170 }
171
172
173 WRegion *framedpholder_do_attach(WFramedPHolder *ph, int flags,
174                                  WRegionAttachData *data)
175 {
176     WRegionAttachData data2;
177     WFrame *frame;
178     AP ap;
179     
180     frame=(WFrame*)ph->frame_watch.obj;
181     
182     if(frame!=NULL){
183         WMPlexAttachParams mp=MPLEXATTACHPARAMS_INIT;
184         return mplex_do_attach(&frame->mplex, &mp, data);
185     }
186     
187     if(ph->cont==NULL)
188         return FALSE;
189
190     data2.type=REGION_ATTACH_NEW;
191     data2.u.n.fn=framed_handler;
192     data2.u.n.param=&ap;
193     
194     ap.data=data;
195     ap.param=&ph->param;
196     ap.reg_ret=NULL;
197         
198     frame=(WFrame*)pholder_do_attach(ph->cont, flags, &data2);
199     
200     if(frame!=NULL){
201         assert(OBJ_IS(frame, WFrame));
202         watch_setup(&ph->frame_watch, (Obj*)frame, NULL);
203     }
204     
205     return (flags&PHOLDER_ATTACH_RETURN_CREATEROOT
206             ? (WRegion*)frame
207             : ap.reg_ret);
208 }
209
210
211 /*}}}*/
212
213
214 /*{{{ Other dynfuns */
215
216
217 bool framedpholder_do_goto(WFramedPHolder *ph)
218 {
219     WRegion *frame=(WRegion*)ph->frame_watch.obj;
220     
221     if(frame!=NULL)
222         return region_goto((WRegion*)frame);
223     else if(ph->cont!=NULL)
224         return pholder_goto(ph->cont);
225     else
226         return FALSE;
227 }
228
229
230 WRegion *framedpholder_do_target(WFramedPHolder *ph)
231 {
232     WRegion *frame=(WRegion*)ph->frame_watch.obj;
233     
234     return (frame!=NULL
235             ? frame
236             : (ph->cont!=NULL
237                ? pholder_target(ph->cont)
238                : NULL));
239 }
240
241
242 bool framedpholder_stale(WFramedPHolder *ph)
243 {
244     WRegion *frame=(WRegion*)ph->frame_watch.obj;
245     
246     return (frame==NULL && (ph->cont==NULL || pholder_stale(ph->cont)));
247 }
248
249
250 /*}}}*/
251
252
253 /*{{{ Class information */
254
255
256 static DynFunTab framedpholder_dynfuntab[]={
257     {(DynFun*)pholder_do_attach, 
258      (DynFun*)framedpholder_do_attach},
259
260     {(DynFun*)pholder_do_goto, 
261      (DynFun*)framedpholder_do_goto},
262
263     {(DynFun*)pholder_do_target, 
264      (DynFun*)framedpholder_do_target},
265      
266     {(DynFun*)pholder_stale, 
267      (DynFun*)framedpholder_stale},
268     
269     END_DYNFUNTAB
270 };
271
272 IMPLCLASS(WFramedPHolder, WPHolder, framedpholder_deinit, 
273           framedpholder_dynfuntab);
274
275
276 /*}}}*/
277