]> git.decadent.org.uk Git - ion3.git/blob - ioncore/attach.c
Merge commit '20080103' into HEAD
[ion3.git] / ioncore / attach.c
1 /*
2  * ion/ioncore/attach.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2008. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10 #include <limits.h>
11
12 #include "common.h"
13 #include "global.h"
14 #include "region.h"
15 #include "attach.h"
16 #include "clientwin.h"
17 #include "saveload.h"
18 #include "manage.h"
19 #include "extlconv.h"
20 #include "names.h"
21 #include "focus.h"
22
23
24 /*{{{ Helper */
25
26
27 static WRegion *doit_new(WRegion *mgr,
28                          WWindow *par, const WFitParams *fp,
29                          WRegionDoAttachFn *cont, void *cont_param,
30                          WRegionCreateFn *fn, void *fn_param)
31 {
32     WRegion *reg=fn(par, fp, fn_param);
33     
34     if(reg==NULL)
35         return NULL;
36         
37     if(!cont(mgr, reg, cont_param)){
38         destroy_obj((Obj*)reg);
39         return NULL;
40     }
41     
42     return reg;
43 }
44
45
46 static WRegion *doit_reparent(WRegion *mgr,
47                               WWindow *par, const WFitParams *fp,
48                               WRegionDoAttachFn *cont, void *cont_param,
49                               WRegion *reg)
50 {
51     WFitParams fp2;
52     WRegion *disposeroot;
53     
54     if(!region_ancestor_check(mgr, reg)){
55         warn(TR("Attempt to make region %s manage its ancestor %s."),
56              region_name(mgr), region_name(reg));
57         return NULL;
58     }
59     
60     disposeroot=region_disposeroot(reg);
61     
62     if(disposeroot==NULL){
63         /* Region may not be reparented */
64         return NULL;
65     }
66     
67     if(fp->mode&REGION_FIT_WHATEVER){
68         /* fp->g is not final; substitute size with current to avoid
69          * useless resizing. 
70          */
71         fp2.mode=fp->mode;
72         fp2.g.x=fp->g.x;
73         fp2.g.y=fp->g.y;
74         fp2.g.w=REGION_GEOM(reg).w;
75         fp2.g.h=REGION_GEOM(reg).h;
76         fp=&fp2;
77     }
78     
79     if(!region_fitrep(reg, par, fp)){
80         warn(TR("Unable to reparent."));
81         return NULL;
82     }
83     
84     region_detach_manager(reg);
85     
86     if(!cont(mgr, reg, cont_param)){
87         WScreen *scr=region_screen_of(reg);
88         
89         warn(TR("Unexpected attach error: "
90                 "trying to recover by attaching to screen."));
91         
92         if(scr!=NULL){
93             /* Try to attach to screen, to have `reg` attached at least
94              * somewhere. For better recovery, we could try to get
95              * a placeholder for `reg` before we detach it, but this
96              * would add unnecessary overhead in the usual succesfull
97              * case. (This failure is supposed to be _very_ rare!)
98              * We intentionally also do not region_postdetach_dispose 
99              * on recovery.
100              */
101             int flags=(region_may_control_focus(reg) 
102                        ? MPLEX_ATTACH_SWITCHTO 
103                        : 0);
104             if(mplex_attach_simple(&scr->mplex, reg, flags)!=NULL)
105                 return NULL;
106         }
107         
108         warn(TR("Failed recovery."));
109         
110         return NULL;
111     }
112     
113     region_postdetach_dispose(reg, disposeroot);
114     
115     return reg;
116 }
117
118
119 typedef struct{
120     ExtlTab tab;
121     WPHolder **sm_ph_p;
122 } WLP;
123
124 static WRegion *wrap_load(WWindow *par, const WFitParams *fp, WLP *p)
125 {
126     return create_region_load(par, fp, p->tab, p->sm_ph_p);
127 }
128
129
130 WRegion *ioncore_newly_created=NULL;
131
132
133 static WRegion *doit_load(WRegion *mgr,
134                           WWindow *par, const WFitParams *fp,
135                           WRegionDoAttachFn *cont, void *cont_param,
136                           const WRegionAttachData *data)
137 {
138     WRegion *reg=NULL;
139     
140     if(extl_table_gets_o(data->u.tab, "reg", (Obj**)&reg)){
141         if(!OBJ_IS(reg, WRegion))
142             return FALSE;
143     }/*else if(extl_table_is_bool_set(tab, "reg_use_new")){
144         reg=ioncore_newly_created;
145         if(reg==NULL)
146             return NULL;
147     }*/
148     
149     if(reg!=NULL){
150         return doit_reparent(mgr, par, fp, cont, cont_param, reg);
151     }else{
152         WLP p;
153         p.tab=data->u.tab;
154         p.sm_ph_p=NULL;
155         
156         return doit_new(mgr, par, fp, cont, cont_param,
157                         (WRegionCreateFn*)wrap_load, &p);
158     }
159 }
160
161
162 WRegion *region_attach_load_helper(WRegion *mgr,
163                                    WWindow *par, const WFitParams *fp,
164                                    WRegionDoAttachFn *fn, void *fn_param,
165                                    ExtlTab tab, WPHolder **sm_ph)
166 {
167     WLP p;
168     p.tab=tab;
169     p.sm_ph_p=sm_ph;
170     
171     return doit_new(mgr, par, fp, fn, fn_param,
172                     (WRegionCreateFn*)wrap_load, &p);
173 }                                   
174
175
176 WRegion *region_attach_helper(WRegion *mgr,
177                               WWindow *par, const WFitParams *fp,
178                               WRegionDoAttachFn *fn, void *fn_param,
179                               const WRegionAttachData *data)
180 {
181     if(data->type==REGION_ATTACH_NEW){
182         return doit_new(mgr, par, fp, fn, fn_param, 
183                         data->u.n.fn, data->u.n.param);
184     }else if(data->type==REGION_ATTACH_LOAD){
185         return doit_load(mgr, par, fp, fn, fn_param, data);
186     }else if(data->type==REGION_ATTACH_REPARENT){
187         return doit_reparent(mgr, par, fp, fn, fn_param, data->u.reg);
188     }else{
189         return NULL;
190     }
191 }
192
193
194 /*}}}*/
195
196
197 /*{{{ Reparent check etc. */
198
199
200 bool region_ancestor_check(WRegion *dst, WRegion *reg)
201 {
202     WRegion *reg2;
203     
204     /* Check that reg is not a parent or manager of mgr */
205     for(reg2=dst; reg2!=NULL; reg2=REGION_MANAGER(reg2)){
206         if(reg2==reg)
207             return FALSE;
208     }
209     
210     for(reg2=REGION_PARENT_REG(dst); reg2!=NULL; reg2=REGION_PARENT_REG(reg2)){
211         if(reg2==reg)
212             return FALSE;
213     }
214
215     return TRUE;
216 }
217
218
219 void region_postdetach_dispose(WRegion *reg, WRegion *disposeroot)
220 {
221     /* disposeroot should be destroyed (as empty and useless) unless it 
222      * still, in fact, is an ancestor of reg.
223      */
224     if(disposeroot!=reg && region_ancestor_check(reg, disposeroot))
225         region_dispose(disposeroot);
226 }
227
228
229 /*}}}*/
230
231