]> git.decadent.org.uk Git - ion3.git/blob - ioncore/manage.c
[svn-upgrade] Integrating new upstream version, ion3 (20070203)
[ion3.git] / ioncore / manage.c
1 /*
2  * ion/ioncore/manage.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 <libextl/extl.h>
14 #include "global.h"
15 #include "common.h"
16 #include "region.h"
17 #include "manage.h"
18 #include "names.h"
19 #include "fullscreen.h"
20 #include "pointer.h"
21 #include "netwm.h"
22 #include "extlconv.h"
23 #include "return.h"
24 #include "conf.h"
25 #include "group-ws.h"
26
27
28 /*{{{ Add */
29
30
31 WScreen *clientwin_find_suitable_screen(WClientWin *cwin, 
32                                         const WManageParams *param)
33 {
34     WScreen *scr=NULL, *found=NULL;
35     bool respectpos=(param->tfor!=NULL || param->userpos);
36     
37     FOR_ALL_SCREENS(scr){
38         if(!region_same_rootwin((WRegion*)scr, (WRegion*)cwin))
39             continue;
40             
41         if(!OBJ_IS(scr, WRootWin)){
42             /* The root window itself is only a fallback */
43             
44             if(REGION_IS_ACTIVE(scr)){
45                 found=scr;
46                 if(!respectpos)
47                     break;
48             }
49             
50             if(rectangle_contains(&REGION_GEOM(scr), 
51                                   param->geom.x, param->geom.y)){
52                 found=scr;
53                 if(respectpos)
54                     break;
55             }
56         }
57         
58         if(found==NULL)
59             found=scr;
60     }
61     
62     return found;
63 }
64
65
66 /*extern WRegion *ioncore_newly_created;*/
67
68
69 static WPHolder *try_target(WClientWin *cwin, const WManageParams *param, 
70                             const char *target)
71 {
72     WRegion *r=ioncore_lookup_region(target, NULL);
73         
74     if(r==NULL)
75         return NULL;
76             
77     return region_prepare_manage(r, cwin, param, MANAGE_REDIR_PREFER_NO);
78 }
79
80
81 static bool handle_target_winprops(WClientWin *cwin, const WManageParams *param,
82                                    WScreen *scr, WPHolder **ph_ret)
83 {
84     char *layout=NULL, *target=NULL;
85     WPHolder *ph=NULL;
86     bool mgd=FALSE;
87     
88     if(extl_table_gets_s(cwin->proptab, "target", &target))
89         ph=try_target(cwin, param, target);
90     
91     if(ph==NULL && extl_table_gets_s(cwin->proptab, "new_group", &layout)){
92         ExtlTab lo=ioncore_get_layout(layout);
93         
94         free(layout);
95         
96         if(lo!=extl_table_none()){
97             WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
98             int mask=MPLEX_ATTACH_SWITCHTO;
99             WRegion *reg;
100             
101             if(param->switchto)
102                 par.flags|=MPLEX_ATTACH_SWITCHTO;
103             
104             /*ioncore_newly_created=(WRegion*)cwin;*/
105             
106             reg=mplex_attach_new_(&scr->mplex, &par, mask, lo);
107             
108             extl_unref_table(lo);
109             
110             /*ioncore_newly_created=NULL;*/
111             
112             mgd=(region_manager((WRegion*)cwin)!=NULL);
113             
114             if(reg!=NULL && !mgd){
115                 if(target!=NULL)
116                     ph=try_target(cwin, param, target);
117                 
118                 if(ph==NULL){
119                     ph=region_prepare_manage(reg, cwin, param, 
120                                              MANAGE_REDIR_PREFER_YES);
121                     
122                     if(ph==NULL)
123                         destroy_obj((Obj*)reg);
124                 }
125             }
126         }
127     }
128     
129     if(target!=NULL)
130         free(target);
131     
132     *ph_ret=ph;
133     
134     return mgd;
135 }
136
137
138 bool clientwin_do_manage_default(WClientWin *cwin, 
139                                  const WManageParams *param)
140 {
141     WRegion *r=NULL, *r2;
142     WScreen *scr=NULL;
143     WPHolder *ph=NULL;
144     int fs=-1;
145     int swf;
146     bool ok, tmp;
147
148     /* Find a suitable screen */
149     scr=clientwin_find_suitable_screen(cwin, param);
150     if(scr==NULL){
151         warn(TR("Unable to find a screen for a new client window."));
152         return FALSE;
153     }
154     
155     if(handle_target_winprops(cwin, param, scr, &ph))
156         return TRUE;
157         
158     /* Check if param->tfor or any of its managers want to manage cwin. */
159     if(ph==NULL && param->tfor!=NULL){
160         assert(param->tfor!=cwin);
161         ph=region_prepare_manage_transient((WRegion*)param->tfor, cwin, 
162                                            param, 0);
163     }
164
165     if(ph==NULL){
166         /* Find a placeholder for non-fullscreen state */
167         ph=region_prepare_manage((WRegion*)scr, cwin, param,
168                                  MANAGE_REDIR_PREFER_YES);
169
170         /* Check fullscreen mode. (This is intentionally not done
171          * for transients and windows with target winprops.)
172          */
173         if(extl_table_gets_b(cwin->proptab, "fullscreen", &tmp))
174             fs=tmp;
175
176         if(fs<0)
177             fs=netwm_check_initial_fullscreen(cwin, param->switchto);
178     
179         if(fs<0){
180             fs=clientwin_check_fullscreen_request(cwin, 
181                                                   param->geom.w,
182                                                   param->geom.h,
183                                                   param->switchto);
184         }
185     }
186
187     if(fs>0){
188         /* Full-screen mode succesfull. */
189         if(pholder_target(ph)==(WRegion*)scr){
190             /* Discard useless placeholder. */
191             destroy_obj((Obj*)ph);
192             return TRUE;
193         }
194         
195         if(!region_do_set_return((WRegion*)cwin, ph))
196             destroy_obj((Obj*)ph);
197         
198         return TRUE;
199     }
200         
201     if(ph==NULL)
202         return FALSE;
203     
204     /* Not in full-screen mode; use the placeholder to attach. */
205     
206     swf=(param->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
207     ok=pholder_attach(ph, swf, (WRegion*)cwin);
208     destroy_obj((Obj*)ph);
209     
210     return ok;
211 }
212
213
214 /*}}}*/
215
216
217 /*{{{ region_prepare_manage/region_manage_clientwin/etc. */
218
219
220 WPHolder *region_prepare_manage(WRegion *reg, const WClientWin *cwin,
221                                 const WManageParams *param, int redir)
222 {
223     WPHolder *ret=NULL;
224     CALL_DYN_RET(ret, WPHolder*, region_prepare_manage, reg, 
225                  (reg, cwin, param, redir));
226     return ret;
227 }
228
229
230 WPHolder *region_prepare_manage_default(WRegion *reg, const WClientWin *cwin,
231                                         const WManageParams *param, int redir)
232 {
233     WRegion *curr;
234     
235     if(redir==MANAGE_REDIR_STRICT_NO)
236         return NULL;
237     
238     curr=region_current(reg);
239     
240     if(curr==NULL)
241         return NULL;
242         
243     return region_prepare_manage(curr, cwin, param, MANAGE_REDIR_PREFER_YES);
244 }
245
246
247 WPHolder *region_prepare_manage_transient(WRegion *reg, 
248                                           const WClientWin *cwin,
249                                           const WManageParams *param,
250                                           int unused)
251 {
252     WPHolder *ret=NULL;
253     CALL_DYN_RET(ret, WPHolder*, region_prepare_manage_transient, reg, 
254                  (reg, cwin, param, unused));
255     return ret;
256 }
257
258
259 WPHolder *region_prepare_manage_transient_default(WRegion *reg, 
260                                                   const WClientWin *cwin,
261                                                   const WManageParams *param,
262                                                   int unused)
263 {
264     WRegion *mgr=REGION_MANAGER(reg);
265     
266     if(mgr!=NULL)
267         return region_prepare_manage_transient(mgr, cwin, param, unused);
268     else
269         return NULL;
270 }
271
272
273 bool region_manage_clientwin(WRegion *reg, WClientWin *cwin,
274                              const WManageParams *par, int redir)
275 {
276     bool ret;
277     WPHolder *ph=region_prepare_manage(reg, cwin, par, redir);
278     int swf=(par->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
279     
280     if(ph==NULL)
281         return FALSE;
282     
283     ret=pholder_attach(ph, swf, (WRegion*)cwin);
284     
285     destroy_obj((Obj*)ph);
286     
287     return ret;
288 }
289
290
291 /*}}}*/
292
293
294 /*{{{ Rescue */
295
296
297 static WRegion *iter_children(void *st)
298 {
299     WRegion **nextp=(WRegion**)st;
300     WRegion *next=*nextp;
301     *nextp=(next==NULL ? NULL : next->p_next);
302     return next;   
303 }
304
305
306 bool region_rescue_child_clientwins(WRegion *reg, WPHolder *ph)
307 {
308     WRegion *next=reg->children;
309     return region_rescue_some_clientwins(reg, ph, iter_children, &next);
310 }
311
312
313 bool region_rescue_some_clientwins(WRegion *reg, WPHolder *ph,
314                                    WRegionIterator *iter, void *st)
315 {
316     bool res=FALSE;
317     int fails=0;
318
319     reg->flags|=REGION_CWINS_BEING_RESCUED;
320     
321     while(TRUE){
322         WRegion *tosave=iter(st);
323         
324         if(tosave==NULL)
325             break;
326         
327         if(!OBJ_IS(tosave, WClientWin)){
328             if(!region_rescue_clientwins(tosave, ph))
329                 fails++;
330         }else{
331             if(!pholder_attach(ph, 0, tosave))
332                 fails++;
333         }
334     }
335     
336     reg->flags&=~REGION_CWINS_BEING_RESCUED;
337
338     return (fails==0);
339 }
340
341
342 bool region_rescue_clientwins(WRegion *reg, WPHolder *ph)
343 {
344     bool ret=FALSE;
345     CALL_DYN_RET(ret, bool, region_rescue_clientwins, reg, (reg, ph));
346     return ret;
347 }
348
349
350 /*}}}*/
351
352
353 /*{{{ Misc. */
354
355
356 ExtlTab manageparams_to_table(const WManageParams *mp)
357 {
358     ExtlTab t=extl_create_table();
359     extl_table_sets_b(t, "switchto", mp->switchto);
360     extl_table_sets_b(t, "jumpto", mp->jumpto);
361     extl_table_sets_b(t, "userpos", mp->userpos);
362     extl_table_sets_b(t, "dockapp", mp->dockapp);
363     extl_table_sets_b(t, "maprq", mp->maprq);
364     extl_table_sets_i(t, "gravity", mp->gravity);
365     extl_table_sets_rectangle(t, "geom", &(mp->geom));
366     extl_table_sets_o(t, "tfor", (Obj*)(mp->tfor));
367     
368     return t;
369 }
370
371
372 /*}}}*/