]> git.decadent.org.uk Git - ion3.git/blob - ioncore/manage.c
5b036053c52218218b5f9dd50deb2f81133b0e5d
[ion3.git] / ioncore / manage.c
1 /*
2  * ion/ioncore/manage.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2008. 
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
190     /* Find a suitable screen */
191     scr=clientwin_find_suitable_screen(cwin, param);
192     if(scr==NULL){
193         warn(TR("Unable to find a screen for a new client window."));
194         return FALSE;
195     }
196     
197     if(handle_target_winprops(cwin, param, scr, &ph))
198         return TRUE;
199         
200     /* Check if param->tfor or any of its managers want to manage cwin. */
201     if(ph==NULL && param->tfor!=NULL){
202         assert(param->tfor!=cwin);
203         ph=region_prepare_manage_transient((WRegion*)param->tfor, cwin, 
204                                            param, 0);
205         uq=TRUE;
206     }
207
208     if(ph==NULL){
209         /* Find a placeholder for non-fullscreen state */
210         ph=region_prepare_manage((WRegion*)scr, cwin, param,
211                                  MANAGE_PRIORITY_NONE);
212         
213         if(try_fullscreen(cwin, scr, param)){
214             if(pholder_target(ph)!=(WRegion*)region_screen_of((WRegion*)cwin)){
215                 WRegion *grp=region_groupleader_of((WRegion*)cwin);
216                 if(region_do_set_return(grp, ph))
217                     return TRUE;
218             }
219             destroy_obj((Obj*)ph);
220             return TRUE;
221         }
222         
223     }
224
225     if(ph==NULL)
226         return FALSE;
227     
228     /* Not in full-screen mode; use the placeholder to attach. */
229     
230     ok=pholder_attach(ph, swf, (WRegion*)cwin);
231     
232     destroy_obj((Obj*)ph);
233     
234     if(uq && ok)
235         ioncore_unsqueeze((WRegion*)cwin, FALSE);
236     
237     return ok;
238 }
239
240
241 /*}}}*/
242
243
244 /*{{{ region_prepare_manage/region_manage_clientwin/etc. */
245
246
247 WPHolder *region_prepare_manage(WRegion *reg, const WClientWin *cwin,
248                                 const WManageParams *param, int priority)
249 {
250     WPHolder *ret=NULL;
251     CALL_DYN_RET(ret, WPHolder*, region_prepare_manage, reg, 
252                  (reg, cwin, param, priority));
253     return ret;
254 }
255
256
257 WPHolder *region_prepare_manage_default(WRegion *reg, const WClientWin *cwin,
258                                         const WManageParams *param, int priority)
259 {
260     int cpriority=MANAGE_PRIORITY_SUB(priority, MANAGE_PRIORITY_NONE);
261     WRegion *curr=region_current(reg);
262     
263     if(curr==NULL)
264         return NULL;
265         
266     return region_prepare_manage(curr, cwin, param, cpriority);
267 }
268
269
270 WPHolder *region_prepare_manage_transient(WRegion *reg, 
271                                           const WClientWin *cwin,
272                                           const WManageParams *param,
273                                           int unused)
274 {
275     WPHolder *ret=NULL;
276     CALL_DYN_RET(ret, WPHolder*, region_prepare_manage_transient, reg, 
277                  (reg, cwin, param, unused));
278     return ret;
279 }
280
281
282 WPHolder *region_prepare_manage_transient_default(WRegion *reg, 
283                                                   const WClientWin *cwin,
284                                                   const WManageParams *param,
285                                                   int unused)
286 {
287     WRegion *mgr=REGION_MANAGER(reg);
288     
289     if(mgr!=NULL)
290         return region_prepare_manage_transient(mgr, cwin, param, unused);
291     else
292         return NULL;
293 }
294
295
296 bool region_manage_clientwin(WRegion *reg, WClientWin *cwin,
297                              const WManageParams *par, int priority)
298 {
299     bool ret;
300     WPHolder *ph=region_prepare_manage(reg, cwin, par, priority);
301     int swf=(par->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
302     
303     if(ph==NULL)
304         return FALSE;
305     
306     ret=pholder_attach(ph, swf, (WRegion*)cwin);
307     
308     destroy_obj((Obj*)ph);
309     
310     return ret;
311 }
312
313
314 /*}}}*/
315
316
317 /*{{{ Rescue */
318
319
320 DECLSTRUCT(WRescueInfo){
321     WPHolder *ph;
322     WRegion *get_rescue;
323     bool failed_get;
324     bool test;
325     int flags;
326 };
327
328
329 static WRegion *iter_children(void *st)
330 {
331     WRegion **nextp=(WRegion**)st;
332     WRegion *next=*nextp;
333     *nextp=(next==NULL ? NULL : next->p_next);
334     return next;   
335 }
336
337
338 bool region_rescue_child_clientwins(WRegion *reg, WRescueInfo *info)
339 {
340     WRegion *next=reg->children;
341     return region_rescue_some_clientwins(reg, info, iter_children, &next);
342 }
343
344
345 WPHolder *rescueinfo_pholder(WRescueInfo *info)
346 {
347     if(info->test)
348         return NULL;
349         
350     if(info->ph==NULL){
351         info->ph=region_get_rescue_pholder(info->get_rescue);
352         if(info->ph==NULL){
353             info->failed_get=TRUE;
354             return NULL;
355         }
356     }
357     
358     return info->ph;
359 }
360
361
362 /* Bah, unsplitissä oikestaan pitäisi tehä non-deep rescue */
363
364 bool region_do_rescue_this(WRegion *tosave_, WRescueInfo *info, int ph_flags)
365 {
366     WClientWin *cwin=OBJ_CAST(tosave_, WClientWin);
367     WRegion *tosave=NULL;
368     
369     if(cwin!=NULL){
370         if(cwin->flags&CLIENTWIN_UNMAP_RQ)
371             return TRUE;
372         tosave=(WRegion*)cwin;
373     }else if(info->flags&REGION_RESCUE_NODEEP){
374         tosave=tosave_;
375     }else{
376         /* Try to rescue whole groups. */
377         /*tosave=(WRegion*)OBJ_CAST(tosave_, WGroupCW);*/
378     }
379     
380     if(tosave==NULL){
381         return region_rescue_clientwins(tosave_, info);
382     }else{
383         int phf=(info->flags&REGION_RESCUE_PHFLAGS_OK ? ph_flags : 0);
384         WPHolder *ph=rescueinfo_pholder(info);
385         
386         return (ph==NULL
387                 ? FALSE
388                 : pholder_attach(info->ph, phf, tosave));
389     }
390 }
391
392
393 bool region_rescue_some_clientwins(WRegion *reg, WRescueInfo *info,
394                                    WRegionIterator *iter, void *st)
395 {
396     bool res=FALSE;
397     int fails=0;
398
399     if(info->failed_get)
400         return FALSE;
401     
402     reg->flags|=REGION_CWINS_BEING_RESCUED;
403     
404     while(TRUE){
405         WRegion *tosave=iter(st);
406         
407         if(tosave==NULL)
408             break;
409
410         if(!region_do_rescue_this(tosave, info, 0)){
411             fails++;
412             if(info->failed_get)
413                 break;
414         }
415     }
416     
417     reg->flags&=~REGION_CWINS_BEING_RESCUED;
418
419     return (fails==0 && !info->failed_get);
420 }
421
422
423 bool region_rescue_clientwins(WRegion *reg, WRescueInfo *info)
424 {
425     bool ret=FALSE;
426     CALL_DYN_RET(ret, bool, region_rescue_clientwins, reg, (reg, info));
427     return ret;
428 }
429
430
431 bool region_rescue(WRegion *reg, WPHolder *ph, int flags)
432 {
433     WRescueInfo info;
434     bool ret;
435     
436     info.ph=ph;
437     info.flags=flags;
438     info.test=FALSE;
439     info.get_rescue=reg;
440     info.failed_get=FALSE;
441     
442     ret=region_rescue_clientwins(reg, &info);
443     
444     if(info.ph!=ph)
445         destroy_obj((Obj*)info.ph);
446     
447     return ret;
448 }
449
450
451 bool region_rescue_needed(WRegion *reg)
452 {
453     WRescueInfo info;
454     
455     info.ph=NULL;
456     info.flags=0;
457     info.test=TRUE;
458     info.get_rescue=reg;
459     info.failed_get=FALSE;
460     
461     return !region_rescue_clientwins(reg, &info);
462 }
463
464
465 /*}}}*/
466
467
468 /*{{{ Misc. */
469
470
471 ExtlTab manageparams_to_table(const WManageParams *mp)
472 {
473     ExtlTab t=extl_create_table();
474     extl_table_sets_b(t, "switchto", mp->switchto);
475     extl_table_sets_b(t, "jumpto", mp->jumpto);
476     extl_table_sets_b(t, "userpos", mp->userpos);
477     extl_table_sets_b(t, "dockapp", mp->dockapp);
478     extl_table_sets_b(t, "maprq", mp->maprq);
479     extl_table_sets_i(t, "gravity", mp->gravity);
480     extl_table_sets_rectangle(t, "geom", &(mp->geom));
481     extl_table_sets_o(t, "tfor", (Obj*)(mp->tfor));
482     
483     return t;
484 }
485
486
487 /*}}}*/