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