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