]> git.decadent.org.uk Git - ion3.git/blob - ioncore/manage.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / manage.c
1 /*
2  * ion/ioncore/manage.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2009. 
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     if(!region_same_rootwin(r, (WRegion*)cwin))
76         return NULL;
77     
78     return region_prepare_manage(r, cwin, param, MANAGE_PRIORITY_NONE);
79 }
80
81
82 static bool handle_target_winprops(WClientWin *cwin, const WManageParams *param,
83                                    WScreen *scr, WPHolder **ph_ret)
84 {
85     char *layout=NULL, *target=NULL;
86     WPHolder *ph=NULL;
87     bool mgd=FALSE;
88     
89     if(extl_table_gets_s(cwin->proptab, "target", &target))
90         ph=try_target(cwin, param, target);
91     
92     if(ph==NULL && extl_table_gets_s(cwin->proptab, "new_group", &layout)){
93         ExtlTab lo=ioncore_get_layout(layout);
94         
95         free(layout);
96         
97         if(lo!=extl_table_none()){
98             WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
99             int mask=MPLEX_ATTACH_SWITCHTO;
100             WRegion *reg;
101             
102             if(param->switchto)
103                 par.flags|=MPLEX_ATTACH_SWITCHTO;
104             
105             /*ioncore_newly_created=(WRegion*)cwin;*/
106             
107             reg=mplex_attach_new_(&scr->mplex, &par, mask, lo);
108             
109             extl_unref_table(lo);
110             
111             /*ioncore_newly_created=NULL;*/
112             
113             mgd=(region_manager((WRegion*)cwin)!=NULL);
114             
115             if(reg!=NULL && !mgd){
116                 if(target!=NULL)
117                     ph=try_target(cwin, param, target);
118                 
119                 if(ph==NULL){
120                     ph=region_prepare_manage(reg, cwin, param, 
121                                              MANAGE_PRIORITY_NONE);
122                     
123                     if(ph==NULL)
124                         destroy_obj((Obj*)reg);
125                 }
126             }
127         }
128     }
129     
130     if(target!=NULL)
131         free(target);
132     
133     *ph_ret=ph;
134     
135     return mgd;
136 }
137
138
139 static bool try_fullscreen(WClientWin *cwin, WScreen *dflt, 
140                            const WManageParams *param)
141 {
142     WScreen *fs_scr=NULL;
143     bool fs=FALSE, tmp;
144     
145     /* Check fullscreen mode. (This is intentionally not done
146      * for transients and windows with target winprops.)
147      */
148     if(extl_table_gets_b(cwin->proptab, "fullscreen", &tmp)){
149         if(!tmp)
150             return FALSE;
151         fs_scr=dflt;
152     }
153
154     if(fs_scr==NULL)
155         fs_scr=netwm_check_initial_fullscreen(cwin);
156
157     if(fs_scr==NULL)
158         fs_scr=clientwin_fullscreen_chkrq(cwin, param->geom.w, param->geom.h);
159     
160     if(fs_scr!=NULL){
161         WPHolder *fs_ph=region_prepare_manage((WRegion*)fs_scr, cwin, param,
162                                               MANAGE_PRIORITY_NOREDIR);
163         
164         if(fs_ph!=NULL){
165             int swf=(param->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
166             
167             cwin->flags|=CLIENTWIN_FS_RQ;
168             
169             fs=pholder_attach(fs_ph, swf, (WRegion*)cwin);
170             
171             if(!fs)
172                 cwin->flags&=~CLIENTWIN_FS_RQ;
173                 
174             destroy_obj((Obj*)fs_ph);
175         }
176     }
177
178     return fs;
179 }
180
181
182 bool clientwin_do_manage_default(WClientWin *cwin, 
183                                  const WManageParams *param)
184 {
185     WScreen *scr=NULL;
186     WPHolder *ph=NULL;
187     int swf=(param->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
188     bool ok, uq=FALSE;
189     WRegion *createroot=NULL;
190
191     /* Find a suitable screen */
192     scr=clientwin_find_suitable_screen(cwin, param);
193     if(scr==NULL){
194         warn(TR("Unable to find a screen for a new client window."));
195         return FALSE;
196     }
197     
198     if(handle_target_winprops(cwin, param, scr, &ph))
199         return TRUE;
200         
201     /* Check if param->tfor or any of its managers want to manage cwin. */
202     if(ph==NULL && param->tfor!=NULL){
203         assert(param->tfor!=cwin);
204         ph=region_prepare_manage_transient((WRegion*)param->tfor, cwin, 
205                                            param, 0);
206         uq=TRUE;
207     }
208
209     if(ph==NULL){
210         /* Find a placeholder for non-fullscreen state */
211         ph=region_prepare_manage((WRegion*)scr, cwin, param,
212                                  MANAGE_PRIORITY_NONE);
213         
214         if(try_fullscreen(cwin, scr, param)){
215             if(pholder_target(ph)!=(WRegion*)region_screen_of((WRegion*)cwin)){
216                 WRegion *grp=region_groupleader_of((WRegion*)cwin);
217                 if(region_do_set_return(grp, ph))
218                     return TRUE;
219             }
220             destroy_obj((Obj*)ph);
221             return TRUE;
222         }
223         
224     }
225
226     if(ph==NULL)
227         return FALSE;
228     
229     /* Not in full-screen mode; use the placeholder to attach. */
230     {
231         WRegionAttachData data;
232         data.type=REGION_ATTACH_REPARENT;
233         data.u.reg=(WRegion*)cwin;
234     
235         createroot=pholder_do_attach(ph, 
236                                      swf|PHOLDER_ATTACH_RETURN_CREATEROOT,
237                                      &data);
238     }
239
240     destroy_obj((Obj*)ph);
241     
242     if(uq && createroot!=NULL)
243         ioncore_unsqueeze(createroot, FALSE);
244     
245     return (createroot!=NULL);
246 }
247
248
249 /*}}}*/
250
251
252 /*{{{ region_prepare_manage/region_manage_clientwin/etc. */
253
254
255 WPHolder *region_prepare_manage(WRegion *reg, const WClientWin *cwin,
256                                 const WManageParams *param, int priority)
257 {
258     WPHolder *ret=NULL;
259     CALL_DYN_RET(ret, WPHolder*, region_prepare_manage, reg, 
260                  (reg, cwin, param, priority));
261     return ret;
262 }
263
264
265 WPHolder *region_prepare_manage_default(WRegion *reg, const WClientWin *cwin,
266                                         const WManageParams *param, int priority)
267 {
268     int cpriority=MANAGE_PRIORITY_SUB(priority, MANAGE_PRIORITY_NONE);
269     WRegion *curr=region_current(reg);
270     
271     if(curr==NULL)
272         return NULL;
273         
274     return region_prepare_manage(curr, cwin, param, cpriority);
275 }
276
277
278 WPHolder *region_prepare_manage_transient(WRegion *reg, 
279                                           const WClientWin *cwin,
280                                           const WManageParams *param,
281                                           int unused)
282 {
283     WPHolder *ret=NULL;
284     CALL_DYN_RET(ret, WPHolder*, region_prepare_manage_transient, reg, 
285                  (reg, cwin, param, unused));
286     return ret;
287 }
288
289
290 WPHolder *region_prepare_manage_transient_default(WRegion *reg, 
291                                                   const WClientWin *cwin,
292                                                   const WManageParams *param,
293                                                   int unused)
294 {
295     WRegion *mgr=REGION_MANAGER(reg);
296     
297     if(mgr!=NULL)
298         return region_prepare_manage_transient(mgr, cwin, param, unused);
299     else
300         return NULL;
301 }
302
303
304 bool region_manage_clientwin(WRegion *reg, WClientWin *cwin,
305                              const WManageParams *par, int priority)
306 {
307     bool ret;
308     WPHolder *ph=region_prepare_manage(reg, cwin, par, priority);
309     int swf=(par->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
310     
311     if(ph==NULL)
312         return FALSE;
313     
314     ret=pholder_attach(ph, swf, (WRegion*)cwin);
315     
316     destroy_obj((Obj*)ph);
317     
318     return ret;
319 }
320
321
322 /*}}}*/
323
324
325 /*{{{ Rescue */
326
327
328 DECLSTRUCT(WRescueInfo){
329     WPHolder *ph;
330     WRegion *get_rescue;
331     bool failed_get;
332     bool test;
333     int flags;
334 };
335
336
337 static WRegion *iter_children(void *st)
338 {
339     WRegion **nextp=(WRegion**)st;
340     WRegion *next=*nextp;
341     *nextp=(next==NULL ? NULL : next->p_next);
342     return next;   
343 }
344
345
346 bool region_rescue_child_clientwins(WRegion *reg, WRescueInfo *info)
347 {
348     WRegion *next=reg->children;
349     return region_rescue_some_clientwins(reg, info, iter_children, &next);
350 }
351
352
353 WPHolder *rescueinfo_pholder(WRescueInfo *info)
354 {
355     if(info->test)
356         return NULL;
357         
358     if(info->ph==NULL){
359         info->ph=region_get_rescue_pholder(info->get_rescue);
360         if(info->ph==NULL){
361             info->failed_get=TRUE;
362             return NULL;
363         }
364     }
365     
366     return info->ph;
367 }
368
369
370 /* Bah, unsplitissä oikestaan pitäisi tehä non-deep rescue */
371
372 bool region_do_rescue_this(WRegion *tosave_, WRescueInfo *info, int ph_flags)
373 {
374     WClientWin *cwin=OBJ_CAST(tosave_, WClientWin);
375     WRegion *tosave=NULL;
376     
377     if(cwin!=NULL){
378         if(cwin->flags&CLIENTWIN_UNMAP_RQ)
379             return TRUE;
380         tosave=(WRegion*)cwin;
381     }else if(info->flags&REGION_RESCUE_NODEEP){
382         tosave=tosave_;
383     }else{
384         /* Try to rescue whole groups. */
385         /*tosave=(WRegion*)OBJ_CAST(tosave_, WGroupCW);*/
386     }
387     
388     if(tosave==NULL){
389         return region_rescue_clientwins(tosave_, info);
390     }else{
391         int phf=(info->flags&REGION_RESCUE_PHFLAGS_OK ? ph_flags : 0);
392         WPHolder *ph=rescueinfo_pholder(info);
393         
394         return (ph==NULL
395                 ? FALSE
396                 : pholder_attach(info->ph, phf, tosave));
397     }
398 }
399
400
401 bool region_rescue_some_clientwins(WRegion *reg, WRescueInfo *info,
402                                    WRegionIterator *iter, void *st)
403 {
404     bool res=FALSE;
405     int fails=0;
406
407     if(info->failed_get)
408         return FALSE;
409     
410     reg->flags|=REGION_CWINS_BEING_RESCUED;
411     
412     while(TRUE){
413         WRegion *tosave=iter(st);
414         
415         if(tosave==NULL)
416             break;
417
418         if(!region_do_rescue_this(tosave, info, 0)){
419             fails++;
420             if(info->failed_get)
421                 break;
422         }
423     }
424     
425     reg->flags&=~REGION_CWINS_BEING_RESCUED;
426
427     return (fails==0 && !info->failed_get);
428 }
429
430
431 bool region_rescue_clientwins(WRegion *reg, WRescueInfo *info)
432 {
433     bool ret=FALSE;
434     CALL_DYN_RET(ret, bool, region_rescue_clientwins, reg, (reg, info));
435     return ret;
436 }
437
438
439 bool region_rescue(WRegion *reg, WPHolder *ph, int flags)
440 {
441     WRescueInfo info;
442     bool ret;
443     
444     info.ph=ph;
445     info.flags=flags;
446     info.test=FALSE;
447     info.get_rescue=reg;
448     info.failed_get=FALSE;
449     
450     ret=region_rescue_clientwins(reg, &info);
451     
452     if(info.ph!=ph)
453         destroy_obj((Obj*)info.ph);
454     
455     return ret;
456 }
457
458
459 bool region_rescue_needed(WRegion *reg)
460 {
461     WRescueInfo info;
462     
463     info.ph=NULL;
464     info.flags=0;
465     info.test=TRUE;
466     info.get_rescue=reg;
467     info.failed_get=FALSE;
468     
469     return !region_rescue_clientwins(reg, &info);
470 }
471
472
473 /*}}}*/
474
475
476 /*{{{ Misc. */
477
478
479 ExtlTab manageparams_to_table(const WManageParams *mp)
480 {
481     ExtlTab t=extl_create_table();
482     extl_table_sets_b(t, "switchto", mp->switchto);
483     extl_table_sets_b(t, "jumpto", mp->jumpto);
484     extl_table_sets_b(t, "userpos", mp->userpos);
485     extl_table_sets_b(t, "dockapp", mp->dockapp);
486     extl_table_sets_b(t, "maprq", mp->maprq);
487     extl_table_sets_i(t, "gravity", mp->gravity);
488     extl_table_sets_rectangle(t, "geom", &(mp->geom));
489     extl_table_sets_o(t, "tfor", (Obj*)(mp->tfor));
490     
491     return t;
492 }
493
494
495 /*}}}*/