Merge branch 'contrib_goto_focus'
[notion.git] / mod_tiling / tiling.c
blob6d28e746b567e63a4135b4bc7c1919db73915167
1 /*
2 * ion/mod_tiling/tiling.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <X11/Xatom.h>
13 #include <libtu/objp.h>
14 #include <libtu/minmax.h>
15 #include <libtu/ptrlist.h>
16 #include <libmainloop/defer.h>
17 #include <libmainloop/signal.h>
19 #include <ioncore/common.h>
20 #include <ioncore/rootwin.h>
21 #include <ioncore/focus.h>
22 #include <ioncore/global.h>
23 #include <ioncore/region.h>
24 #include <ioncore/manage.h>
25 #include <ioncore/screen.h>
26 #include <ioncore/names.h>
27 #include <ioncore/saveload.h>
28 #include <ioncore/attach.h>
29 #include <ioncore/resize.h>
30 #include <libextl/extl.h>
31 #include <ioncore/regbind.h>
32 #include <ioncore/extlconv.h>
33 #include <ioncore/xwindow.h>
34 #include <ioncore/navi.h>
35 #include <ioncore/property.h>
36 #include "placement.h"
37 #include "tiling.h"
38 #include "split.h"
39 #include "splitfloat.h"
40 #include "split-stdisp.h"
41 #include "main.h"
45 /*{{{ Some helper routines */
48 static WSplitRegion *get_node_check(WTiling *ws, WRegion *reg)
50 WSplitRegion *node;
52 if(reg==NULL)
53 return NULL;
55 node=splittree_node_of(reg);
57 if(node==NULL || REGION_MANAGER(reg)!=(WRegion*)ws)
58 return NULL;
60 return node;
64 static bool check_node(WTiling *ws, WSplit *split)
66 if(split->parent)
67 return check_node(ws, (WSplit*)split->parent);
69 if((split->ws_if_root!=(void*)ws)){
70 warn(TR("Split not on workspace."));
71 return FALSE;
73 return TRUE;
77 /*}}}*/
80 /*{{{ Dynfun implementations */
83 static void reparent_mgd(WRegion *sub, WWindow *par)
85 WFitParams subfp;
86 subfp.g=REGION_GEOM(sub);
87 subfp.mode=REGION_FIT_EXACT;
88 if(!region_fitrep(sub, par, &subfp)){
89 warn(TR("Error reparenting %s."), region_name(sub));
90 region_detach_manager(sub);
95 bool tiling_fitrep(WTiling *ws, WWindow *par, const WFitParams *fp)
97 bool ok=FALSE;
99 if(par!=NULL){
100 if(!region_same_rootwin((WRegion*)ws, (WRegion*)par))
101 return FALSE;
103 region_unset_parent((WRegion*)ws);
105 XReparentWindow(ioncore_g.dpy, ws->dummywin,
106 par->win, fp->g.x, fp->g.y);
108 region_set_parent((WRegion*)ws, par);
110 if(ws->split_tree!=NULL)
111 split_reparent(ws->split_tree, par);
114 REGION_GEOM(ws)=fp->g;
116 if(ws->split_tree!=NULL){
117 if(fp->mode&REGION_FIT_ROTATE)
118 ok=split_rotate_to(ws->split_tree, &(fp->g), fp->rotation);
119 if(!ok)
120 split_resize(ws->split_tree, &(fp->g), PRIMN_ANY, PRIMN_ANY);
123 return TRUE;
127 void tiling_managed_rqgeom(WTiling *ws, WRegion *mgd,
128 const WRQGeomParams *rq,
129 WRectangle *geomret)
131 WSplitRegion *node=get_node_check(ws, mgd);
132 if(node!=NULL && ws->split_tree!=NULL)
133 splittree_rqgeom((WSplit*)node, rq->flags, &rq->geom, geomret);
136 bool tiling_managed_maximize(WTiling *ws, WRegion *mgd, int dir, int action)
138 WSplitRegion *node=get_node_check(ws, mgd);
139 bool ret;
140 if(node!=NULL && ws->split_tree!=NULL){
141 ret=split_maximize((WSplit*)node, dir, action);
142 if(action==RESTORE && ret)
143 split_regularise_stdisp(ws->stdispnode);
144 return ret;
146 else
147 return FALSE;
151 void tiling_map(WTiling *ws)
153 REGION_MARK_MAPPED(ws);
154 XMapWindow(ioncore_g.dpy, ws->dummywin);
156 if(ws->split_tree!=NULL)
157 split_map(ws->split_tree);
161 void tiling_unmap(WTiling *ws)
163 REGION_MARK_UNMAPPED(ws);
164 XUnmapWindow(ioncore_g.dpy, ws->dummywin);
166 if(ws->split_tree!=NULL)
167 split_unmap(ws->split_tree);
171 void tiling_fallback_focus(WTiling *ws, bool warp)
173 region_finalise_focusing((WRegion*)ws, ws->dummywin, warp, CurrentTime, TRUE);
177 void tiling_do_set_focus(WTiling *ws, bool warp)
179 WRegion *sub=tiling_current(ws);
181 if(sub==NULL){
182 tiling_fallback_focus(ws, warp);
183 return;
186 region_do_set_focus(sub, warp);
190 static WTimer *restack_timer=NULL;
193 static void restack_handler(WTimer *UNUSED(tmr), Obj *obj)
195 if(obj!=NULL){
196 WTiling *ws=(WTiling*)obj;
197 split_restack(ws->split_tree, ws->dummywin, Above);
202 bool tiling_managed_prepare_focus(WTiling *ws, WRegion *reg,
203 int flags, WPrepareFocusResult *res)
205 WSplitRegion *node;
207 if(!region_prepare_focus((WRegion*)ws, flags, res))
208 return FALSE;
210 node=get_node_check(ws, reg);
212 if(node!=NULL && node->split.parent!=NULL)
213 splitinner_mark_current(node->split.parent, &(node->split));
215 /* WSplitSplit uses activity based stacking as required on WAutoWS,
216 * so we must restack here.
218 if(ws->split_tree!=NULL){
219 int rd=mod_tiling_raise_delay;
220 bool use_timer=rd>0 && flags&REGION_GOTO_ENTERWINDOW;
222 if(use_timer){
223 if(restack_timer!=NULL){
224 Obj *obj=restack_timer->objwatch.obj;
225 if(obj!=(Obj*)ws){
226 timer_reset(restack_timer);
227 restack_handler(restack_timer, obj);
229 }else{
230 restack_timer=create_timer();
234 if(use_timer && restack_timer!=NULL){
235 timer_set(restack_timer, rd, restack_handler, (Obj*)ws);
236 }else{
237 split_restack(ws->split_tree, ws->dummywin, Above);
241 res->reg=reg;
242 res->flags=flags;
243 return TRUE;
248 void tiling_restack(WTiling *ws, Window other, int mode)
250 xwindow_restack(ws->dummywin, other, mode);
251 if(ws->split_tree!=NULL)
252 split_restack(ws->split_tree, ws->dummywin, Above);
256 void tiling_stacking(WTiling *ws, Window *bottomret, Window *topret)
258 Window sbottom=None, stop=None;
260 if(ws->split_tree!=None)
261 split_stacking(ws->split_tree, &sbottom, &stop);
263 *bottomret=ws->dummywin;
264 *topret=(stop!=None ? stop : ws->dummywin);
268 Window tiling_xwindow(const WTiling *ws)
270 return ws->dummywin;
274 /*}}}*/
277 /*{{{ Status display support code */
280 static bool regnodefilter(WSplit *split)
282 return OBJ_IS(split, WSplitRegion);
286 void tiling_unmanage_stdisp(WTiling *ws, bool permanent, bool nofocus)
288 WSplitRegion *tofocus=NULL;
289 bool setfocus=FALSE;
290 WRegion *od;
292 if(ws->stdispnode==NULL)
293 return;
295 od=ws->stdispnode->regnode.reg;
297 if(od!=NULL){
298 if(!nofocus && REGION_IS_ACTIVE(od) &&
299 region_may_control_focus((WRegion*)ws)){
300 setfocus=TRUE;
301 tofocus=(WSplitRegion*)split_nextto((WSplit*)(ws->stdispnode),
302 PRIMN_ANY, PRIMN_ANY,
303 regnodefilter);
305 /* Reset node_of info here so tiling_managed_remove will not
306 * remove the node.
308 splittree_set_node_of(od, NULL);
309 tiling_do_managed_remove(ws, od);
312 if(permanent){
313 WSplit *node=(WSplit*)ws->stdispnode;
314 ws->stdispnode=NULL;
315 splittree_remove(node, TRUE);
318 if(setfocus){
319 if(tofocus!=NULL)
320 region_set_focus(tofocus->reg);
321 else
322 tiling_fallback_focus(ws, FALSE);
327 static void tiling_create_stdispnode(WTiling *ws, WRegion *stdisp,
328 int corner, int orientation,
329 bool fullsize)
331 WRectangle *wg=&REGION_GEOM(ws), dg;
332 WSplitST *stdispnode;
333 WSplitSplit *split;
335 assert(ws->split_tree!=NULL);
337 if(orientation==REGION_ORIENTATION_HORIZONTAL){
338 dg.x=wg->x;
339 dg.w=wg->w;
340 dg.h=0;
341 dg.y=((corner==MPLEX_STDISP_BL || corner==MPLEX_STDISP_BR)
342 ? wg->y+wg->h
343 : 0);
344 }else{
345 dg.y=wg->y;
346 dg.h=wg->h;
347 dg.w=0;
348 dg.x=((corner==MPLEX_STDISP_TR || corner==MPLEX_STDISP_BR)
349 ? wg->x+wg->w
350 : 0);
353 stdispnode=create_splitst(&dg, stdisp);
355 if(stdispnode==NULL){
356 warn(TR("Unable to create a node for status display."));
357 return;
360 stdispnode->corner=corner;
361 stdispnode->orientation=orientation;
362 stdispnode->fullsize=fullsize;
364 split=create_splitsplit(wg, (orientation==REGION_ORIENTATION_HORIZONTAL
365 ? SPLIT_VERTICAL
366 : SPLIT_HORIZONTAL));
368 if(split==NULL){
369 warn(TR("Unable to create new split for status display."));
370 stdispnode->regnode.reg=NULL;
371 destroy_obj((Obj*)stdispnode);
372 return;
375 /* Set up new split tree */
376 ((WSplit*)stdispnode)->parent=(WSplitInner*)split;
377 ws->split_tree->parent=(WSplitInner*)split;
378 ws->split_tree->ws_if_root=NULL;
380 if((orientation==REGION_ORIENTATION_HORIZONTAL &&
381 (corner==MPLEX_STDISP_BL || corner==MPLEX_STDISP_BR)) ||
382 (orientation==REGION_ORIENTATION_VERTICAL &&
383 (corner==MPLEX_STDISP_TR || corner==MPLEX_STDISP_BR))){
384 split->tl=ws->split_tree;
385 split->br=(WSplit*)stdispnode;
386 split->current=SPLIT_CURRENT_TL;
387 }else{
388 split->tl=(WSplit*)stdispnode;
389 split->br=ws->split_tree;
390 split->current=SPLIT_CURRENT_BR;
393 ws->split_tree=(WSplit*)split;
394 ((WSplit*)split)->ws_if_root=ws;
395 ws->stdispnode=stdispnode;
399 void tiling_manage_stdisp(WTiling *ws, WRegion *stdisp,
400 const WMPlexSTDispInfo *di)
402 bool mcf=region_may_control_focus((WRegion*)ws);
403 int flags=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
404 int orientation=region_orientation(stdisp);
405 bool act=FALSE;
406 WRectangle dg, *stdg;
408 if(orientation!=REGION_ORIENTATION_VERTICAL /*&&
409 orientation!=REGION_ORIENTATION_HORIZONTAL*/){
410 orientation=REGION_ORIENTATION_HORIZONTAL;
413 if(ws->stdispnode==NULL || ws->stdispnode->regnode.reg!=stdisp)
414 region_detach_manager(stdisp);
416 /* Remove old stdisp if corner and orientation don't match.
418 if(ws->stdispnode!=NULL && (di->pos!=ws->stdispnode->corner ||
419 orientation!=ws->stdispnode->orientation)){
420 tiling_unmanage_stdisp(ws, TRUE, TRUE);
423 if(ws->stdispnode==NULL){
424 tiling_create_stdispnode(ws, stdisp, di->pos, orientation,
425 di->fullsize);
426 if(ws->stdispnode==NULL)
427 return;
428 }else{
429 WRegion *od=ws->stdispnode->regnode.reg;
430 if(od!=NULL){
431 act=REGION_IS_ACTIVE(od);
432 splittree_set_node_of(od, NULL);
433 tiling_managed_remove(ws, od);
434 assert(ws->stdispnode->regnode.reg==NULL);
437 ws->stdispnode->fullsize=di->fullsize;
438 ws->stdispnode->regnode.reg=stdisp;
439 splittree_set_node_of(stdisp, &(ws->stdispnode->regnode));
442 if(!tiling_managed_add(ws, stdisp)){
443 tiling_unmanage_stdisp(ws, TRUE, TRUE);
444 return;
447 stdisp->flags|=REGION_SKIP_FOCUS;
449 dg=((WSplit*)(ws->stdispnode))->geom;
451 dg.h=stdisp_recommended_h(ws->stdispnode);
452 dg.w=stdisp_recommended_w(ws->stdispnode);
454 splittree_rqgeom((WSplit*)(ws->stdispnode), flags, &dg, FALSE);
456 stdg=&(((WSplit*)ws->stdispnode)->geom);
458 if(stdisp->geom.x!=stdg->x || stdisp->geom.y!=stdg->y ||
459 stdisp->geom.w!=stdg->w || stdisp->geom.h!=stdg->h){
460 region_fit(stdisp, stdg, REGION_FIT_EXACT);
463 /* Restack to ensure the split tree is stacked in the expected order. */
464 if(ws->split_tree!=NULL)
465 split_restack(ws->split_tree, ws->dummywin, Above);
467 if(mcf && act)
468 region_set_focus(stdisp);
472 /*}}}*/
475 /*{{{ Create/destroy */
478 bool tiling_managed_add_default(WTiling *ws, WRegion *reg)
480 WFrame *frame;
482 if(TILING_STDISP_OF(ws)!=reg){
483 if(!ptrlist_insert_last(&(ws->managed_list), reg))
484 return FALSE;
487 region_set_manager(reg, (WRegion*)ws);
489 frame=OBJ_CAST(reg, WFrame);
490 if(frame!=NULL){
491 if(framemode_unalt(frame_mode(frame))!=FRAME_MODE_TILED)
492 frame_set_mode(frame, FRAME_MODE_TILED);
495 if(REGION_IS_MAPPED(ws))
496 region_map(reg);
498 if(region_may_control_focus((WRegion*)ws)){
499 WRegion *curr=tiling_current(ws);
500 if(curr==NULL || !REGION_IS_ACTIVE(curr))
501 region_warp(reg);
504 return TRUE;
508 bool tiling_managed_add(WTiling *ws, WRegion *reg)
510 bool ret=FALSE;
511 CALL_DYN_RET(ret, bool, tiling_managed_add, ws, (ws, reg));
512 return ret;
516 bool tiling_do_attach_initial(WTiling *ws, WRegion *reg)
518 assert(ws->split_tree==NULL);
520 ws->split_tree=(WSplit*)create_splitregion(&REGION_GEOM(reg), reg);
521 if(ws->split_tree==NULL)
522 return FALSE;
524 ws->split_tree->ws_if_root=ws;
526 if(!tiling_managed_add(ws, reg)){
527 destroy_obj((Obj*)ws->split_tree);
528 ws->split_tree=NULL;
529 return FALSE;
532 return TRUE;
536 static WRegion *create_frame_tiling(WWindow *parent, const WFitParams *fp)
538 return (WRegion*)create_frame(parent, fp, FRAME_MODE_TILED, "Tiling Frame");
542 bool tiling_init(WTiling *ws, WWindow *parent, const WFitParams *fp,
543 WRegionSimpleCreateFn *create_frame_fn, bool ci)
545 const char *p[1];
547 ws->split_tree=NULL;
548 ws->create_frame_fn=(create_frame_fn
549 ? create_frame_fn
550 : create_frame_tiling);
551 ws->stdispnode=NULL;
552 ws->managed_list=NULL;
553 ws->batchop=FALSE;
555 ws->dummywin=XCreateWindow(ioncore_g.dpy, parent->win,
556 fp->g.x, fp->g.y, 1, 1, 0,
557 CopyFromParent, InputOnly,
558 CopyFromParent, 0, NULL);
559 if(ws->dummywin==None)
560 return FALSE;
562 p[0] = "Notion WTiling dummy window";
563 xwindow_set_text_property(ws->dummywin, XA_WM_NAME, p, 1);
565 region_init(&(ws->reg), parent, fp);
567 ws->reg.flags|=(REGION_GRAB_ON_PARENT|
568 REGION_PLEASE_WARP);
570 if(ci){
571 WRegionAttachData data;
572 WRegion *res;
574 data.type=REGION_ATTACH_NEW;
575 data.u.n.fn=(WRegionCreateFn*)ws->create_frame_fn;
576 data.u.n.param=NULL;
578 res=region_attach_helper((WRegion*)ws, parent, fp,
579 (WRegionDoAttachFn*)tiling_do_attach_initial,
580 NULL, &data);
582 if(res==NULL){
583 XDestroyWindow(ioncore_g.dpy, ws->dummywin);
584 return FALSE;
588 XSelectInput(ioncore_g.dpy, ws->dummywin,
589 FocusChangeMask|KeyPressMask|KeyReleaseMask|
590 ButtonPressMask|ButtonReleaseMask);
591 XSaveContext(ioncore_g.dpy, ws->dummywin, ioncore_g.win_context,
592 (XPointer)ws);
594 region_register(&(ws->reg));
595 region_add_bindmap((WRegion*)ws, mod_tiling_tiling_bindmap);
597 return TRUE;
601 WTiling *create_tiling(WWindow *parent, const WFitParams *fp,
602 WRegionSimpleCreateFn *create_frame_fn, bool ci)
604 CREATEOBJ_IMPL(WTiling, tiling, (p, parent, fp, create_frame_fn, ci));
608 WTiling *create_tiling_simple(WWindow *parent, const WFitParams *fp)
610 return create_tiling(parent, fp, NULL, TRUE);
614 void tiling_deinit(WTiling *ws)
616 WRegion *reg;
617 WTilingIterTmp tmp;
619 tiling_unmanage_stdisp(ws, FALSE, TRUE);
621 FOR_ALL_MANAGED_BY_TILING(reg, ws, tmp){
622 destroy_obj((Obj*)reg);
625 FOR_ALL_MANAGED_BY_TILING(reg, ws, tmp){
626 assert(FALSE);
629 if(ws->split_tree!=NULL)
630 destroy_obj((Obj*)(ws->split_tree));
632 XDeleteContext(ioncore_g.dpy, ws->dummywin, ioncore_g.win_context);
633 XDestroyWindow(ioncore_g.dpy, ws->dummywin);
634 ws->dummywin=None;
636 region_deinit(&(ws->reg));
640 WRegion *tiling_managed_disposeroot(WTiling *ws, WRegion *reg)
642 WTilingIterTmp tmp;
643 WRegion *mgd;
645 if(ws->batchop)
646 return reg;
648 FOR_ALL_MANAGED_BY_TILING(mgd, ws, tmp){
649 if(mgd!=TILING_STDISP_OF(ws) && mgd!=reg)
650 return reg;
653 return region_disposeroot((WRegion*)ws);
657 bool tiling_rescue_clientwins(WTiling *ws, WRescueInfo *info)
659 WTilingIterTmp tmp;
661 ptrlist_iter_init(&tmp, ws->managed_list);
663 return region_rescue_some_clientwins((WRegion*)ws, info,
664 (WRegionIterator*)ptrlist_iter,
665 &tmp);
669 void tiling_do_managed_remove(WTiling *ws, WRegion *reg)
671 if(TILING_STDISP_OF(ws)==reg){
672 ws->stdispnode->regnode.reg=NULL;
673 }else{
674 ptrlist_remove(&(ws->managed_list), reg);
677 region_unset_manager(reg, (WRegion*)ws);
678 splittree_set_node_of(reg, NULL);
682 static bool nostdispfilter(WSplit *node)
684 return (OBJ_IS(node, WSplitRegion) && !OBJ_IS(node, WSplitST));
688 void tiling_managed_remove(WTiling *ws, WRegion *reg)
690 bool act=REGION_IS_ACTIVE(reg);
691 bool mcf=region_may_control_focus((WRegion*)ws);
692 WSplitRegion *node=get_node_check(ws, reg);
693 bool norestore=(OBJ_IS_BEING_DESTROYED(ws) || ws->batchop);
694 WRegion *other=NULL;
696 if(!norestore)
697 other=tiling_do_navi_next(ws, reg, REGION_NAVI_ANY, TRUE, FALSE);
699 tiling_do_managed_remove(ws, reg);
701 if(node==(WSplitRegion*)(ws->stdispnode))
702 ws->stdispnode=NULL;
704 if(node!=NULL){
705 bool reused=FALSE;
707 if(other==NULL && !norestore){
708 WWindow *par=REGION_PARENT(ws);
709 WFitParams fp;
711 assert(par!=NULL);
713 fp.g=node->split.geom;
714 fp.mode=REGION_FIT_EXACT;
716 other=(ws->create_frame_fn)(par, &fp);
718 if(other!=NULL){
719 node->reg=other;
720 splittree_set_node_of(other, node);
721 tiling_managed_add(ws, other);
722 reused=TRUE;
723 }else{
724 warn(TR("Tiling in useless state."));
728 if(!reused)
729 splittree_remove((WSplit*)node, (!norestore && other!=NULL));
732 if(!norestore && other!=NULL && act && mcf)
733 region_warp(other);
737 static bool mplexfilter(WSplit *node)
739 WSplitRegion *regnode=OBJ_CAST(node, WSplitRegion);
741 return (regnode!=NULL && regnode->reg!=NULL &&
742 OBJ_IS(regnode->reg, WMPlex));
746 static WPHolder *find_ph_result=NULL;
747 static WRegion *find_ph_param=NULL;
750 static bool find_ph(WSplit *split)
752 WSplitRegion *sr=OBJ_CAST(split, WSplitRegion);
754 assert(find_ph_result==NULL);
756 if(sr==NULL || sr->reg==NULL)
757 return FALSE;
759 find_ph_result=region_get_rescue_pholder_for(sr->reg, find_ph_param);
761 return (find_ph_result!=NULL);
765 WPHolder *tiling_get_rescue_pholder_for(WTiling *ws, WRegion *mgd)
767 WSplit *node=(WSplit*)get_node_check(ws, mgd);
768 WPHolder *ph;
770 find_ph_result=NULL;
771 find_ph_param=mgd;
773 if(node==NULL){
774 if(ws->split_tree!=NULL){
775 split_current_todir(ws->split_tree, PRIMN_ANY, PRIMN_ANY,
776 find_ph);
778 }else{
779 while(node!=NULL){
780 split_nextto(node, PRIMN_ANY, PRIMN_ANY, find_ph);
781 if(find_ph_result!=NULL)
782 break;
783 node=(WSplit*)node->parent;
787 ph=find_ph_result;
788 find_ph_result=NULL;
789 find_ph_param=NULL;
791 return ph;
795 /*}}}*/
798 /*{{{ Navigation */
801 static void navi_to_primn(WRegionNavi nh, WPrimn *hprimn, WPrimn *vprimn,
802 WPrimn choice)
804 /* choice should be PRIMN_ANY or PRIMN_NONE */
806 switch(nh){
807 case REGION_NAVI_BEG:
808 *vprimn=PRIMN_TL;
809 *hprimn=PRIMN_TL;
810 break;
812 case REGION_NAVI_END:
813 *vprimn=PRIMN_BR;
814 *hprimn=PRIMN_BR;
815 break;
817 case REGION_NAVI_LEFT:
818 *hprimn=PRIMN_TL;
819 *vprimn=choice;
820 break;
822 case REGION_NAVI_RIGHT:
823 *hprimn=PRIMN_BR;
824 *vprimn=choice;
825 break;
827 case REGION_NAVI_TOP:
828 *hprimn=choice;
829 *vprimn=PRIMN_TL;
830 break;
832 case REGION_NAVI_BOTTOM:
833 *hprimn=choice;
834 *vprimn=PRIMN_BR;
835 break;
837 default:
838 case REGION_NAVI_ANY:
839 *hprimn=PRIMN_ANY;
840 *vprimn=PRIMN_ANY;
841 break;
846 static WRegion *node_reg(WSplit *node)
848 WSplitRegion *rnode=OBJ_CAST(node, WSplitRegion);
849 return (rnode!=NULL ? rnode->reg : NULL);
853 WRegion *tiling_do_navi_next(WTiling *ws, WRegion *reg,
854 WRegionNavi nh, bool nowrap,
855 bool any)
857 WSplitFilter *filter=(any ? NULL : nostdispfilter);
858 WPrimn hprimn, vprimn;
859 WRegion *nxt=NULL;
861 navi_to_primn(nh, &hprimn, &vprimn, PRIMN_NONE);
863 if(reg==NULL)
864 reg=tiling_current(ws);
866 if(reg!=NULL){
867 WSplitRegion *node=get_node_check(ws, reg);
868 if(node!=NULL){
869 nxt=node_reg(split_nextto((WSplit*)node, hprimn, vprimn,
870 filter));
874 if(nxt==NULL && !nowrap){
875 nxt=node_reg(split_current_todir(ws->split_tree,
876 primn_none2any(primn_invert(hprimn)),
877 primn_none2any(primn_invert(vprimn)),
878 filter));
881 return nxt;
885 WRegion *tiling_do_navi_first(WTiling *ws, WRegionNavi nh, bool any)
887 WSplitFilter *filter=(any ? NULL : nostdispfilter);
888 WPrimn hprimn, vprimn;
890 navi_to_primn(nh, &hprimn, &vprimn, PRIMN_ANY);
892 return node_reg(split_current_todir(ws->split_tree,
893 hprimn, vprimn, filter));
897 WRegion *tiling_navi_next(WTiling *ws, WRegion *reg,
898 WRegionNavi nh, WRegionNaviData *data)
900 WRegion *nxt=tiling_do_navi_next(ws, reg, nh, TRUE, FALSE);
902 return region_navi_cont(&ws->reg, nxt, data);
906 WRegion *tiling_navi_first(WTiling *ws, WRegionNavi nh,
907 WRegionNaviData *data)
909 WRegion *reg=tiling_do_navi_first(ws, nh, FALSE);
911 return region_navi_cont(&ws->reg, reg, data);
915 /*}}}*/
918 /*{{{ Split/unsplit */
921 static bool get_split_dir_primn(const char *str, int *dir, int *primn)
923 WPrimn hprimn, vprimn;
924 WRegionNavi nh;
926 if(!ioncore_string_to_navi(str, &nh))
927 return FALSE;
929 navi_to_primn(nh, &hprimn, &vprimn, PRIMN_NONE);
931 if(hprimn==PRIMN_NONE){
932 *dir=SPLIT_VERTICAL;
933 *primn=vprimn;
934 }else if(vprimn==PRIMN_NONE){
935 *dir=SPLIT_HORIZONTAL;
936 *primn=hprimn;
937 }else{
938 warn(TR("Invalid direction"));
939 return FALSE;
942 return TRUE;
946 static bool get_split_dir_primn_float(const char *str, int *dir, int *primn,
947 bool *floating)
949 if(strncmp(str, "floating:", 9)==0){
950 *floating=TRUE;
951 return get_split_dir_primn(str+9, dir, primn);
952 }else{
953 *floating=FALSE;
954 return get_split_dir_primn(str, dir, primn);
959 #define SPLIT_MINS 16 /* totally arbitrary */
962 static WFrame *tiling_do_split(WTiling *ws, WSplit *node,
963 const char *dirstr, int minw, int minh)
965 int dir, primn, mins;
966 bool floating=FALSE;
967 WFrame *newframe;
968 WSplitRegion *nnode;
970 if(node==NULL || ws->split_tree==NULL){
971 warn(TR("Invalid node."));
972 return NULL;
975 if(!get_split_dir_primn_float(dirstr, &dir, &primn, &floating))
976 return NULL;
978 mins=(dir==SPLIT_VERTICAL ? minh : minw);
980 if(!floating){
981 nnode=splittree_split(node, dir, primn, mins,
982 ws->create_frame_fn,
983 REGION_PARENT(ws));
984 }else{
985 nnode=splittree_split_floating(node, dir, primn, mins,
986 ws->create_frame_fn, ws);
989 if(nnode==NULL){
990 warn(TR("Unable to split."));
991 return NULL;
994 /* We must restack here to ensure the split tree is stacked in the
995 * expected order.
997 if(ws->split_tree!=NULL)
998 split_restack(ws->split_tree, ws->dummywin, Above);
1000 newframe=OBJ_CAST(nnode->reg, WFrame);
1001 assert(newframe!=NULL);
1003 if(!tiling_managed_add(ws, nnode->reg)){
1004 nnode->reg=NULL;
1005 destroy_obj((Obj*)nnode);
1006 destroy_obj((Obj*)newframe);
1007 return NULL;
1010 return newframe;
1014 /*EXTL_DOC
1015 * Create a new frame on \var{ws} \codestr{above}, \codestr{below}
1016 * \codestr{left} of, or \codestr{right} of \var{node} as indicated
1017 * by \var{dirstr}. If \var{dirstr} is prefixed with
1018 * \codestr{floating:} a floating split is created.
1020 EXTL_EXPORT_MEMBER
1021 WFrame *tiling_split(WTiling *ws, WSplit *node, const char *dirstr)
1023 if(!check_node(ws, node))
1024 return NULL;
1026 return tiling_do_split(ws, node, dirstr,
1027 SPLIT_MINS, SPLIT_MINS);
1031 /*EXTL_DOC
1032 * Same as \fnref{WTiling.split} at the root of the split tree.
1034 EXTL_EXPORT_MEMBER
1035 WFrame *tiling_split_top(WTiling *ws, const char *dirstr)
1037 return tiling_do_split(ws, ws->split_tree, dirstr,
1038 SPLIT_MINS, SPLIT_MINS);
1042 /*EXTL_DOC
1043 * Split \var{frame} creating a new frame to direction \var{dirstr}
1044 * (one of \codestr{left}, \codestr{right}, \codestr{top} or
1045 * \codestr{bottom}) of \var{frame}.
1046 * If \var{attach_current} is set, the region currently displayed in
1047 * \var{frame}, if any, is moved to thenew frame.
1048 * If \var{dirstr} is prefixed with \codestr{floating:}, a floating
1049 * split is created.
1051 EXTL_EXPORT_MEMBER
1052 WFrame *tiling_split_at(WTiling *ws, WFrame *frame, const char *dirstr,
1053 bool attach_current)
1055 WRegion *curr;
1056 WSplitRegion *node;
1057 WFrame *newframe;
1059 if(frame==NULL)
1060 return NULL;
1062 node=get_node_check(ws, (WRegion*)frame);
1064 newframe=tiling_do_split(ws, (WSplit*)node, dirstr,
1065 region_min_w((WRegion*)frame),
1066 region_min_h((WRegion*)frame));
1068 if(newframe==NULL)
1069 return NULL;
1071 curr=mplex_mx_current(&(frame->mplex));
1073 if(attach_current && curr!=NULL)
1074 mplex_attach_simple(&(newframe->mplex), curr, MPLEX_ATTACH_SWITCHTO);
1076 if(region_may_control_focus((WRegion*)frame))
1077 region_goto((WRegion*)newframe);
1079 return newframe;
1083 /*EXTL_DOC
1084 * Try to relocate regions managed by \var{reg} to another frame
1085 * and, if possible, destroy it.
1087 EXTL_EXPORT_MEMBER
1088 void tiling_unsplit_at(WTiling *ws, WRegion *reg)
1090 WPHolder *ph;
1092 if(reg==NULL || REGION_MANAGER(reg)!=(WRegion*)ws)
1093 return;
1095 ph=region_get_rescue_pholder_for((WRegion*)ws, reg);
1097 if(ph!=NULL){
1098 region_rescue(reg, ph, REGION_RESCUE_NODEEP|REGION_RESCUE_PHFLAGS_OK);
1099 destroy_obj((Obj*)ph);
1102 region_defer_rqdispose(reg);
1106 /*}}}*/
1109 /*{{{ Navigation etc. exports */
1112 WRegion *tiling_current(WTiling *ws)
1114 WSplitRegion *node=NULL;
1115 if(ws->split_tree!=NULL){
1116 node=(WSplitRegion*)split_current_todir(ws->split_tree,
1117 PRIMN_ANY, PRIMN_ANY, NULL);
1119 return (node ? node->reg : NULL);
1123 /*EXTL_DOC
1124 * Iterate over managed regions of \var{ws} until \var{iterfn} returns
1125 * \code{false}.
1126 * The function is called in protected mode.
1127 * This routine returns \code{true} if it reaches the end of list
1128 * without this happening.
1130 EXTL_SAFE
1131 EXTL_EXPORT_MEMBER
1132 bool tiling_managed_i(WTiling *ws, ExtlFn iterfn)
1134 PtrListIterTmp tmp;
1136 ptrlist_iter_init(&tmp, ws->managed_list);
1138 return extl_iter_objlist_(iterfn, (ObjIterator*)ptrlist_iter, &tmp);
1142 /*EXTL_DOC
1143 * Returns the root of the split tree.
1145 EXTL_SAFE
1146 EXTL_EXPORT_MEMBER
1147 WSplit *tiling_split_tree(WTiling *ws)
1149 return ws->split_tree;
1153 /*EXTL_DOC
1154 * Return the most previously active region next to \var{reg} in
1155 * direction \var{dirstr} (\codestr{left}, \codestr{right}, \codestr{up},
1156 * or \codestr{down}). The region \var{reg}
1157 * must be managed by \var{ws}. If \var{any} is not set, the status display
1158 * is not considered.
1160 EXTL_SAFE
1161 EXTL_EXPORT_MEMBER
1162 WRegion *tiling_nextto(WTiling *ws, WRegion *reg, const char *dirstr,
1163 bool any)
1165 WRegionNavi nh;
1167 if(!ioncore_string_to_navi(dirstr, &nh))
1168 return NULL;
1170 return tiling_do_navi_next(ws, reg, nh, FALSE, any);
1174 /*EXTL_DOC
1175 * Return the most previously active region on \var{ws} with no
1176 * other regions next to it in direction \var{dirstr}
1177 * (\codestr{left}, \codestr{right}, \codestr{up}, or \codestr{down}).
1178 * If \var{any} is not set, the status display is not considered.
1180 EXTL_SAFE
1181 EXTL_EXPORT_MEMBER
1182 WRegion *tiling_farthest(WTiling *ws, const char *dirstr, bool any)
1184 WRegionNavi nh;
1186 if(!ioncore_string_to_navi(dirstr, &nh))
1187 return NULL;
1189 return tiling_do_navi_first(ws, nh, any);
1193 /*EXTL_DOC
1194 * For region \var{reg} managed by \var{ws} return the \type{WSplit}
1195 * a leaf of which \var{reg} is.
1197 EXTL_SAFE
1198 EXTL_EXPORT_MEMBER
1199 WSplitRegion *tiling_node_of(WTiling *ws, WRegion *reg)
1201 if(reg==NULL){
1202 warn(TR("Nil parameter."));
1203 return NULL;
1206 if(REGION_MANAGER(reg)!=(WRegion*)ws){
1207 warn(TR("Manager doesn't match."));
1208 return NULL;
1211 return splittree_node_of(reg);
1215 /*}}}*/
1218 /*{{{ Flip and transpose */
1221 static WSplitSplit *get_at_split(WTiling *ws, WRegion *reg)
1223 WSplit *node;
1224 WSplitSplit *split;
1226 if(reg==NULL){
1227 split=OBJ_CAST(ws->split_tree, WSplitSplit);
1228 if(split==NULL)
1229 return NULL;
1230 else if(split->br==(WSplit*)ws->stdispnode)
1231 return OBJ_CAST(split->tl, WSplitSplit);
1232 else if(split->tl==(WSplit*)ws->stdispnode)
1233 return OBJ_CAST(split->br, WSplitSplit);
1234 else
1235 return split;
1238 node=(WSplit*)get_node_check(ws, reg);
1240 if(node==NULL)
1241 return NULL;
1243 if(node==(WSplit*)ws->stdispnode){
1244 warn(TR("The status display is not a valid parameter for "
1245 "this routine."));
1246 return NULL;
1249 split=OBJ_CAST(node->parent, WSplitSplit);
1251 if(split!=NULL && (split->tl==(WSplit*)ws->stdispnode ||
1252 split->br==(WSplit*)ws->stdispnode)){
1253 split=OBJ_CAST(((WSplit*)split)->parent, WSplitSplit);
1256 return split;
1260 /*EXTL_DOC
1261 * Flip \var{ws} at \var{reg} or root if nil.
1263 EXTL_EXPORT_MEMBER
1264 bool iowns_flip_at(WTiling *ws, WRegion *reg)
1266 WSplitSplit *split=get_at_split(ws, reg);
1268 if(split==NULL){
1269 return FALSE;
1270 }else{
1271 splitsplit_flip(split);
1272 return TRUE;
1277 /*EXTL_DOC
1278 * Transpose \var{ws} at \var{reg} or root if nil.
1280 EXTL_EXPORT_MEMBER
1281 bool iowns_transpose_at(WTiling *ws, WRegion *reg)
1283 WSplitSplit *split=get_at_split(ws, reg);
1285 if(split==NULL){
1286 return FALSE;
1287 }else{
1288 split_transpose((WSplit*)split);
1289 return TRUE;
1294 /*}}}*/
1297 /*{{{ Floating toggle */
1300 static void replace(WSplitSplit *split, WSplitSplit *nsplit)
1302 WSplitInner *psplit=split->isplit.split.parent;
1304 nsplit->tl=split->tl;
1305 split->tl=NULL;
1306 nsplit->tl->parent=(WSplitInner*)nsplit;
1308 nsplit->br=split->br;
1309 split->br=NULL;
1310 nsplit->br->parent=(WSplitInner*)nsplit;
1312 if(psplit!=NULL){
1313 splitinner_replace((WSplitInner*)psplit, (WSplit*)split,
1314 (WSplit*)nsplit);
1315 }else{
1316 splittree_changeroot((WSplit*)split, (WSplit*)nsplit);
1321 WSplitSplit *tiling_set_floating(WTiling *ws, WSplitSplit *split, int sp)
1323 bool set=OBJ_IS(split, WSplitFloat);
1324 bool nset=libtu_do_setparam(sp, set);
1325 const WRectangle *g=&((WSplit*)split)->geom;
1326 WSplitSplit *ns;
1328 if(!XOR(nset, set))
1329 return split;
1331 if(nset){
1332 ns=(WSplitSplit*)create_splitfloat(g, ws, split->dir);
1333 }else{
1334 if(OBJ_IS(split->tl, WSplitST) || OBJ_IS(split->br, WSplitST)){
1335 warn(TR("Refusing to float split directly containing the "
1336 "status display."));
1337 return NULL;
1339 ns=create_splitsplit(g, split->dir);
1342 if(ns!=NULL){
1343 replace(split, ns);
1344 split_resize((WSplit*)ns, g, PRIMN_ANY, PRIMN_ANY);
1345 mainloop_defer_destroy((Obj*)split);
1348 return ns;
1352 /*EXTL_DOC
1353 * Toggle floating of a split's sides at \var{split} as indicated by the
1354 * parameter \var{how} (\codestr{set}, \codestr{unset}, or \codestr{toggle}).
1355 * A split of the appropriate is returned, if there was a change.
1357 EXTL_EXPORT_AS(WTiling, set_floating)
1358 WSplitSplit *tiling_set_floating_extl(WTiling *ws, WSplitSplit *split,
1359 const char *how)
1361 if(!check_node(ws, (WSplit*)split))
1362 return NULL;
1363 return tiling_set_floating(ws, split, libtu_string_to_setparam(how));
1367 /*EXTL_DOC
1368 * Toggle floating of the sides of a split containin \var{reg} as indicated
1369 * by the parameters \var{how} (\codestr{set}, \codestr{unset}, or
1370 * \codestr{toggle}) and \var{dirstr} (\codestr{left}, \codestr{right},
1371 * \codestr{up}, or \codestr{down}). The new status is returned
1372 * (and \code{false} also on error).
1374 EXTL_EXPORT_AS(WTiling, set_floating_at)
1375 bool tiling_set_floating_at_extl(WTiling *ws, WRegion *reg, const char *how,
1376 const char *dirstr)
1378 WPrimn hprimn=PRIMN_ANY, vprimn=PRIMN_ANY;
1379 WSplitSplit *split, *nsplit;
1380 WSplit *node;
1382 node=(WSplit*)get_node_check(ws, reg);
1383 if(node==NULL)
1384 return FALSE;
1387 if(dirstr!=NULL){
1388 WRegionNavi nh;
1390 if(!ioncore_string_to_navi(dirstr, &nh))
1391 return FALSE;
1393 navi_to_primn(nh, &hprimn, &vprimn, PRIMN_NONE);
1396 while(TRUE){
1397 split=OBJ_CAST(node->parent, WSplitSplit);
1398 if(split==NULL){
1399 warn(TR("No suitable split here."));
1400 return FALSE;
1403 if(!OBJ_IS(split->tl, WSplitST) && !OBJ_IS(split->br, WSplitST)){
1404 WPrimn tmp=(split->dir==SPLIT_VERTICAL ? vprimn : hprimn);
1405 if(tmp==PRIMN_ANY
1406 || (node==split->tl && tmp==PRIMN_BR)
1407 || (node==split->br && tmp==PRIMN_TL)){
1408 break;
1412 node=(WSplit*)split;
1415 nsplit=tiling_set_floating(ws, split, libtu_string_to_setparam(how));
1417 return OBJ_IS((Obj*)(nsplit==NULL ? split : nsplit), WSplitFloat);
1421 /*}}}*/
1424 /*{{{ Save */
1427 ExtlTab tiling_get_configuration(WTiling *ws)
1429 ExtlTab tab, split_tree=extl_table_none();
1431 tab=region_get_base_configuration((WRegion*)ws);
1433 if(ws->split_tree!=NULL){
1434 if(!split_get_config(ws->split_tree, &split_tree))
1435 warn(TR("Could not get split tree."));
1438 extl_table_sets_t(tab, "split_tree", split_tree);
1439 extl_unref_table(split_tree);
1441 return tab;
1445 /*}}}*/
1448 /*{{{ Load */
1451 WSplit *load_splitst(WTiling *ws, const WRectangle *geom, ExtlTab tab)
1453 WSplitST *st;
1455 if(ws->stdispnode!=NULL){
1456 warn(TR("Workspace already has a status display node."));
1457 return NULL;
1460 st=create_splitst(geom, NULL);
1461 ws->stdispnode=st;
1462 return (WSplit*)st;
1466 static bool do_attach(WTiling *ws, WRegion *reg, void *p)
1468 WSplitRegion *node=create_splitregion(&REGION_GEOM(reg), reg);
1470 if(node==NULL)
1471 return FALSE;
1473 if(!tiling_managed_add(ws, reg)){
1474 node->reg=NULL;
1475 destroy_obj((Obj*)node);
1476 return FALSE;
1479 *(WSplitRegion**)p=node;
1481 return TRUE;
1485 WSplit *load_splitregion(WTiling *ws, const WRectangle *geom, ExtlTab tab)
1487 WWindow *par=REGION_PARENT(ws);
1488 WRegionAttachData data;
1489 WSplit *node=NULL;
1490 WFitParams fp;
1491 ExtlTab rt;
1493 if(!extl_table_gets_t(tab, "regparams", &rt)){
1494 warn(TR("Missing region parameters."));
1495 return NULL;
1498 data.type=REGION_ATTACH_LOAD;
1499 data.u.tab=rt;
1501 assert(par!=NULL);
1502 fp.g=*geom;
1503 fp.mode=REGION_FIT_EXACT;
1505 region_attach_helper((WRegion*)ws, par, &fp,
1506 (WRegionDoAttachFn*)do_attach, &node, &data);
1508 extl_unref_table(rt);
1510 return node;
1514 #define MINS 1
1516 WSplit *load_splitsplit(WTiling *ws, const WRectangle *geom, ExtlTab tab)
1518 WSplit *tl=NULL, *br=NULL;
1519 WSplitSplit *split;
1520 char *dir_str;
1521 int dir, brs, tls;
1522 ExtlTab subtab;
1523 WRectangle geom2;
1524 int set=0;
1526 set+=(extl_table_gets_i(tab, "tls", &tls)==TRUE);
1527 set+=(extl_table_gets_i(tab, "brs", &brs)==TRUE);
1528 set+=(extl_table_gets_s(tab, "dir", &dir_str)==TRUE);
1530 if(set!=3)
1531 return NULL;
1533 if(strcmp(dir_str, "vertical")==0){
1534 dir=SPLIT_VERTICAL;
1535 }else if(strcmp(dir_str, "horizontal")==0){
1536 dir=SPLIT_HORIZONTAL;
1537 }else{
1538 warn(TR("Invalid direction."));
1539 free(dir_str);
1540 return NULL;
1542 free(dir_str);
1544 split=create_splitsplit(geom, dir);
1545 if(split==NULL)
1546 return NULL;
1548 tls=maxof(tls, MINS);
1549 brs=maxof(brs, MINS);
1551 geom2=*geom;
1552 if(dir==SPLIT_HORIZONTAL){
1553 tls=maxof(0, geom->w)*tls/(tls+brs);
1554 geom2.w=tls;
1555 }else{
1556 tls=maxof(0, geom->h)*tls/(tls+brs);
1557 geom2.h=tls;
1560 if(extl_table_gets_t(tab, "tl", &subtab)){
1561 tl=tiling_load_node(ws, &geom2, subtab);
1562 extl_unref_table(subtab);
1565 geom2=*geom;
1566 if(dir==SPLIT_HORIZONTAL){
1567 geom2.w-=tls;
1568 geom2.x+=tls;
1569 }else{
1570 geom2.h-=tls;
1571 geom2.y+=tls;
1574 if(extl_table_gets_t(tab, "br", &subtab)){
1575 br=tiling_load_node(ws, &geom2, subtab);
1576 extl_unref_table(subtab);
1579 if(tl==NULL || br==NULL){
1580 /* PRIMN_TL/BR instead of ANY because of stdisp. */
1581 destroy_obj((Obj*)split);
1582 if(tl!=NULL){
1583 split_do_resize(tl, geom, PRIMN_BR, PRIMN_BR, FALSE);
1584 return tl;
1586 if(br!=NULL){
1587 split_do_resize(br, geom, PRIMN_TL, PRIMN_TL, FALSE);
1588 return br;
1590 return NULL;
1593 tl->parent=(WSplitInner*)split;
1594 br->parent=(WSplitInner*)split;
1596 /*split->tmpsize=tls;*/
1597 split->tl=tl;
1598 split->br=br;
1600 return (WSplit*)split;
1604 WSplit *tiling_load_node_default(WTiling *ws, const WRectangle *geom,
1605 ExtlTab tab)
1607 char *typestr=NULL;
1608 WSplit *node=NULL;
1610 extl_table_gets_s(tab, "type", &typestr);
1612 if(typestr==NULL){
1613 warn(TR("No split type given."));
1614 return NULL;
1617 if(strcmp(typestr, "WSplitRegion")==0)
1618 node=load_splitregion(ws, geom, tab);
1619 else if(strcmp(typestr, "WSplitSplit")==0)
1620 node=load_splitsplit(ws, geom, tab);
1621 else if(strcmp(typestr, "WSplitFloat")==0)
1622 node=load_splitfloat(ws, geom, tab);
1623 else if(strcmp(typestr, "WSplitST")==0)
1624 node=NULL;/*load_splitst(ws, geom, tab);*/
1625 else
1626 warn(TR("Unknown split type."));
1628 free(typestr);
1630 return node;
1634 WSplit *tiling_load_node(WTiling *ws, const WRectangle *geom, ExtlTab tab)
1636 WSplit *ret=NULL;
1637 CALL_DYN_RET(ret, WSplit*, tiling_load_node, ws, (ws, geom, tab));
1638 return ret;
1643 WRegion *tiling_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
1645 WTiling *ws;
1646 ExtlTab treetab;
1647 bool ci=TRUE;
1649 if(extl_table_gets_t(tab, "split_tree", &treetab))
1650 ci=FALSE;
1652 ws=create_tiling(par, fp, NULL, ci);
1654 if(ws==NULL){
1655 if(!ci)
1656 extl_unref_table(treetab);
1657 return NULL;
1660 if(!ci){
1661 ws->split_tree=tiling_load_node(ws, &REGION_GEOM(ws), treetab);
1662 extl_unref_table(treetab);
1665 if(ws->split_tree==NULL){
1666 warn(TR("The workspace is empty."));
1667 destroy_obj((Obj*)ws);
1668 return NULL;
1671 ws->split_tree->ws_if_root=ws;
1672 split_restack(ws->split_tree, ws->dummywin, Above);
1674 return (WRegion*)ws;
1678 /*}}}*/
1681 /*{{{ Dynamic function table and class implementation */
1684 static DynFunTab tiling_dynfuntab[]={
1685 {region_map,
1686 tiling_map},
1688 {region_unmap,
1689 tiling_unmap},
1691 {region_do_set_focus,
1692 tiling_do_set_focus},
1694 {(DynFun*)region_fitrep,
1695 (DynFun*)tiling_fitrep},
1697 {region_managed_rqgeom,
1698 tiling_managed_rqgeom},
1700 {(DynFun*)region_managed_maximize,
1701 (DynFun*)tiling_managed_maximize},
1703 {region_managed_remove,
1704 tiling_managed_remove},
1706 {(DynFun*)region_managed_prepare_focus,
1707 (DynFun*)tiling_managed_prepare_focus},
1709 {(DynFun*)region_prepare_manage,
1710 (DynFun*)tiling_prepare_manage},
1712 {(DynFun*)region_rescue_clientwins,
1713 (DynFun*)tiling_rescue_clientwins},
1715 {(DynFun*)region_get_rescue_pholder_for,
1716 (DynFun*)tiling_get_rescue_pholder_for},
1718 {(DynFun*)region_get_configuration,
1719 (DynFun*)tiling_get_configuration},
1721 {(DynFun*)region_managed_disposeroot,
1722 (DynFun*)tiling_managed_disposeroot},
1724 {(DynFun*)region_current,
1725 (DynFun*)tiling_current},
1727 {(DynFun*)tiling_managed_add,
1728 (DynFun*)tiling_managed_add_default},
1730 {region_manage_stdisp,
1731 tiling_manage_stdisp},
1733 {region_unmanage_stdisp,
1734 tiling_unmanage_stdisp},
1736 {(DynFun*)tiling_load_node,
1737 (DynFun*)tiling_load_node_default},
1739 {region_restack,
1740 tiling_restack},
1742 {region_stacking,
1743 tiling_stacking},
1745 {(DynFun*)region_navi_first,
1746 (DynFun*)tiling_navi_first},
1748 {(DynFun*)region_navi_next,
1749 (DynFun*)tiling_navi_next},
1751 {(DynFun*)region_xwindow,
1752 (DynFun*)tiling_xwindow},
1754 END_DYNFUNTAB
1758 EXTL_EXPORT
1759 IMPLCLASS(WTiling, WRegion, tiling_deinit, tiling_dynfuntab);
1762 /*}}}*/