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