]> git.decadent.org.uk Git - ion3.git/blob - ioncore/detach.c
[svn-upgrade] Integrating new upstream version, ion3 (20071130)
[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 <string.h>
10
11 #include <libtu/objp.h>
12 #include <libtu/setparam.h>
13 #include <libtu/minmax.h>
14
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>
25
26
27 static void get_relative_geom(WRectangle *g, WRegion *reg, WRegion *mgr)
28 {
29     WWindow *rel=REGION_PARENT(mgr), *w;
30     
31     *g=REGION_GEOM(reg);
32     
33     for(w=REGION_PARENT(reg); 
34         w!=rel && (WRegion*)w!=mgr; 
35         w=REGION_PARENT(w)){
36         
37         g->x+=REGION_GEOM(w).x;
38         g->y+=REGION_GEOM(w).y;
39     }
40 }
41
42
43 static bool ioncore_do_detach(WRegion *reg, WGroup *grp, WFrameMode framemode,
44                               uint framelevel)
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         ap.level_set=TRUE;
76         ap.level=framelevel+1;
77         
78         get_relative_geom(&fpa.inner_geom, reg, (WRegion*)grp);
79
80         ret=(region_attach_framed((WRegion*)grp, &fpa,
81                                   (WRegionAttachFn*)group_do_attach,
82                                   &ap, &data)!=NULL);
83     }else{
84         WStacking *st=ioncore_find_stacking(reg);
85         
86         if(st!=NULL){
87             ap.szplcy=st->szplcy;
88             ap.szplcy_set=TRUE;
89             
90             ap.level_set=TRUE;
91             ap.level=maxof(st->level, STACKING_LEVEL_NORMAL);
92         }
93         
94         ap.geom_set=TRUE;
95         get_relative_geom(&ap.geom, reg, (WRegion*)grp);
96         
97         ret=(group_do_attach(grp, &ap, &data)!=NULL);
98     }
99     
100     if(!ret && newph)
101         destroy_obj((Obj*)ph);
102     else if(!region_do_set_return(reg, ph))
103         destroy_obj((Obj*)ph);
104     
105     return ret;
106 }
107
108
109 static WRegion *check_mplex(WRegion *reg, WFrameMode *mode)
110 {
111     WMPlex *mplex=REGION_MANAGER_CHK(reg, WMPlex);
112     
113     if(OBJ_IS(reg, WWindow) || mplex==NULL){
114         *mode=FRAME_MODE_UNKNOWN;
115         return reg;
116     }
117         
118     *mode=FRAME_MODE_FLOATING;
119     
120     if(OBJ_IS(mplex, WFrame)){
121         WFrameMode mode2=frame_mode((WFrame*)mplex);
122         if(framemode_unalt(mode2)==FRAME_MODE_TRANSIENT)
123             *mode=mode2;
124     }
125     
126     return (WRegion*)mplex;
127 }
128
129
130 static WGroup *find_group(WRegion *reg, uint *level)
131 {
132     WRegion *mgr=REGION_MANAGER(reg);
133     
134     while(mgr!=NULL){
135         reg=mgr;
136         mgr=REGION_MANAGER(mgr);
137         if(OBJ_IS(mgr, WGroup)){
138             WStacking *st=ioncore_find_stacking((WRegion*)reg);
139             if(st!=NULL)
140                 *level=st->level;
141             break;
142         }
143     }
144     
145     return (WGroup*)mgr;
146 }
147
148
149 bool ioncore_detach(WRegion *reg, int sp)
150 {
151     WFrameMode mode;
152     WGroup *grp;
153     bool set, nset;
154     uint level=STACKING_LEVEL_NORMAL;
155     
156     reg=region_groupleader_of(reg);
157     
158     grp=find_group(check_mplex(reg, &mode), &level);
159     
160     /* reg is only considered detached if there's no higher-level group
161      * to attach to, thus causing 'toggle' to cycle.
162      */
163     set=(grp==NULL);
164     nset=libtu_do_setparam(sp, set);
165     
166     if(!XOR(nset, set))
167         return set;
168
169     if(!set){
170         return ioncore_do_detach(reg, grp, mode, level);
171     }else{
172         WPHolder *ph=region_get_return(reg);
173         
174         if(ph!=NULL){
175             if(!pholder_attach_mcfgoto(ph, PHOLDER_ATTACH_SWITCHTO, reg)){
176                 warn(TR("Failed to reattach."));    
177                 return TRUE;
178             }
179             region_unset_return(reg);
180         }
181         
182         return FALSE;
183     }
184 }
185
186
187 /*EXTL_DOC
188  * Detach or reattach \var{reg} or any group it is the leader of
189  * (see \fnref{WRegion.groupleader_of}), depending on whether \var{how} 
190  * is \codestr{set}, \codestr{unset} or \codestr{toggle}. If this
191  * region is not a window, it is put into a frame.
192  *
193  * Detaching a region means having it managed by its nearest ancestor
194  * \type{WGroup}. Reattaching means having it managed where it used 
195  * to be managed, if a ``return placeholder'' exists.
196  *
197  * Additionally, setting \var{how} to \codestr{forget}, can be used to
198  * clear this return placeholder of the group leader of \var{reg}.
199  */
200 EXTL_EXPORT_AS(ioncore, detach)
201 bool ioncore_detach_extl(WRegion *reg, const char *how)
202 {
203     if(how==NULL)
204         how="set";
205     
206     if(strcmp(how, "forget")==0){
207         region_unset_return(region_groupleader_of(reg));
208         return FALSE;
209     }
210     
211     return ioncore_detach(reg, libtu_string_to_setparam(how));
212 }
213
214
215 void do_unsqueeze(WRegion *reg)
216 {
217     WSizeHints h;
218     WRegion *mgr=REGION_MANAGER(reg);
219     
220     if(OBJ_IS(reg, WScreen))
221         return;
222     
223     region_size_hints(reg, &h);
224
225     if(!h.min_set)
226         return;
227         
228     if(h.min_width<=REGION_GEOM(reg).w && 
229        h.min_height<=REGION_GEOM(reg).h){
230         return;
231     }
232     
233     ioncore_detach(reg, SETPARAM_SET);
234         
235     if(REGION_MANAGER(reg)==mgr)
236         return;
237     
238     do_unsqueeze(reg);
239 }
240
241
242 /*EXTL_DOC
243  * Try to detach \var{reg} if it fits poorly in its 
244  * current location. This function does not do anything,
245  * unless \var{override} is set or the \var{unsqueeze} option
246  * of \fnref{ioncore.set} is set.
247  */
248 EXTL_EXPORT
249 void ioncore_unsqueeze(WRegion *reg, bool override)
250 {
251     if(ioncore_g.unsqueeze_enabled || override)
252         do_unsqueeze(region_groupleader_of(reg));
253 }
254
255