ion->notion
[notion/jeffpc.git] / ioncore / detach.c
blobe175759e7d231d0d1681da036f5280b7746ac594
1 /*
2 * ion/ioncore/detach.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <libtu/objp.h>
12 #include <libtu/setparam.h>
13 #include <libtu/minmax.h>
15 #include <ioncore/common.h>
16 #include <ioncore/global.h>
17 #include <ioncore/mplex.h>
18 #include <ioncore/focus.h>
19 #include <ioncore/group.h>
20 #include <ioncore/group-ws.h>
21 #include <ioncore/framedpholder.h>
22 #include <ioncore/return.h>
23 #include <ioncore/sizehint.h>
24 #include <ioncore/resize.h>
27 static void get_relative_geom(WRectangle *g, WRegion *reg, WRegion *mgr)
29 WWindow *rel=REGION_PARENT(mgr), *w;
31 *g=REGION_GEOM(reg);
33 for(w=REGION_PARENT(reg);
34 w!=rel && (WRegion*)w!=mgr;
35 w=REGION_PARENT(w)){
37 g->x+=REGION_GEOM(w).x;
38 g->y+=REGION_GEOM(w).y;
43 static bool ioncore_do_detach(WRegion *reg, WGroup *grp, WFrameMode framemode,
44 uint framelevel)
46 WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
47 WRegionAttachData data;
48 WPHolder *ph;
49 bool newph=FALSE;
50 bool ret;
52 ap.switchto_set=TRUE;
53 ap.switchto=region_may_control_focus(reg);
55 data.type=REGION_ATTACH_REPARENT;
56 data.u.reg=reg;
58 ph=region_unset_get_return(reg);
60 if(ph==NULL){
61 ph=region_make_return_pholder(reg);
62 newph=TRUE;
65 if(framemode!=FRAME_MODE_UNKNOWN){
66 /* TODO: remove/obsolete this special case */
67 WFramedParam fpa=FRAMEDPARAM_INIT;
69 fpa.mode=framemode;
70 fpa.inner_geom_gravity_set=TRUE;
71 fpa.gravity=ForgetGravity;
73 ap.geom_weak_set=TRUE;
74 ap.geom_weak=0;
76 ap.level_set=TRUE;
77 ap.level=framelevel+1;
79 get_relative_geom(&fpa.inner_geom, reg, (WRegion*)grp);
81 ret=(region_attach_framed((WRegion*)grp, &fpa,
82 (WRegionAttachFn*)group_do_attach,
83 &ap, &data)!=NULL);
84 }else{
85 WStacking *st=ioncore_find_stacking(reg);
87 ap.level_set=TRUE;
88 ap.level=framelevel+1;
90 if(st!=NULL){
91 ap.szplcy=st->szplcy;
92 ap.szplcy_set=TRUE;
94 /* Hack for modal detached queries, while transients become
95 * non-modal detached.
97 if(st->level>STACKING_LEVEL_MODAL1)
98 ap.level=st->level;
101 ap.geom_set=TRUE;
102 get_relative_geom(&ap.geom, reg, (WRegion*)grp);
104 ret=(group_do_attach(grp, &ap, &data)!=NULL);
107 if(!ret && newph)
108 destroy_obj((Obj*)ph);
109 else if(!region_do_set_return(reg, ph))
110 destroy_obj((Obj*)ph);
112 return ret;
116 static WRegion *check_mplex(WRegion *reg, WFrameMode *mode)
118 WMPlex *mplex=REGION_MANAGER_CHK(reg, WMPlex);
120 if(OBJ_IS(reg, WWindow) || mplex==NULL){
121 *mode=FRAME_MODE_UNKNOWN;
122 return reg;
125 *mode=FRAME_MODE_FLOATING;
127 if(OBJ_IS(mplex, WFrame)){
128 WFrameMode mode2=frame_mode((WFrame*)mplex);
129 if(framemode_unalt(mode2)==FRAME_MODE_TRANSIENT)
130 *mode=mode2;
133 return (WRegion*)mplex;
137 static WGroup *find_group(WRegion *reg, uint *level)
139 WRegion *mgr=REGION_MANAGER(reg);
141 while(mgr!=NULL){
142 reg=mgr;
143 mgr=REGION_MANAGER(mgr);
144 if(OBJ_IS(mgr, WGroup)){
145 WStacking *st=ioncore_find_stacking((WRegion*)reg);
146 if(st!=NULL)
147 *level=st->level;
148 break;
152 return (WGroup*)mgr;
156 bool ioncore_detach(WRegion *reg, int sp)
158 WFrameMode mode;
159 WGroup *grp;
160 bool set, nset;
161 uint level=STACKING_LEVEL_NORMAL;
163 reg=region_groupleader_of(reg);
165 grp=find_group(check_mplex(reg, &mode), &level);
167 /* reg is only considered detached if there's no higher-level group
168 * to attach to, thus causing 'toggle' to cycle.
170 set=(grp==NULL);
171 nset=libtu_do_setparam(sp, set);
173 if(!XOR(nset, set))
174 return set;
176 if(!set){
177 return ioncore_do_detach(reg, grp, mode, level);
178 }else{
179 WPHolder *ph=region_get_return(reg);
181 if(ph!=NULL){
182 if(!pholder_attach_mcfgoto(ph, PHOLDER_ATTACH_SWITCHTO, reg)){
183 warn(TR("Failed to reattach."));
184 return TRUE;
186 region_unset_return(reg);
189 return FALSE;
194 /*EXTL_DOC
195 * Detach or reattach \var{reg} or any group it is the leader of
196 * (see \fnref{WRegion.groupleader_of}), depending on whether \var{how}
197 * is \codestr{set}, \codestr{unset} or \codestr{toggle}. If this
198 * region is not a window, it is put into a frame.
200 * Detaching a region means having it managed by its nearest ancestor
201 * \type{WGroup}. Reattaching means having it managed where it used
202 * to be managed, if a ``return placeholder'' exists.
204 * Additionally, setting \var{how} to \codestr{forget}, can be used to
205 * clear this return placeholder of the group leader of \var{reg}.
207 EXTL_EXPORT_AS(ioncore, detach)
208 bool ioncore_detach_extl(WRegion *reg, const char *how)
210 if(how==NULL)
211 how="set";
213 if(strcmp(how, "forget")==0){
214 region_unset_return(region_groupleader_of(reg));
215 return FALSE;
218 return ioncore_detach(reg, libtu_string_to_setparam(how));
222 void do_unsqueeze(WRegion *reg)
224 WSizeHints h;
226 if(OBJ_IS(reg, WScreen))
227 return;
229 region_size_hints(reg, &h);
231 if(!h.min_set)
232 return;
234 if(h.min_width<=REGION_GEOM(reg).w &&
235 h.min_height<=REGION_GEOM(reg).h){
236 return;
239 ioncore_detach(reg, SETPARAM_SET);
243 /*EXTL_DOC
244 * Try to detach \var{reg} if it fits poorly in its
245 * current location. This function does not do anything,
246 * unless \var{override} is set or the \var{unsqueeze} option
247 * of \fnref{ioncore.set} is set.
249 EXTL_EXPORT
250 void ioncore_unsqueeze(WRegion *reg, bool override)
252 if(ioncore_g.unsqueeze_enabled || override)
253 do_unsqueeze(reg);