Released version 3-2015061300
[notion.git] / ioncore / attach.c
blob51e4f92897548e721ac47824e7479279037d5a7a
1 /*
2 * ion/ioncore/attach.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
10 #include <limits.h>
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 #include "screen-notify.h"
25 /*{{{ Helper */
28 static WRegion *doit_new(WRegion *mgr,
29 WWindow *par, const WFitParams *fp,
30 WRegionDoAttachFn *cont, void *cont_param,
31 WRegionCreateFn *fn, void *fn_param)
33 WRegion *reg=fn(par, fp, fn_param);
35 if(reg==NULL)
36 return NULL;
38 if(!cont(mgr, reg, cont_param)){
39 destroy_obj((Obj*)reg);
40 return NULL;
43 return reg;
47 static WRegion *doit_reparent(WRegion *mgr,
48 WWindow *par, const WFitParams *fp,
49 WRegionDoAttachFn *cont, void *cont_param,
50 WRegion *reg)
52 WFitParams fp2;
53 WRegion *disposeroot;
54 WScreen *old_scr=region_screen_of(reg);
56 if(!region_ancestor_check(mgr, reg)){
57 warn(TR("Attempt to make region %s manage its ancestor %s."),
58 region_name(mgr), region_name(reg));
59 return NULL;
62 disposeroot=region_disposeroot(reg);
64 if(disposeroot==NULL){
65 /* Region may not be reparented */
66 return NULL;
69 if(fp->mode&REGION_FIT_WHATEVER){
70 /* fp->g is not final; substitute size with current to avoid
71 * useless resizing.
73 fp2.mode=fp->mode;
74 fp2.g.x=fp->g.x;
75 fp2.g.y=fp->g.y;
76 fp2.g.w=REGION_GEOM(reg).w;
77 fp2.g.h=REGION_GEOM(reg).h;
78 fp=&fp2;
81 if(!region_fitrep(reg, par, fp)){
82 warn(TR("Unable to reparent."));
83 return NULL;
86 region_detach_manager(reg);
88 if(old_scr!=NULL)
89 screen_update_notifywin(old_scr);
91 ioncore_screen_activity_notify(reg, ioncore_g.notifies.activity);
93 if(!cont(mgr, reg, cont_param)){
94 WScreen *scr=region_screen_of(reg);
96 warn(TR("Unexpected attach error: "
97 "trying to recover by attaching to screen."));
99 if(scr!=NULL){
100 /* Try to attach to screen, to have `reg` attached at least
101 * somewhere. For better recovery, we could try to get
102 * a placeholder for `reg` before we detach it, but this
103 * would add unnecessary overhead in the usual succesfull
104 * case. (This failure is supposed to be _very_ rare!)
105 * We intentionally also do not region_postdetach_dispose
106 * on recovery.
108 int flags=(region_may_control_focus(reg)
109 ? MPLEX_ATTACH_SWITCHTO
110 : 0);
111 if(mplex_attach_simple(&scr->mplex, reg, flags)!=NULL)
112 return NULL;
115 warn(TR("Failed recovery."));
117 return NULL;
120 region_postdetach_dispose(reg, disposeroot);
122 return reg;
126 typedef struct{
127 ExtlTab tab;
128 WPHolder **sm_ph_p;
129 } WLP;
131 static WRegion *wrap_load(WWindow *par, const WFitParams *fp, WLP *p)
133 return create_region_load(par, fp, p->tab, p->sm_ph_p);
137 WRegion *ioncore_newly_created=NULL;
140 static WRegion *doit_load(WRegion *mgr,
141 WWindow *par, const WFitParams *fp,
142 WRegionDoAttachFn *cont, void *cont_param,
143 ExtlTab tab, WPHolder **sm_ph)
145 WRegion *reg=NULL;
147 if(extl_table_gets_o(tab, "reg", (Obj**)&reg)){
148 if(!OBJ_IS(reg, WRegion))
149 return FALSE;
150 }/*else if(extl_table_is_bool_set(tab, "reg_use_new")){
151 reg=ioncore_newly_created;
152 if(reg==NULL)
153 return NULL;
156 if(reg!=NULL){
157 return doit_reparent(mgr, par, fp, cont, cont_param, reg);
158 }else{
159 WLP p;
160 p.tab=tab;
161 p.sm_ph_p=sm_ph;
163 return doit_new(mgr, par, fp, cont, cont_param,
164 (WRegionCreateFn*)wrap_load, &p);
169 WRegion *region_attach_load_helper(WRegion *mgr,
170 WWindow *par, const WFitParams *fp,
171 WRegionDoAttachFn *fn, void *fn_param,
172 ExtlTab tab, WPHolder **sm_ph)
174 return doit_load(mgr, par, fp, fn, fn_param, tab, sm_ph);
178 WRegion *region_attach_helper(WRegion *mgr,
179 WWindow *par, const WFitParams *fp,
180 WRegionDoAttachFn *fn, void *fn_param,
181 const WRegionAttachData *data)
183 if(data->type==REGION_ATTACH_NEW){
184 return doit_new(mgr, par, fp, fn, fn_param,
185 data->u.n.fn, data->u.n.param);
186 }else if(data->type==REGION_ATTACH_LOAD){
187 return doit_load(mgr, par, fp, fn, fn_param, data->u.tab, NULL);
188 }else if(data->type==REGION_ATTACH_REPARENT){
189 return doit_reparent(mgr, par, fp, fn, fn_param, data->u.reg);
190 }else{
191 return NULL;
196 /*}}}*/
199 /*{{{ Reparent check etc. */
202 bool region_ancestor_check(WRegion *dst, WRegion *reg)
204 WRegion *reg2;
206 /* Check that reg is not a parent or manager of mgr */
207 for(reg2=dst; reg2!=NULL; reg2=REGION_MANAGER(reg2)){
208 if(reg2==reg)
209 return FALSE;
212 for(reg2=REGION_PARENT_REG(dst); reg2!=NULL; reg2=REGION_PARENT_REG(reg2)){
213 if(reg2==reg)
214 return FALSE;
217 return TRUE;
221 void region_postdetach_dispose(WRegion *reg, WRegion *disposeroot)
223 /* disposeroot should be destroyed (as empty and useless) unless it
224 * still, in fact, is an ancestor of reg.
226 if(disposeroot!=reg && region_ancestor_check(reg, disposeroot))
227 region_dispose(disposeroot);
231 /*}}}*/