]> git.decadent.org.uk Git - ion3.git/blob - ioncore/detach.c
[svn-upgrade] Integrating new upstream version, ion3 (20070203)
[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/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
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 bool ioncore_do_detach(WRegion *reg, WGroup *grp, WFrameMode framemode)
42 {
43     WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
44     WRegionAttachData data;
45     WPHolder *ph;
46     bool newph=FALSE;
47     bool ret;
48     
49     ap.switchto_set=TRUE;
50     ap.switchto=region_may_control_focus(reg);
51     
52     data.type=REGION_ATTACH_REPARENT;
53     data.u.reg=reg;
54     
55     ph=region_unset_get_return(reg);
56     
57     if(ph==NULL){
58         ph=region_make_return_pholder(reg);
59         newph=TRUE;
60     }
61     
62     if(framemode!=FRAME_MODE_UNKNOWN){
63         WFramedParam fpa=FRAMEDPARAM_INIT;
64         
65         fpa.mode=framemode;
66         fpa.inner_geom_gravity_set=TRUE;
67         fpa.gravity=ForgetGravity;
68         
69         ap.geom_weak_set=TRUE;
70         ap.geom_weak=0;
71         
72         get_relative_geom(&fpa.inner_geom, reg, (WRegion*)grp);
73
74         ret=(region_attach_framed((WRegion*)grp, &fpa,
75                                   (WRegionAttachFn*)group_do_attach,
76                                   &ap, &data)!=NULL);
77     }else{
78         WStacking *st=ioncore_find_stacking(reg);
79         
80         if(st!=NULL){
81             ap.szplcy=st->szplcy;
82             ap.szplcy_set=TRUE;
83             
84             ap.level=maxof(st->level, STACKING_LEVEL_NORMAL);
85             ap.level_set=TRUE;
86         }
87         
88         ap.geom_set=TRUE;
89         get_relative_geom(&ap.geom, reg, (WRegion*)grp);
90         
91         ret=(group_do_attach(grp, &ap, &data)!=NULL);
92     }
93     
94     if(!ret && newph)
95         destroy_obj((Obj*)ph);
96     else if(!region_do_set_return(reg, ph))
97         destroy_obj((Obj*)ph);
98     
99     return ret;
100 }
101
102
103 static WRegion *check_mplex(WRegion *reg, WFrameMode *mode)
104 {
105     WMPlex *mplex=REGION_MANAGER_CHK(reg, WMPlex);
106     
107     if(OBJ_IS(reg, WWindow) || mplex==NULL){
108         *mode=FRAME_MODE_UNKNOWN;
109         return reg;
110     }
111         
112     *mode=FRAME_MODE_FLOATING;
113     
114     if(OBJ_IS(mplex, WFrame)
115        && frame_mode((WFrame*)mplex)==FRAME_MODE_TRANSIENT){
116         *mode=FRAME_MODE_TRANSIENT;
117     }
118     
119     return (WRegion*)mplex;
120 }
121
122
123 static WGroup *find_group(WRegion *reg)
124 {
125     WRegion *mgr=REGION_MANAGER(reg);
126     
127     while(mgr!=NULL){
128         mgr=REGION_MANAGER(mgr);
129         if(OBJ_IS(mgr, WGroup))
130             break;
131     }
132     
133     return (WGroup*)mgr;
134 }
135
136
137 bool ioncore_detach(WRegion *reg, int sp)
138 {
139     WPHolder *ph=region_get_return(reg);
140     WFrameMode mode;
141     WGroup *grp;
142     bool set, nset;
143     
144     reg=region_group_if_bottom(reg);
145     
146     grp=find_group(check_mplex(reg, &mode));
147     
148     /* reg is only considered detached if there's no higher-level group
149      * to attach to, thus causing 'toggle' to cycle.
150      */
151     set=(grp==NULL);
152     nset=libtu_do_setparam(sp, set);
153     
154     if(!XOR(nset, set))
155         return set;
156
157     if(!set){
158         return ioncore_do_detach(reg, grp, mode);
159     }else{
160         WPHolder *ph=region_get_return(reg);
161         
162         if(ph!=NULL){
163             if(!pholder_attach_mcfgoto(ph, PHOLDER_ATTACH_SWITCHTO, reg)){
164                 warn(TR("Failed to reattach."));    
165                 return TRUE;
166             }
167             region_unset_return(reg);
168         }
169         
170         return FALSE;
171     }
172 }
173
174
175 /*EXTL_DOC
176  * Detach or reattach \var{reg}, depending on whether \var{how}
177  * is 'set'/'unset'/'toggle'. (Detaching means making \var{reg} 
178  * managed by its nearest ancestor \type{WGroup}, framed if \var{reg} is
179  * not itself \type{WFrame}. Reattaching means making it managed where
180  * it used to be managed, if a return-placeholder exists.)
181  * If \var{reg} is the 'bottom' of some group, the whole group is
182  * detached. If \var{reg} is a \type{WWindow}, it is put into a 
183  * frame.
184  */
185 EXTL_EXPORT_AS(ioncore, detach)
186 bool ioncore_detach_extl(WRegion *reg, const char *how)
187 {
188     if(how==NULL)
189         how="set";
190     
191     return ioncore_detach(reg, libtu_string_to_setparam(how));
192 }
193
194