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