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