]> git.decadent.org.uk Git - ion3.git/blob - ioncore/detach.c
8493b9afbca73dc82922b053aafef49d8d8ad9d6
[ion3.git] / ioncore / detach.c
1 /*
2  * ion/ioncore/detach.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 <libtu/objp.h>
13 #include <libtu/setparam.h>
14 #include <libtu/minmax.h>
15
16 #include <ioncore/common.h>
17 #include <ioncore/global.h>
18 #include <ioncore/mplex.h>
19 #include <ioncore/focus.h>
20 #include <ioncore/group.h>
21 #include <ioncore/group-ws.h>
22 #include <ioncore/framedpholder.h>
23 #include <ioncore/return.h>
24 #include <ioncore/sizehint.h>
25 #include <ioncore/resize.h>
26
27
28 static void get_relative_geom(WRectangle *g, WRegion *reg, WRegion *mgr)
29 {
30     WWindow *rel=REGION_PARENT(mgr), *w;
31     
32     *g=REGION_GEOM(reg);
33     
34     for(w=REGION_PARENT(reg); 
35         w!=rel && (WRegion*)w!=mgr; 
36         w=REGION_PARENT(w)){
37         
38         g->x+=REGION_GEOM(w).x;
39         g->y+=REGION_GEOM(w).y;
40     }
41 }
42
43
44 bool ioncore_do_detach(WRegion *reg, WGroup *grp, WFrameMode framemode)
45 {
46     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
47     WRegionAttachData data;
48     WPHolder *ph;
49     bool newph=FALSE;
50     bool ret;
51     
52     ap.switchto_set=TRUE;
53     ap.switchto=region_may_control_focus(reg);
54     
55     data.type=REGION_ATTACH_REPARENT;
56     data.u.reg=reg;
57     
58     ph=region_unset_get_return(reg);
59     
60     if(ph==NULL){
61         ph=region_make_return_pholder(reg);
62         newph=TRUE;
63     }
64     
65     if(framemode!=FRAME_MODE_UNKNOWN){
66         WFramedParam fpa=FRAMEDPARAM_INIT;
67         
68         fpa.mode=framemode;
69         fpa.inner_geom_gravity_set=TRUE;
70         fpa.gravity=ForgetGravity;
71         
72         ap.geom_weak_set=TRUE;
73         ap.geom_weak=0;
74         
75         get_relative_geom(&fpa.inner_geom, reg, (WRegion*)grp);
76
77         ret=(region_attach_framed((WRegion*)grp, &fpa,
78                                   (WRegionAttachFn*)group_do_attach,
79                                   &ap, &data)!=NULL);
80     }else{
81         WStacking *st=ioncore_find_stacking(reg);
82         
83         if(st!=NULL){
84             ap.szplcy=st->szplcy;
85             ap.szplcy_set=TRUE;
86             
87             ap.level=maxof(st->level, STACKING_LEVEL_NORMAL);
88             ap.level_set=TRUE;
89         }
90         
91         ap.geom_set=TRUE;
92         get_relative_geom(&ap.geom, reg, (WRegion*)grp);
93         
94         ret=(group_do_attach(grp, &ap, &data)!=NULL);
95     }
96     
97     if(!ret && newph)
98         destroy_obj((Obj*)ph);
99     else if(!region_do_set_return(reg, ph))
100         destroy_obj((Obj*)ph);
101     
102     return ret;
103 }
104
105
106 static WRegion *check_mplex(WRegion *reg, WFrameMode *mode)
107 {
108     WMPlex *mplex=REGION_MANAGER_CHK(reg, WMPlex);
109     
110     if(OBJ_IS(reg, WWindow) || mplex==NULL){
111         *mode=FRAME_MODE_UNKNOWN;
112         return reg;
113     }
114         
115     *mode=FRAME_MODE_FLOATING;
116     
117     if(OBJ_IS(mplex, WFrame)
118        && frame_mode((WFrame*)mplex)==FRAME_MODE_TRANSIENT){
119         *mode=FRAME_MODE_TRANSIENT;
120     }
121     
122     return (WRegion*)mplex;
123 }
124
125
126 static WGroup *find_group(WRegion *reg)
127 {
128     WRegion *mgr=REGION_MANAGER(reg);
129     
130     while(mgr!=NULL){
131         mgr=REGION_MANAGER(mgr);
132         if(OBJ_IS(mgr, WGroup))
133             break;
134     }
135     
136     return (WGroup*)mgr;
137 }
138
139
140 bool ioncore_detach(WRegion *reg, int sp)
141 {
142     WPHolder *ph=region_get_return(reg);
143     WFrameMode mode;
144     WGroup *grp;
145     bool set, nset;
146     
147     reg=region_groupleader_of(reg);
148     
149     grp=find_group(check_mplex(reg, &mode));
150     
151     /* reg is only considered detached if there's no higher-level group
152      * to attach to, thus causing 'toggle' to cycle.
153      */
154     set=(grp==NULL);
155     nset=libtu_do_setparam(sp, set);
156     
157     if(!XOR(nset, set))
158         return set;
159
160     if(!set){
161         return ioncore_do_detach(reg, grp, mode);
162     }else{
163         WPHolder *ph=region_get_return(reg);
164         
165         if(ph!=NULL){
166             if(!pholder_attach_mcfgoto(ph, PHOLDER_ATTACH_SWITCHTO, reg)){
167                 warn(TR("Failed to reattach."));    
168                 return TRUE;
169             }
170             region_unset_return(reg);
171         }
172         
173         return FALSE;
174     }
175 }
176
177
178 /*EXTL_DOC
179  * Detach or reattach \var{reg}, depending on whether \var{how}
180  * is 'set'/'unset'/'toggle'. (Detaching means making \var{reg} 
181  * managed by its nearest ancestor \type{WGroup}, framed if \var{reg} is
182  * not itself \type{WFrame}. Reattaching means making it managed where
183  * it used to be managed, if a return-placeholder exists.)
184  * If \var{reg} is the 'bottom' of some group, the whole group is
185  * detached. If \var{reg} is a \type{WWindow}, it is put into a 
186  * frame.
187  */
188 EXTL_EXPORT_AS(ioncore, detach)
189 bool ioncore_detach_extl(WRegion *reg, const char *how)
190 {
191     if(how==NULL)
192         how="set";
193     
194     return ioncore_detach(reg, libtu_string_to_setparam(how));
195 }
196
197
198 void do_unsqueeze(WRegion *reg)
199 {
200     WSizeHints hints;
201     
202     if(REGION_MANAGER_CHK(reg, WScreen)!=NULL)
203         return;
204     
205     region_size_hints(reg, &hints);
206
207     if(!hints.min_set)
208         return;
209         
210     if(hints.min_width<=REGION_GEOM(reg).w &&
211        hints.min_height<=REGION_GEOM(reg).h){
212         return;
213     }
214     
215     if(!ioncore_detach(reg, SETPARAM_SET))
216         return;
217         
218     do_unsqueeze(reg);
219 }
220
221
222 /*EXTL_DOC
223  * Try to detach \var{reg} if it fits poorly in its 
224  * current location. This function does not do anything,
225  * unless \var{override} is set or the \var{unsqueeze} option
226  * of \fnref{ioncore.set} is set.
227  */
228 EXTL_EXPORT
229 void ioncore_unsqueeze(WRegion *reg, bool override)
230 {
231     if(ioncore_g.unsqueeze_enabled || override)
232         do_unsqueeze(region_groupleader_of(reg));
233 }
234
235