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