Better error message
[notion/jeffpc.git] / ioncore / manage.c
blob4d93d4eec470ca65165cac6931350f500075bc41
1 /*
2 * ion/ioncore/manage.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
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"
26 /*{{{ Add */
29 WScreen *clientwin_find_suitable_screen(WClientWin *cwin,
30 const WManageParams *param)
32 WScreen *scr=NULL, *found=NULL;
33 bool respectpos=(param->tfor!=NULL || param->userpos);
35 FOR_ALL_SCREENS(scr){
36 if(!region_same_rootwin((WRegion*)scr, (WRegion*)cwin))
37 continue;
38 if(REGION_IS_ACTIVE(scr)){
39 found=scr;
40 if(!respectpos)
41 break;
44 if(rectangle_contains(&REGION_GEOM(scr),
45 param->geom.x, param->geom.y)){
46 found=scr;
47 if(respectpos)
48 break;
51 if(found==NULL)
52 found=scr;
55 return found;
59 /*extern WRegion *ioncore_newly_created;*/
62 static WPHolder *try_target(WClientWin *cwin, const WManageParams *param,
63 const char *target)
65 WRegion *r=ioncore_lookup_region(target, NULL);
67 if(r==NULL)
68 return NULL;
70 if(!region_same_rootwin(r, (WRegion*)cwin))
71 return NULL;
73 return region_prepare_manage(r, cwin, param, MANAGE_PRIORITY_NONE);
77 static bool handle_target_winprops(WClientWin *cwin, const WManageParams *param,
78 WScreen *scr, WPHolder **ph_ret)
80 char *layout=NULL, *target=NULL;
81 WPHolder *ph=NULL;
82 bool mgd=FALSE;
84 if(extl_table_gets_s(cwin->proptab, "target", &target))
85 ph=try_target(cwin, param, target);
87 if(ph==NULL && extl_table_gets_s(cwin->proptab, "new_group", &layout)){
88 ExtlTab lo=ioncore_get_layout(layout);
90 free(layout);
92 if(lo!=extl_table_none()){
93 WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
94 int mask=MPLEX_ATTACH_SWITCHTO;
95 WRegion *reg;
97 if(param->switchto)
98 par.flags|=MPLEX_ATTACH_SWITCHTO;
100 /*ioncore_newly_created=(WRegion*)cwin;*/
102 reg=mplex_attach_new_(&scr->mplex, &par, mask, lo);
104 extl_unref_table(lo);
106 /*ioncore_newly_created=NULL;*/
108 mgd=(region_manager((WRegion*)cwin)!=NULL);
110 if(reg!=NULL && !mgd){
111 if(target!=NULL)
112 ph=try_target(cwin, param, target);
114 if(ph==NULL){
115 ph=region_prepare_manage(reg, cwin, param,
116 MANAGE_PRIORITY_NONE);
118 if(ph==NULL)
119 destroy_obj((Obj*)reg);
125 if(target!=NULL)
126 free(target);
128 *ph_ret=ph;
130 return mgd;
134 static bool try_fullscreen(WClientWin *cwin, WScreen *dflt,
135 const WManageParams *param)
137 WScreen *fs_scr=NULL;
138 bool fs=FALSE, tmp;
140 /* Check fullscreen mode. (This is intentionally not done
141 * for transients and windows with target winprops.)
143 if(extl_table_gets_b(cwin->proptab, "fullscreen", &tmp)){
144 if(!tmp)
145 return FALSE;
146 fs_scr=dflt;
149 if(fs_scr==NULL && netwm_check_initial_fullscreen(cwin))
150 fs_scr=dflt;
152 if(fs_scr==NULL)
153 fs_scr=clientwin_fullscreen_chkrq(cwin, param->geom.w, param->geom.h);
155 if(fs_scr!=NULL){
156 WPHolder *fs_ph=region_prepare_manage((WRegion*)fs_scr, cwin, param,
157 MANAGE_PRIORITY_NOREDIR);
159 if(fs_ph!=NULL){
160 int swf=(param->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
162 cwin->flags|=CLIENTWIN_FS_RQ;
164 fs=pholder_attach(fs_ph, swf, (WRegion*)cwin);
166 if(!fs)
167 cwin->flags&=~CLIENTWIN_FS_RQ;
169 destroy_obj((Obj*)fs_ph);
173 return fs;
177 bool clientwin_do_manage_default(WClientWin *cwin,
178 const WManageParams *param)
180 WScreen *scr=NULL;
181 WPHolder *ph=NULL;
182 int swf=(param->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
183 bool ok, uq=FALSE;
184 WRegion *createroot=NULL;
186 /* Find a suitable screen */
187 scr=clientwin_find_suitable_screen(cwin, param);
188 if(scr==NULL){
189 warn(TR("Unable to find a screen for a new client window."));
190 return FALSE;
193 if(handle_target_winprops(cwin, param, scr, &ph))
194 return TRUE;
196 /* Check if param->tfor or any of its managers want to manage cwin. */
197 if(ph==NULL && param->tfor!=NULL){
198 assert(param->tfor!=cwin);
199 ph=region_prepare_manage_transient((WRegion*)param->tfor, cwin,
200 param, 0);
201 uq=TRUE;
204 if(ph==NULL){
205 /* Find a placeholder for non-fullscreen state */
206 ph=region_prepare_manage((WRegion*)scr, cwin, param,
207 MANAGE_PRIORITY_NONE);
209 if(try_fullscreen(cwin, scr, param)){
210 if(pholder_target(ph)!=(WRegion*)region_screen_of((WRegion*)cwin)){
211 WRegion *grp=region_groupleader_of((WRegion*)cwin);
212 if(region_do_set_return(grp, ph))
213 return TRUE;
215 destroy_obj((Obj*)ph);
216 return TRUE;
221 if(ph==NULL)
222 return FALSE;
224 /* Not in full-screen mode; use the placeholder to attach. */
226 WRegionAttachData data;
227 data.type=REGION_ATTACH_REPARENT;
228 data.u.reg=(WRegion*)cwin;
230 createroot=pholder_do_attach(ph,
231 swf|PHOLDER_ATTACH_RETURN_CREATEROOT,
232 &data);
235 destroy_obj((Obj*)ph);
237 if(uq && createroot!=NULL)
238 ioncore_unsqueeze(createroot, FALSE);
240 return (createroot!=NULL);
244 /*}}}*/
247 /*{{{ region_prepare_manage/region_manage_clientwin/etc. */
250 WPHolder *region_prepare_manage(WRegion *reg, const WClientWin *cwin,
251 const WManageParams *param, int priority)
253 WPHolder *ret=NULL;
254 CALL_DYN_RET(ret, WPHolder*, region_prepare_manage, reg,
255 (reg, cwin, param, priority));
256 return ret;
260 WPHolder *region_prepare_manage_default(WRegion *reg, const WClientWin *cwin,
261 const WManageParams *param, int priority)
263 int cpriority=MANAGE_PRIORITY_SUB(priority, MANAGE_PRIORITY_NONE);
264 WRegion *curr=region_current(reg);
266 if(curr==NULL)
267 return NULL;
269 return region_prepare_manage(curr, cwin, param, cpriority);
273 WPHolder *region_prepare_manage_transient(WRegion *reg,
274 const WClientWin *cwin,
275 const WManageParams *param,
276 int unused)
278 WPHolder *ret=NULL;
279 CALL_DYN_RET(ret, WPHolder*, region_prepare_manage_transient, reg,
280 (reg, cwin, param, unused));
281 return ret;
285 WPHolder *region_prepare_manage_transient_default(WRegion *reg,
286 const WClientWin *cwin,
287 const WManageParams *param,
288 int unused)
290 WRegion *mgr=REGION_MANAGER(reg);
292 if(mgr!=NULL)
293 return region_prepare_manage_transient(mgr, cwin, param, unused);
294 else
295 return NULL;
299 bool region_manage_clientwin(WRegion *reg, WClientWin *cwin,
300 const WManageParams *par, int priority)
302 bool ret;
303 WPHolder *ph=region_prepare_manage(reg, cwin, par, priority);
304 int swf=(par->switchto ? PHOLDER_ATTACH_SWITCHTO : 0);
306 if(ph==NULL)
307 return FALSE;
309 ret=pholder_attach(ph, swf, (WRegion*)cwin);
311 destroy_obj((Obj*)ph);
313 return ret;
317 /*}}}*/
320 /*{{{ Rescue */
323 DECLSTRUCT(WRescueInfo){
324 WPHolder *ph;
325 WRegion *get_rescue;
326 /** set to TRUE when we fail to get a PHolder for this region. */
327 bool failed_get;
328 bool test;
329 int flags;
333 static WRegion *iter_children(void *st)
335 WRegion **nextp=(WRegion**)st;
336 WRegion *next=*nextp;
337 *nextp=(next==NULL ? NULL : next->p_next);
338 return next;
342 bool region_rescue_child_clientwins(WRegion *reg, WRescueInfo *info)
344 WRegion *next=reg->children;
345 return region_rescue_some_clientwins(reg, info, iter_children, &next);
349 WPHolder *rescueinfo_pholder(WRescueInfo *info)
351 if(info->test)
352 return NULL;
354 if(info->ph==NULL){
355 info->ph=region_get_rescue_pholder(info->get_rescue);
356 if(info->ph==NULL){
357 info->failed_get=TRUE;
358 return NULL;
362 return info->ph;
366 /* Bah, unsplitissä oikestaan pitäisi tehä non-deep rescue */
368 bool region_do_rescue_this(WRegion *tosave_, WRescueInfo *info, int ph_flags)
370 WClientWin *cwin=OBJ_CAST(tosave_, WClientWin);
371 WRegion *tosave=NULL;
373 if(cwin!=NULL){
374 if(cwin->flags&CLIENTWIN_UNMAP_RQ)
375 return TRUE;
376 tosave=(WRegion*)cwin;
377 }else if(info->flags&REGION_RESCUE_NODEEP){
378 tosave=tosave_;
379 }else{
380 /* Try to rescue whole groups. */
381 /*tosave=(WRegion*)OBJ_CAST(tosave_, WGroupCW);*/
384 if(tosave==NULL){
385 return region_rescue_clientwins(tosave_, info);
386 }else{
387 int phf=(info->flags&REGION_RESCUE_PHFLAGS_OK ? ph_flags : 0);
388 WPHolder *ph=rescueinfo_pholder(info);
390 return (ph==NULL
391 ? FALSE
392 : pholder_attach(info->ph, phf, tosave));
397 bool region_rescue_some_clientwins(WRegion *reg, WRescueInfo *info,
398 WRegionIterator *iter, void *st)
400 bool res=FALSE;
401 int fails=0;
403 if(info->failed_get)
404 return FALSE;
406 reg->flags|=REGION_CWINS_BEING_RESCUED;
408 while(TRUE){
409 WRegion *tosave=iter(st);
411 if(tosave==NULL)
412 break;
414 if(!region_do_rescue_this(tosave, info, 0)){
415 fails++;
416 if(info->failed_get)
417 break;
421 reg->flags&=~REGION_CWINS_BEING_RESCUED;
423 return (fails==0 && !info->failed_get);
427 bool region_rescue_clientwins(WRegion *reg, WRescueInfo *info)
429 bool ret=FALSE;
430 CALL_DYN_RET(ret, bool, region_rescue_clientwins, reg, (reg, info));
431 return ret;
435 bool region_rescue(WRegion *reg, WPHolder *ph, int flags)
437 WRescueInfo info;
438 bool ret;
440 info.ph=ph;
441 info.flags=flags;
442 info.test=FALSE;
443 info.get_rescue=reg;
444 info.failed_get=FALSE;
446 ret=region_rescue_clientwins(reg, &info);
448 if(info.ph!=ph)
449 destroy_obj((Obj*)info.ph);
451 return ret;
455 bool region_rescue_needed(WRegion *reg)
457 WRescueInfo info;
459 info.ph=NULL;
460 info.flags=0;
461 info.test=TRUE;
462 info.get_rescue=reg;
463 info.failed_get=FALSE;
465 return !region_rescue_clientwins(reg, &info);
469 /*}}}*/
472 /*{{{ Misc. */
475 ExtlTab manageparams_to_table(const WManageParams *mp)
477 ExtlTab t=extl_create_table();
478 extl_table_sets_b(t, "switchto", mp->switchto);
479 extl_table_sets_b(t, "jumpto", mp->jumpto);
480 extl_table_sets_b(t, "userpos", mp->userpos);
481 extl_table_sets_b(t, "dockapp", mp->dockapp);
482 extl_table_sets_b(t, "maprq", mp->maprq);
483 extl_table_sets_i(t, "gravity", mp->gravity);
484 extl_table_sets_rectangle(t, "geom", &(mp->geom));
485 extl_table_sets_o(t, "tfor", (Obj*)(mp->tfor));
487 return t;
491 /*}}}*/