4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
15 #include <libtu/objp.h>
16 #include <libtu/minmax.h>
18 #include <libextl/extl.h>
19 #include <libmainloop/defer.h>
33 #include "frame-pointer.h"
38 #include "mplexpholder.h"
41 #include "sizepolicy.h"
45 #include "groupedpholder.h"
48 #define SUBS_MAY_BE_MAPPED(MPLEX) \
49 (REGION_IS_MAPPED(MPLEX) && !MPLEX_MGD_UNVIEWABLE(MPLEX))
51 #define PASSIVE(ST) ((ST)->level<=STACKING_LEVEL_MODAL1 \
53 || (ST)->reg->flags®ION_SKIP_FOCUS))
55 #define CAN_MANAGE_STDISP(REG) HAS_DYN(REG, region_manage_stdisp)
58 /*{{{ Stacking list stuff */
61 WStacking *mplex_get_stacking(WMPlex *mplex)
63 return window_get_stacking(&mplex->win);
67 WStacking **mplex_get_stackingp(WMPlex *mplex)
69 return window_get_stackingp(&mplex->win);
73 void mplex_iter_init(WMPlexIterTmp *tmp, WMPlex *mplex)
75 stacking_iter_mgr_init(tmp, mplex->mgd, NULL, mplex);
79 WRegion *mplex_iter(WMPlexIterTmp *tmp)
81 return stacking_iter_mgr(tmp);
85 WStacking *mplex_iter_nodes(WMPlexIterTmp *tmp)
87 return stacking_iter_mgr_nodes(tmp);
94 /*{{{ Destroy/create mplex */
97 bool mplex_do_init(WMPlex *mplex, WWindow *parent,
98 const WFitParams *fp, Window win)
103 mplex->mx_current=NULL;
109 watch_init(&(mplex->stdispwatch));
110 mplex->stdispinfo.pos=MPLEX_STDISP_BL;
111 mplex->stdispinfo.fullsize=FALSE;
113 if(!window_do_init((WWindow*)mplex, parent, fp, win))
116 mplex->win.region.flags|=REGION_BINDINGS_ARE_GRABBED;
118 window_select_input(&(mplex->win), IONCORE_EVENTMASK_CWINMGR);
120 region_register((WRegion*)mplex);
122 /* Call this to set MPLEX_MANAGED_UNVIEWABLE if necessary. */
123 mplex_fit_managed(mplex);
129 bool mplex_init(WMPlex *mplex, WWindow *parent, const WFitParams *fp)
131 return mplex_do_init(mplex, parent, fp, None);
135 WMPlex *create_mplex(WWindow *parent, const WFitParams *fp)
137 CREATEOBJ_IMPL(WMPlex, mplex, (p, parent, fp));
141 void mplex_deinit(WMPlex *mplex)
146 FOR_ALL_MANAGED_BY_MPLEX(mplex, reg, tmp){
147 destroy_obj((Obj*)reg);
150 assert(mplex->mgd==NULL);
151 assert(mplex->mx_list==NULL);
153 while(mplex->mx_phs!=NULL){
154 assert(mplexpholder_move(mplex->mx_phs, NULL, NULL, NULL));
157 window_deinit((WWindow*)mplex);
161 bool mplex_may_destroy(WMPlex *mplex)
163 if(mplex->mgd!=NULL){
164 warn(TR("Refusing to destroy - not empty."));
175 /*{{{ Node lookup etc. */
178 WStacking *mplex_find_stacking(WMPlex *mplex, WRegion *reg)
182 /* Some routines that call us expect us to this check. */
183 if(reg==NULL || REGION_MANAGER(reg)!=(WRegion*)mplex)
186 st=ioncore_find_stacking(reg);
188 assert(st==NULL || st->mgr_prev!=NULL);
194 WStacking *mplex_current_node(WMPlex *mplex)
199 reg=REGION_ACTIVE_SUB(mplex);
200 reg=region_managed_within((WRegion*)mplex, reg);
202 st=mplex_find_stacking(mplex, reg);
207 return (mplex->mx_current!=NULL ? mplex->mx_current->st : NULL);
211 WRegion *mplex_current(WMPlex *mplex)
213 WStacking *node=mplex_current_node(mplex);
214 return (node==NULL ? NULL : node->reg);
221 /*{{{ Exclusive list management and exports */
224 * Returns the number of objects on the mutually exclusive list of \var{mplex}.
228 int mplex_mx_count(WMPlex *mplex)
230 return mplex->mx_count;
235 * Returns the managed object currently active within the mutually exclusive
236 * list of \var{mplex}.
240 WRegion *mplex_mx_current(WMPlex *mplex)
242 WLListNode *lnode=mplex->mx_current;
243 return (lnode==NULL ? NULL : lnode->st->reg);
248 * Returns the \var{n}:th object managed by \var{mplex} on the
253 WRegion *mplex_mx_nth(WMPlex *mplex, uint n)
255 WLListNode *lnode=llist_nth_node(mplex->mx_list, n);
256 return (lnode==NULL ? NULL : lnode->st->reg);
261 * Iterate over numbered/mutually exclusive region list of \var{mplex}
262 * until \var{iterfn} returns \code{false}.
263 * The function itself returns \code{true} if it reaches the end of list
264 * without this happening.
268 bool mplex_mx_i(WMPlex *mplex, ExtlFn iterfn)
271 llist_iter_init(&tmp, mplex->mx_list);
273 return extl_iter_objlist_(iterfn, (ObjIterator*)llist_iter_regions, &tmp);
278 * Iterate over managed regions of \var{mplex} until \var{iterfn} returns
280 * The function itself returns \code{true} if it reaches the end of list
281 * without this happening.
285 bool mplex_managed_i(WMPlex *mplex, ExtlFn iterfn)
288 mplex_iter_init(&tmp, mplex);
290 return extl_iter_objlist_(iterfn, (ObjIterator*)mplex_iter, &tmp);
295 * Set index of \var{reg} within the multiplexer to \var{index} within
296 * the mutually exclusive list. Special values for \var{index} are:
297 * \begin{tabularx}{\linewidth}{lX}
299 * $-2$ & After \fnref{WMPlex.mx_current}. \\
303 void mplex_set_index(WMPlex *mplex, WRegion *reg, int index)
305 WLListNode *lnode, *after;
308 node=mplex_find_stacking(mplex, reg);
316 lnode=ALLOC(WLListNode);
326 mplex_move_phs_before(mplex, lnode);
327 llist_unlink(&(mplex->mx_list), lnode);
330 /* TODO: Support remove? */
332 after=llist_index_to_after(mplex->mx_list, mplex->mx_current, index);
333 llist_link_after(&(mplex->mx_list), after, lnode);
334 mplex_managed_changed(mplex, MPLEX_CHANGE_REORDER, FALSE, reg);
339 * Get index of \var{reg} within the multiplexer on list 1. The first region
340 * managed by \var{mplex} has index zero. If \var{reg} is not managed by
341 * \var{mplex}, -1 is returned.
345 int mplex_get_index(WMPlex *mplex, WRegion *reg)
351 FOR_ALL_NODES_ON_LLIST(lnode, mplex->mx_list, tmp){
352 if(reg==lnode->st->reg)
362 * Move \var{r} ''right'' within objects managed by \var{mplex} on list 1.
365 void mplex_inc_index(WMPlex *mplex, WRegion *r)
368 r=mplex_mx_current(mplex);
370 mplex_set_index(mplex, r, mplex_get_index(mplex, r)+1);
375 * Move \var{r} ''right'' within objects managed by \var{mplex} on list 1.
378 void mplex_dec_index(WMPlex *mplex, WRegion *r)
381 r=mplex_mx_current(mplex);
383 mplex_set_index(mplex, r, mplex_get_index(mplex, r)-1);
393 static void mplex_map_mgd(WMPlex *mplex)
398 FOR_ALL_NODES_IN_MPLEX(mplex, node, tmp){
399 if(!STACKING_IS_HIDDEN(node))
400 region_map(node->reg);
405 static void mplex_unmap_mgd(WMPlex *mplex)
410 FOR_ALL_NODES_IN_MPLEX(mplex, node, tmp){
411 if(!STACKING_IS_HIDDEN(node))
412 region_unmap(node->reg);
418 void mplex_map(WMPlex *mplex)
420 window_map((WWindow*)mplex);
421 /* A lame requirement of the ICCCM is that client windows should be
422 * unmapped if the parent is unmapped.
424 if(!MPLEX_MGD_UNVIEWABLE(mplex))
425 mplex_map_mgd(mplex);
429 void mplex_unmap(WMPlex *mplex)
431 window_unmap((WWindow*)mplex);
432 /* A lame requirement of the ICCCM is that client windows should be
433 * unmapped if the parent is unmapped.
435 if(!MPLEX_MGD_UNVIEWABLE(mplex))
436 mplex_unmap_mgd(mplex);
443 /*{{{ Resize and reparent */
446 bool mplex_fitrep(WMPlex *mplex, WWindow *par, const WFitParams *fp)
448 bool wchg=(REGION_GEOM(mplex).w!=fp->g.w);
449 bool hchg=(REGION_GEOM(mplex).h!=fp->g.h);
451 window_do_fitrep(&(mplex->win), par, &(fp->g));
454 mplex_fit_managed(mplex);
455 mplex_size_changed(mplex, wchg, hchg);
462 void mplex_do_fit_managed(WMPlex *mplex, WFitParams *fp)
469 if(!MPLEX_MGD_UNVIEWABLE(mplex) && (fp->g.w<=1 || fp->g.h<=1)){
470 mplex->flags|=MPLEX_MANAGED_UNVIEWABLE;
471 if(REGION_IS_MAPPED(mplex))
472 mplex_unmap_mgd(mplex);
473 }else if(MPLEX_MGD_UNVIEWABLE(mplex) && !(fp->g.w<=1 || fp->g.h<=1)){
474 mplex->flags&=~MPLEX_MANAGED_UNVIEWABLE;
475 if(REGION_IS_MAPPED(mplex))
476 mplex_map_mgd(mplex);
479 if(!MPLEX_MGD_UNVIEWABLE(mplex)){
480 FOR_ALL_NODES_IN_MPLEX(mplex, node, tmp){
482 sizepolicy(&node->szplcy, node->reg, NULL, 0, &fp2);
483 region_fitrep(node->reg, NULL, &fp2);
489 void mplex_fit_managed(WMPlex *mplex)
493 fp.mode=REGION_FIT_EXACT;
494 mplex_managed_geom(mplex, &(fp.g));
496 mplex_do_fit_managed(mplex, &fp);
500 static void mplex_managed_rqgeom(WMPlex *mplex, WRegion *sub,
501 const WRQGeomParams *rq,
508 node=mplex_find_stacking(mplex, sub);
512 mplex_managed_geom(mplex, &fp.g);
514 sizepolicy(&node->szplcy, sub, &rq->geom, rq->flags, &fp);
519 if(!(rq->flags®ION_RQGEOM_TRYONLY))
520 region_fitrep(sub, NULL, &fp);
530 static WRegion *mplex_do_to_focus(WMPlex *mplex, WStacking *to_try)
532 WStacking *stacking=mplex_get_stacking(mplex);
538 if(to_try!=NULL && (to_try->reg==NULL || !REGION_IS_MAPPED(to_try->reg)))
541 st=stacking_find_to_focus_mapped(stacking, to_try, NULL);
545 else if(mplex->mx_current!=NULL)
546 return mplex->mx_current->st->reg;
552 WRegion *mplex_to_focus(WMPlex *mplex)
554 WRegion *reg=REGION_ACTIVE_SUB(mplex);
555 WStacking *to_try=NULL;
558 to_try=ioncore_find_stacking(reg);
560 return mplex_do_to_focus(mplex, to_try);
564 static WRegion *mplex_do_to_focus_on(WMPlex *mplex, WStacking *node,
567 WStacking *stacking=mplex_get_stacking(mplex);
573 if(to_try!=NULL && (to_try->reg==NULL || !REGION_IS_MAPPED(to_try->reg)))
576 st=stacking_find_to_focus_mapped(stacking, to_try, node->reg);
578 return (st!=NULL ? st->reg : NULL);
582 static WRegion *mplex_to_focus_on(WMPlex *mplex, WStacking *node,
586 WGroup *grp=OBJ_CAST(node->reg, WGroup);
590 to_try=grp->current_managed;
591 reg=mplex_do_to_focus_on(mplex, node, to_try);
592 if(reg!=NULL || to_try!=NULL)
594 /* We don't know whether something is blocking focus here,
595 * or if there was nothing to focus (as node->reg itself
596 * isn't on the stacking list).
600 reg=mplex_do_to_focus(mplex, node);
601 return (reg==node->reg ? reg : NULL);
605 void mplex_do_set_focus(WMPlex *mplex, bool warp)
607 if(!MPLEX_MGD_UNVIEWABLE(mplex)){
608 WRegion *reg=mplex_to_focus(mplex);
611 region_do_set_focus(reg, warp);
616 window_do_set_focus((WWindow*)mplex, warp);
626 static void mplex_do_remanage_stdisp(WMPlex *mplex, WRegion *sub)
628 WRegion *stdisp=(WRegion*)(mplex->stdispwatch.obj);
631 if(sub!=NULL && CAN_MANAGE_STDISP(sub)){
633 WRegion *mgrw=region_managed_within((WRegion*)mplex, stdisp);
635 WRegion *mgr=REGION_MANAGER(stdisp);
637 if(CAN_MANAGE_STDISP(mgr))
638 region_unmanage_stdisp(mgr, FALSE, FALSE);
639 region_detach_manager(stdisp);
642 region_manage_stdisp(sub, stdisp,
643 &(mplex->stdispinfo));
646 region_unmanage_stdisp(sub, TRUE, FALSE);
648 }/*else if(stdisp!=NULL){
649 region_detach_manager(stdisp);
650 region_unmap(stdisp);
655 void mplex_remanage_stdisp(WMPlex *mplex)
657 mplex_do_remanage_stdisp(mplex, (mplex->mx_current!=NULL
658 ? mplex->mx_current->st->reg
663 static void mplex_do_node_display(WMPlex *mplex, WStacking *node,
666 WRegion *sub=node->reg;
667 WLListNode *mxc=mplex->mx_current;
669 if(!STACKING_IS_HIDDEN(node))
672 if(node->lnode!=NULL && node->lnode!=mxc)
673 mplex_do_remanage_stdisp(mplex, sub);
677 if(SUBS_MAY_BE_MAPPED(mplex))
682 if(node->lnode!=NULL){
684 /* Hide current mx region. We do it after mapping the
685 * new one to avoid flicker.
687 if(REGION_IS_MAPPED(mplex))
688 region_unmap(mxc->st->reg);
689 mxc->st->hidden=TRUE;
692 mplex->mx_current=node->lnode;
695 * Many programs will get upset if the visible, although only
696 * such, client window is not the lowest window in the mplex.
697 * xprop/xwininfo will return the information for the lowest
698 * window. 'netscape -remote' will not work at all if there are
699 * no visible netscape windows.
702 #warning "TODO: less ugly hack"
703 WGroup *grp=(WGroup*)OBJ_CAST(sub, WGroupCW);
704 if(grp!=NULL && grp->bottom!=NULL){
705 region_managed_rqorder((WRegion*)grp, grp->bottom->reg,
711 mplex_managed_changed(mplex, MPLEX_CHANGE_SWITCHONLY, TRUE, sub);
716 static bool mplex_refocus(WMPlex *mplex, WStacking *node, bool warp)
722 foc=mplex_to_focus_on(mplex, node, NULL);
728 foc=mplex_to_focus(mplex);
731 if(foc!=NULL /* && !REGION_IS_ACTIVE(foc) */ )
732 region_maybewarp(foc, warp);
738 bool mplex_do_prepare_focus(WMPlex *mplex, WStacking *node,
739 WStacking *sub, int flags,
740 WPrepareFocusResult *res)
744 if(sub==NULL && node==NULL)
747 /* Display the node in any case */
748 if(node!=NULL && !(flags®ION_GOTO_ENTERWINDOW))
749 mplex_do_node_display(mplex, node, TRUE);
751 if(!region_prepare_focus((WRegion*)mplex, flags, res))
755 foc=mplex_to_focus_on(mplex, node, sub);
757 foc=mplex_do_to_focus(mplex, sub);
764 return (foc==node->reg);
766 return (foc==sub->reg);
773 bool mplex_managed_prepare_focus(WMPlex *mplex, WRegion *disp,
774 int flags, WPrepareFocusResult *res)
776 WStacking *node=mplex_find_stacking(mplex, disp);
781 return mplex_do_prepare_focus(mplex, node, NULL, flags, res);
788 /*{{{ Switch exports */
791 static void do_switch(WMPlex *mplex, WLListNode *lnode)
793 WStacking *node=(lnode!=NULL ? lnode->st : NULL);
796 bool mcf=region_may_control_focus((WRegion*)mplex);
798 mplex_do_node_display(mplex, node, TRUE);
801 mplex_refocus(mplex, node, TRUE);
807 * Have \var{mplex} display the \var{n}:th object managed by it.
810 void mplex_switch_nth(WMPlex *mplex, uint n)
812 do_switch(mplex, llist_nth_node(mplex->mx_list, n));
817 * Have \var{mplex} display next (wrt. currently selected) object managed
821 void mplex_switch_next(WMPlex *mplex)
823 do_switch(mplex, LIST_NEXT_WRAP(mplex->mx_list, mplex->mx_current,
829 * Have \var{mplex} display previous (wrt. currently selected) object
833 void mplex_switch_prev(WMPlex *mplex)
835 do_switch(mplex, LIST_PREV_WRAP(mplex->mx_list, mplex->mx_current,
840 bool mplex_set_hidden(WMPlex *mplex, WRegion *reg, int sp)
842 bool mcf=region_may_control_focus((WRegion*)mplex);
843 WStacking *node=mplex_find_stacking(mplex, reg);
844 bool hidden, nhidden;
849 hidden=STACKING_IS_HIDDEN(node);
850 nhidden=libtu_do_setparam(sp, hidden);
852 if(!hidden && nhidden){
855 if(REGION_IS_MAPPED(mplex) && !MPLEX_MGD_UNVIEWABLE(mplex))
858 /* lnode -> switch next? */
859 }else if(hidden && !nhidden){
860 mplex_do_node_display(mplex, node, TRUE);
863 if(mcf && !PASSIVE(node))
864 mplex_refocus(mplex, (nhidden ? NULL : node), TRUE);
866 return STACKING_IS_HIDDEN(node);
871 * Set the visibility of the region \var{reg} on \var{mplex}
872 * as specified with the parameter \var{how} (set/unset/toggle).
873 * The resulting state is returned.
875 EXTL_EXPORT_AS(WMPlex, set_hidden)
876 bool mplex_set_hidden_extl(WMPlex *mplex, WRegion *reg, const char *how)
878 return mplex_set_hidden(mplex, reg, libtu_string_to_setparam(how));
883 * Is \var{reg} on within \var{mplex} and hidden?
887 bool mplex_is_hidden(WMPlex *mplex, WRegion *reg)
889 WStacking *node=mplex_find_stacking(mplex, reg);
891 return (node!=NULL && STACKING_IS_HIDDEN(node));
901 static WStacking *mplex_nxt(WMPlex *mplex, WStacking *st, bool wrap)
903 return (st->mgr_next!=NULL
905 : (wrap ? mplex->mgd : NULL));
909 static WStacking *mplex_prv(WMPlex *mplex, WStacking *st, bool wrap)
911 return (st!=mplex->mgd
913 : (wrap ? st->mgr_prev : NULL));
917 typedef WStacking *NxtFn(WMPlex *mplex, WStacking *st, bool wrap);
920 static WRegion *do_navi(WMPlex *mplex, WStacking *sti,
921 NxtFn *fn, WRegionNaviData *data,
922 bool sti_ok, bool wrap)
924 WStacking *st, *stacking;
927 stacking=mplex_get_stacking(mplex);
930 min_level=stacking_min_level_mapped(stacking);
934 st=fn(mplex, st, wrap);
936 if(st==NULL || (st==sti && !sti_ok))
940 if(OBJ_IS(st->reg, WGroup)){
941 /* WGroup navigation code should respect modal stuff. */
942 WRegion *res=region_navi_cont((WRegion*)mplex, st->reg, data);
947 #warning "TODO: What to do?"
951 if(st->level>=min_level && !PASSIVE(st))
952 return region_navi_cont((WRegion*)mplex, st->reg, data);
964 WRegion *mplex_navi_first(WMPlex *mplex, WRegionNavi nh,
965 WRegionNaviData *data)
967 WStacking *lst=mplex->mgd;
971 if(nh==REGION_NAVI_ANY){
975 if(nh==REGION_NAVI_ANY || nh==REGION_NAVI_END ||
976 nh==REGION_NAVI_BOTTOM || nh==REGION_NAVI_RIGHT){
977 res=do_navi(mplex, lst, mplex_prv, data, TRUE, TRUE);
979 res=do_navi(mplex, lst->mgr_prev, mplex_nxt, data, TRUE, TRUE);
983 return region_navi_cont((WRegion*)mplex, res, data);
987 WRegion *mplex_navi_next(WMPlex *mplex, WRegion *rel, WRegionNavi nh,
988 WRegionNaviData *data)
994 st=mplex_find_stacking(mplex, rel);
997 }else if(mplex->mx_current!=NULL){
998 st=mplex->mx_current->st;
1000 return mplex_navi_first(mplex, nh, data);
1003 if(nh==REGION_NAVI_ANY){
1007 if(nh==REGION_NAVI_ANY || nh==REGION_NAVI_END ||
1008 nh==REGION_NAVI_BOTTOM || nh==REGION_NAVI_RIGHT){
1009 res=do_navi(mplex, st, mplex_nxt, data, FALSE, FALSE);
1011 res=do_navi(mplex, st, mplex_prv, data, FALSE, FALSE);
1014 return region_navi_cont((WRegion*)mplex, res, data);
1024 bool mplex_managed_rqorder(WMPlex *mplex, WRegion *reg, WRegionOrder order)
1026 WStacking **stackingp=mplex_get_stackingp(mplex);
1029 if(stackingp==NULL || *stackingp==NULL)
1032 st=mplex_find_stacking(mplex, reg);
1037 stacking_restack(stackingp, st, None, NULL, NULL,
1038 (order!=REGION_ORDER_FRONT));
1050 static bool mplex_stack(WMPlex *mplex, WStacking *st)
1052 WStacking *tmp=NULL;
1053 Window bottom=None, top=None;
1054 WStacking **stackingp=mplex_get_stackingp(mplex);
1059 LINK_ITEM_FIRST(tmp, st, next, prev);
1060 stacking_weave(stackingp, &tmp, FALSE);
1067 static void mplex_unstack(WMPlex *mplex, WStacking *st)
1069 WStacking *stacking;
1071 stacking=mplex_get_stacking(mplex);
1073 stacking_unstack(&mplex->win, st);
1077 /* WMPlexWPHolder is used for position marking in order to allow
1078 * WLListNodes be safely removed in the attach handler hnd, that
1079 * could remove something this mplex is managing.
1081 bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph)
1083 WStacking *node=NULL;
1084 WLListNode *lnode=NULL;
1085 WMPlexAttachParams *param=&ph->param;
1086 bool mx_was_empty, sw, modal, mcf, hidden;
1089 mcf=region_may_control_focus((WRegion*)mplex);
1091 mx_was_empty=(mplex->mx_list==NULL);
1093 modal=(param->flags&MPLEX_ATTACH_LEVEL
1094 ? param->level>=STACKING_LEVEL_MODAL1
1095 : param->flags&MPLEX_ATTACH_MODAL);
1097 level=(param->flags&MPLEX_ATTACH_LEVEL
1099 : (param->flags&MPLEX_ATTACH_MODAL
1100 ? STACKING_LEVEL_MODAL1
1101 : (param->flags&MPLEX_ATTACH_UNNUMBERED
1102 ? STACKING_LEVEL_NORMAL
1103 : STACKING_LEVEL_BOTTOM)));
1105 hidden=(param->flags&MPLEX_ATTACH_HIDDEN
1106 && (param->flags&MPLEX_ATTACH_UNNUMBERED
1109 sw=(!hidden && (param->flags&MPLEX_ATTACH_SWITCHTO
1110 || (param->flags&MPLEX_ATTACH_UNNUMBERED
1112 : (mplex_current_node(mplex)==NULL))));
1114 hidden=(hidden || (!sw && !(param->flags&MPLEX_ATTACH_UNNUMBERED)));
1117 node=create_stacking();
1122 if(!(param->flags&MPLEX_ATTACH_UNNUMBERED)){
1123 lnode=ALLOC(WLListNode);
1125 stacking_free(node);
1135 if(!stacking_assoc(node, reg)){
1140 stacking_free(node);
1145 node->szplcy=param->szplcy;
1149 llist_link_after(&(mplex->mx_list),
1150 (ph!=NULL ? ph->after : NULL),
1154 /* Move following placeholders after new node */
1155 while(ph->next!=NULL)
1156 mplexpholder_move(ph->next, mplex, NULL, lnode);
1159 LINK_ITEM(mplex->mgd, node, mgr_next, mgr_prev);
1161 if(!OBJ_IS(reg, WGroup))
1162 mplex_stack(mplex, node);
1164 region_set_manager(reg, (WRegion*)mplex);
1167 mplex_do_node_display(mplex, node, FALSE);
1172 mplex_refocus(mplex, node, FALSE);
1175 mplex_managed_changed(mplex, MPLEX_CHANGE_ADD, sw, reg);
1181 WRegion *mplex_do_attach_pholder(WMPlex *mplex, WMPlexPHolder *ph,
1182 WRegionAttachData *data)
1184 WMPlexAttachParams *param=&(ph->param);
1185 WSizePolicy szplcy=param->szplcy;
1189 param->szplcy=(param->flags&MPLEX_ATTACH_SIZEPOLICY &&
1190 param->szplcy!=SIZEPOLICY_DEFAULT
1192 : (param->flags&MPLEX_ATTACH_UNNUMBERED
1193 ? SIZEPOLICY_FULL_BOUNDS
1194 : SIZEPOLICY_FULL_EXACT));
1196 mplex_managed_geom(mplex, &(fp.g));
1198 sizepolicy(¶m->szplcy, NULL,
1199 (param->flags&MPLEX_ATTACH_GEOM
1204 if(param->flags&MPLEX_ATTACH_WHATEVER)
1205 fp.mode|=REGION_FIT_WHATEVER;
1207 reg=region_attach_helper((WRegion*)mplex,
1208 (WWindow*)mplex, &fp,
1209 (WRegionDoAttachFn*)mplex_do_attach_final,
1213 ph->param.szplcy=szplcy;
1219 WRegion *mplex_do_attach(WMPlex *mplex, WMPlexAttachParams *param,
1220 WRegionAttachData *data)
1225 ph=create_mplexpholder(mplex, NULL, param);
1230 reg=mplex_do_attach_pholder(mplex, ph, data);
1232 destroy_obj((Obj*)ph);
1238 WRegion *mplex_do_attach_new(WMPlex *mplex, WMPlexAttachParams *param,
1239 WRegionCreateFn *fn, void *fn_param)
1241 WRegionAttachData data;
1243 data.type=REGION_ATTACH_NEW;
1245 data.u.n.param=fn_param;
1247 return mplex_do_attach(mplex, param, &data);
1251 #define MPLEX_ATTACH_SET_FLAGS (MPLEX_ATTACH_GEOM| \
1252 MPLEX_ATTACH_SIZEPOLICY| \
1256 WRegion *mplex_attach_simple(WMPlex *mplex, WRegion *reg, int flags)
1258 WMPlexAttachParams param;
1259 WRegionAttachData data;
1261 param.flags=flags&~MPLEX_ATTACH_SET_FLAGS;
1263 data.type=REGION_ATTACH_REPARENT;
1266 return mplex_do_attach(mplex, ¶m, &data);
1270 static void get_params(WMPlex *mplex, ExtlTab tab, int mask,
1271 WMPlexAttachParams *par)
1277 if(mask==0 && extl_table_gets_i(tab, "layer", &tmp)){
1278 /* backwards compatibility. No need to consider masked cases */
1280 par->flags|=MPLEX_ATTACH_UNNUMBERED;
1281 if(!extl_table_is_bool_set(tab, "passive"))
1282 par->flags|=MPLEX_ATTACH_MODAL;
1286 if(extl_table_gets_i(tab, "level", &tmp)){
1287 if(tmp>=0 && ok&MPLEX_ATTACH_LEVEL){
1288 par->flags|=MPLEX_ATTACH_LEVEL;
1293 if(extl_table_is_bool_set(tab, "modal"))
1294 par->flags|=MPLEX_ATTACH_MODAL&ok;
1296 if(extl_table_is_bool_set(tab, "unnumbered"))
1297 par->flags|=MPLEX_ATTACH_UNNUMBERED&ok;
1299 if(extl_table_is_bool_set(tab, "switchto"))
1300 par->flags|=MPLEX_ATTACH_SWITCHTO&ok;
1302 if(extl_table_is_bool_set(tab, "hidden"))
1303 par->flags|=MPLEX_ATTACH_HIDDEN&ok;
1305 if(extl_table_gets_i(tab, "index", &(par->index)))
1306 par->flags|=MPLEX_ATTACH_INDEX&ok;
1308 if(extl_table_gets_i(tab, "sizepolicy", &tmp)){
1309 if(ok&MPLEX_ATTACH_SIZEPOLICY){
1310 par->flags|=MPLEX_ATTACH_SIZEPOLICY;
1315 if(extl_table_gets_rectangle(tab, "geom", &par->geom))
1316 par->flags|=MPLEX_ATTACH_GEOM&ok;
1321 * Attach and reparent existing region \var{reg} to \var{mplex}.
1322 * The table \var{param} may contain the fields \var{index} and
1323 * \var{switchto} that are interpreted as for \fnref{WMPlex.attach_new}.
1326 WRegion *mplex_attach(WMPlex *mplex, WRegion *reg, ExtlTab param)
1328 WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
1329 WRegionAttachData data;
1334 get_params(mplex, param, 0, &par);
1336 data.type=REGION_ATTACH_REPARENT;
1339 return mplex_do_attach(mplex, &par, &data);
1343 WRegion *mplex_attach_new_(WMPlex *mplex, WMPlexAttachParams *par,
1344 int mask, ExtlTab param)
1346 WRegionAttachData data;
1348 get_params(mplex, param, mask, par);
1350 data.type=REGION_ATTACH_LOAD;
1353 return mplex_do_attach(mplex, par, &data);
1358 * Create a new region to be managed by \var{mplex}. At least the following
1359 * fields in \var{param} are understood (all but \var{type} are optional).
1361 * \begin{tabularx}{\linewidth}{lX}
1362 * \tabhead{Field & Description}
1363 * \var{type} & (string) Class name (a string) of the object to be created. \\
1364 * \var{name} & (string) Name of the object to be created (a string). \\
1365 * \var{switchto} & (boolean) Should the region be switched to (boolean)? \\
1366 * \var{unnumbered} & (boolean) Do not put on the numbered mutually
1367 * exclusive list. \\
1368 * \var{index} & (integer) Index on this list, same as for
1369 * \fnref{WMPlex.set_index}. \\
1370 * \var{level} & (integer) Stacking level. \\
1371 * \var{modal} & (boolean) Shortcut for modal stacking level. \\
1372 * \var{hidden} & (boolean) Attach hidden, if not prevented
1373 * by e.g. the mutually exclusive list being empty.
1374 * This option overrides \var{switchto}. \\
1375 * \var{sizepolicy} & (integer) Size policy.
1376 * (TODO: document them somewhere.) \\
1377 * \var{geom} & (table) Geometry specification. \\
1380 * In addition parameters to the region to be created are passed in this
1384 WRegion *mplex_attach_new(WMPlex *mplex, ExtlTab param)
1386 WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
1388 return mplex_attach_new_(mplex, &par, 0, param);
1393 * Attach all tagged regions to \var{mplex}.
1396 void mplex_attach_tagged(WMPlex *mplex)
1399 int flags=MPLEX_ATTACH_SWITCHTO;
1401 while((reg=ioncore_tagged_take_first())!=NULL){
1402 mplex_attach_simple(mplex, reg, flags);
1408 static bool mplex_handle_drop(WMPlex *mplex, int x, int y,
1411 WRegion *curr=mplex_mx_current(mplex);
1413 /* This code should handle dropping tabs on floating workspaces. */
1414 if(curr && HAS_DYN(curr, region_handle_drop)){
1416 region_rootpos(curr, &rx, &ry);
1417 if(rectangle_contains(®ION_GEOM(curr), x-rx, y-ry)){
1418 if(region_handle_drop(curr, x, y, dropped))
1423 return (NULL!=mplex_attach_simple(mplex, dropped, MPLEX_ATTACH_SWITCHTO));
1427 WPHolder *mplex_prepare_manage(WMPlex *mplex, const WClientWin *cwin,
1428 const WManageParams *param, int redir)
1430 WMPlexAttachParams ap;
1435 if(redir==MANAGE_REDIR_STRICT_YES || redir==MANAGE_REDIR_PREFER_YES){
1436 WStacking *cur=mplex_current_node(mplex);
1439 ph=region_prepare_manage(cur->reg, cwin, param,
1440 MANAGE_REDIR_PREFER_YES);
1445 if(mplex->mx_current!=NULL && mplex->mx_current->st!=cur){
1446 ph=region_prepare_manage(mplex->mx_current->st->reg,
1448 MANAGE_REDIR_PREFER_YES);
1454 if(redir==MANAGE_REDIR_STRICT_YES)
1457 ap.flags=((param->switchto ? MPLEX_ATTACH_SWITCHTO : 0)
1458 |MPLEX_ATTACH_SIZEPOLICY);
1459 ap.szplcy=SIZEPOLICY_FULL_BOUNDS;
1461 mph=create_mplexpholder(mplex, NULL, &ap);
1464 WGroupedPHolder *gph=create_groupedpholder((WPHolder*)mph);
1466 return (WPHolder*)gph;
1469 return (WPHolder*)mph;
1479 void mplex_managed_remove(WMPlex *mplex, WRegion *sub)
1481 bool mx=FALSE, hadfocus=FALSE, mcf;
1482 WRegion *stdisp=(WRegion*)(mplex->stdispwatch.obj);
1483 WStacking *node, *next=NULL;
1485 mcf=region_may_control_focus((WRegion*)mplex);
1488 if(CAN_MANAGE_STDISP(sub) &&
1489 region_managed_within((WRegion*)mplex, stdisp)==sub){
1490 region_unmanage_stdisp(sub, TRUE, TRUE);
1491 region_detach_manager(stdisp);
1495 node=mplex_find_stacking(mplex, sub);
1500 hadfocus=(mplex_current_node(mplex)==node);
1502 if(node->lnode!=NULL){
1503 if(mplex->mx_current==node->lnode){
1506 mplex->mx_current=NULL;
1507 lnext=LIST_PREV(mplex->mx_list, node->lnode, next, prev);
1509 lnext=LIST_NEXT(mplex->mx_list, node->lnode, next, prev);
1510 if(lnext==node->lnode)
1517 mplex_move_phs_before(mplex, node->lnode);
1518 llist_unlink(&(mplex->mx_list), node->lnode);
1526 UNLINK_ITEM(mplex->mgd, node, mgr_next, mgr_prev);
1528 mplex_unstack(mplex, node);
1530 stacking_unassoc(node);
1531 stacking_free(node);
1533 region_unset_manager(sub, (WRegion*)mplex);
1535 if(OBJ_IS_BEING_DESTROYED(mplex))
1539 mplex_do_node_display(mplex, next, FALSE);
1542 mplex_refocus(mplex, next, FALSE);
1545 mplex_managed_changed(mplex, MPLEX_CHANGE_REMOVE, next!=NULL, sub);
1549 bool mplex_rescue_clientwins(WMPlex *mplex, WPHolder *ph)
1554 mplex_iter_init(&tmp, mplex);
1555 ret1=region_rescue_some_clientwins((WRegion*)mplex, ph,
1556 (WRegionIterator*)mplex_iter,
1559 ret2=region_rescue_child_clientwins((WRegion*)mplex, ph);
1561 return (ret1 && ret2);
1566 void mplex_child_removed(WMPlex *mplex, WRegion *sub)
1568 if(sub!=NULL && sub==(WRegion*)(mplex->stdispwatch.obj)){
1569 watch_reset(&(mplex->stdispwatch));
1570 mplex_set_stdisp(mplex, NULL, NULL);
1578 /*{{{ Status display support */
1581 # define offsetof(T,F) ((size_t)((char*)&((T*)0L)->F-(char*)0L))
1584 #define STRUCTOF(T, F, FADDR) \
1585 ((T*)((char*)(FADDR)-offsetof(T, F)))
1588 static void stdisp_watch_handler(Watch *watch, Obj *obj)
1590 /*WMPlex *mplex=STRUCTOF(WMPlex, stdispinfo,
1591 STRUCTOF(WMPlexSTDispInfo, regwatch, watch));
1592 WMPlexSTDispInfo *di=&(mplex->stdispinfo);
1593 WGenWS *ws=OBJ_CAST(REGION_MANAGER(obj), WGenWS);
1595 if(ioncore_g.opmode!=IONCORE_OPMODE_DEINIT && ws!=NULL)
1596 genws_unmanage_stdisp(ws, TRUE, FALSE);*/
1600 bool mplex_set_stdisp(WMPlex *mplex, WRegion *reg,
1601 const WMPlexSTDispInfo *din)
1603 WRegion *oldstdisp=(WRegion*)(mplex->stdispwatch.obj);
1606 assert(reg==NULL || (reg==oldstdisp) ||
1607 (REGION_MANAGER(reg)==NULL &&
1608 REGION_PARENT(reg)==(WWindow*)mplex));
1610 if(oldstdisp!=NULL){
1611 mgr=region_managed_within((WRegion*)mplex, oldstdisp);
1613 if(!CAN_MANAGE_STDISP(mgr))
1618 mplex->stdispinfo=*din;
1621 watch_reset(&(mplex->stdispwatch));
1624 region_unmanage_stdisp(mgr, TRUE, FALSE);
1626 region_detach_manager(oldstdisp);
1629 watch_setup(&(mplex->stdispwatch), (Obj*)reg, stdisp_watch_handler);
1631 mplex_remanage_stdisp(mplex);
1634 if(oldstdisp!=NULL && oldstdisp!=reg)
1635 region_dispose((WRegion*)oldstdisp, FALSE);
1641 void mplex_get_stdisp(WMPlex *mplex, WRegion **reg, WMPlexSTDispInfo *di)
1643 *di=mplex->stdispinfo;
1644 *reg=(WRegion*)mplex->stdispwatch.obj;
1648 static StringIntMap pos_map[]={
1649 {"tl", MPLEX_STDISP_TL},
1650 {"tr", MPLEX_STDISP_TR},
1651 {"bl", MPLEX_STDISP_BL},
1652 {"br", MPLEX_STDISP_BR},
1657 static bool do_attach_stdisp(WRegion *mplex, WRegion *reg, void *unused)
1659 /* We do not actually manage the stdisp. */
1665 * Set/create status display for \var{mplex}. Table is a standard
1666 * description of the object to be created (as passed to e.g.
1667 * \fnref{WMPlex.attach_new}). In addition, the following fields are
1670 * \begin{tabularx}{\linewidth}{lX}
1671 * \tabhead{Field & Description}
1672 * \var{pos} & The corner of the screen to place the status display
1673 * in. One of \code{tl}, \code{tr}, \var{bl} or \var{br}. \\
1674 * \var{action} & If this field is set to \code{keep}, \var{corner}
1675 * and \var{orientation} are changed for the existing
1676 * status display. If this field is set to \var{remove},
1677 * the existing status display is removed. If this
1678 * field is not set or is set to \code{replace}, a
1679 * new status display is created and the old, if any,
1683 EXTL_EXPORT_AS(WMPlex, set_stdisp)
1684 WRegion *mplex_set_stdisp_extl(WMPlex *mplex, ExtlTab t)
1686 WRegion *stdisp=NULL;
1687 WMPlexSTDispInfo din=mplex->stdispinfo;
1690 if(extl_table_gets_s(t, "pos", &s)){
1691 din.pos=stringintmap_value(pos_map, s, -1);
1693 warn(TR("Invalid position setting."));
1698 extl_table_gets_b(t, "fullsize", &(din.fullsize));
1701 extl_table_gets_s(t, "action", &s);
1703 if(s==NULL || strcmp(s, "replace")==0){
1704 WRegionAttachData data;
1710 fp.g.w=REGION_GEOM(mplex).w;
1711 fp.g.h=REGION_GEOM(mplex).h;
1712 fp.mode=REGION_FIT_BOUNDS|REGION_FIT_WHATEVER;
1714 /* Full mplex size is stupid so use saved geometry initially
1717 extl_table_gets_rectangle(t, "geom", &(fp.g));
1719 data.type=REGION_ATTACH_LOAD;
1722 stdisp=region_attach_helper((WRegion*)mplex,
1723 (WWindow*)mplex, &fp,
1724 do_attach_stdisp, NULL,
1730 }else if(strcmp(s, "keep")==0){
1731 stdisp=(WRegion*)(mplex->stdispwatch.obj);
1732 }else if(strcmp(s, "remove")!=0){
1733 warn(TR("Invalid action setting."));
1737 if(!mplex_set_stdisp(mplex, stdisp, &din)){
1738 destroy_obj((Obj*)stdisp);
1746 static ExtlTab mplex_do_get_stdisp_extl(WMPlex *mplex, bool fullconfig)
1748 WRegion *reg=(WRegion*)mplex->stdispwatch.obj;
1752 return extl_table_none();
1755 t=region_get_configuration(reg);
1756 extl_table_sets_rectangle(t, "geom", ®ION_GEOM(reg));
1758 t=extl_create_table();
1759 extl_table_sets_o(t, "reg", (Obj*)reg);
1762 if(t!=extl_table_none()){
1763 WMPlexSTDispInfo *di=&(mplex->stdispinfo);
1764 extl_table_sets_s(t, "pos", stringintmap_key(pos_map, di->pos, NULL));
1765 extl_table_sets_b(t, "fullsize", di->fullsize);
1772 * Get status display information. See \fnref{WMPlex.get_stdisp} for
1773 * information on the fields.
1776 EXTL_EXPORT_AS(WMPlex, get_stdisp)
1777 ExtlTab mplex_get_stdisp_extl(WMPlex *mplex)
1779 return mplex_do_get_stdisp_extl(mplex, FALSE);
1789 void mplex_managed_geom_default(const WMPlex *mplex, WRectangle *geom)
1793 geom->w=REGION_GEOM(mplex).w;
1794 geom->h=REGION_GEOM(mplex).h;
1798 void mplex_managed_geom(const WMPlex *mplex, WRectangle *geom)
1800 CALL_DYN(mplex_managed_geom, mplex, (mplex, geom));
1804 void mplex_size_changed(WMPlex *mplex, bool wchg, bool hchg)
1806 CALL_DYN(mplex_size_changed, mplex, (mplex, wchg, hchg));
1810 void mplex_managed_changed(WMPlex *mplex, int mode, bool sw, WRegion *mgd)
1812 CALL_DYN(mplex_managed_changed, mplex, (mplex, mode, sw, mgd));
1816 int mplex_default_index(WMPlex *mplex)
1818 int idx=LLIST_INDEX_LAST;
1819 CALL_DYN_RET(idx, int, mplex_default_index, mplex, (mplex));
1824 /* For regions managing stdisps */
1826 void region_manage_stdisp(WRegion *reg, WRegion *stdisp,
1827 const WMPlexSTDispInfo *info)
1829 CALL_DYN(region_manage_stdisp, reg, (reg, stdisp, info));
1833 void region_unmanage_stdisp(WRegion *reg, bool permanent, bool nofocus)
1835 CALL_DYN(region_unmanage_stdisp, reg, (reg, permanent, nofocus));
1842 /*{{{ Changed hook helper */
1845 static const char *mode2str(int mode)
1847 if(mode==MPLEX_CHANGE_SWITCHONLY)
1848 return "switchonly";
1849 else if(mode==MPLEX_CHANGE_REORDER)
1851 else if(mode==MPLEX_CHANGE_ADD)
1853 else if(mode==MPLEX_CHANGE_REMOVE)
1859 static bool mrsh_chg(ExtlFn fn, WMPlexChangedParams *p)
1861 ExtlTab t=extl_create_table();
1864 extl_table_sets_o(t, "reg", (Obj*)p->reg);
1865 extl_table_sets_s(t, "mode", mode2str(p->mode));
1866 extl_table_sets_b(t, "sw", p->sw);
1867 extl_table_sets_o(t, "sub", (Obj*)p->sub);
1870 ret=extl_call(fn, "t", NULL, t);
1871 extl_unprotect(NULL);
1873 extl_unref_table(t);
1879 void mplex_call_changed_hook(WMPlex *mplex, WHook *hook,
1880 int mode, bool sw, WRegion *reg)
1882 WMPlexChangedParams p;
1889 hook_call_p(hook, &p, (WHookMarshallExtl*)mrsh_chg);
1899 static void save_node(WMPlex *mplex, ExtlTab subs, int *n,
1900 WStacking *node, bool unnumbered)
1904 st=region_get_configuration(node->reg);
1906 if(st!=extl_table_none()){
1907 /*"TODO: better switchto saving? */
1908 if(mplex->mx_current!=NULL && node==mplex->mx_current->st)
1909 extl_table_sets_b(st, "switchto", TRUE);
1910 extl_table_sets_i(st, "sizepolicy", node->szplcy);
1911 extl_table_sets_i(st, "level", node->level);
1912 g=extl_table_from_rectangle(®ION_GEOM(node->reg));
1913 extl_table_sets_t(st, "geom", g);
1914 extl_unref_table(g);
1915 if(STACKING_IS_HIDDEN(node))
1916 extl_table_sets_b(st, "hidden", TRUE);
1918 extl_table_sets_b(st, "unnumbered", TRUE);
1920 extl_table_seti_t(subs, ++(*n), st);
1921 extl_unref_table(st);
1926 ExtlTab mplex_get_configuration(WMPlex *mplex)
1928 ExtlTab tab, subs, stdisptab;
1935 tab=region_get_base_configuration((WRegion*)mplex);
1937 subs=extl_create_table();
1938 extl_table_sets_t(tab, "managed", subs);
1940 /* First the numbered/mutually exclusive nodes */
1941 FOR_ALL_NODES_ON_LLIST(lnode, mplex->mx_list, ltmp){
1942 save_node(mplex, subs, &n, lnode->st, FALSE);
1945 FOR_ALL_NODES_IN_MPLEX(mplex, node, tmp){
1946 if(node->lnode==NULL)
1947 save_node(mplex, subs, &n, node, TRUE);
1950 extl_unref_table(subs);
1952 /*stdisptab=mplex_do_get_stdisp_extl(mplex, TRUE);
1953 if(stdisptab!=extl_table_none()){
1954 extl_table_sets_t(tab, "stdisp", stdisptab);
1955 extl_unref_table(stdisptab);
1962 static WMPlex *tmp_mplex=NULL;
1963 static WMPlexAttachParams *tmp_par=NULL;
1965 static WPHolder *pholder_callback()
1967 assert(tmp_mplex!=NULL);
1968 return (WPHolder*)create_mplexpholder(tmp_mplex, NULL, tmp_par);
1972 void mplex_load_contents(WMPlex *mplex, ExtlTab tab)
1974 ExtlTab substab, subtab;
1977 /*if(extl_table_gets_t(tab, "stdisp", &subtab)){
1978 mplex_set_stdisp_extl(mplex, subtab);
1979 extl_unref_table(subtab);
1982 if(extl_table_gets_t(tab, "managed", &substab) ||
1983 extl_table_gets_t(tab, "subs", &substab)){
1984 n=extl_table_get_n(substab);
1985 for(i=1; i<=n; i++){
1986 if(extl_table_geti_t(substab, i, &subtab)){
1987 /*mplex_attach_new(mplex, subtab);*/
1988 WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT;
1989 WRegionAttachData data;
1992 get_params(mplex, subtab, 0, &par);
1994 par.flags|=MPLEX_ATTACH_INDEX;
1995 par.index=LLIST_INDEX_LAST;
2000 data.type=REGION_ATTACH_LOAD;
2003 ioncore_set_sm_pholder_callback(pholder_callback);
2005 mplex_do_attach(mplex, &par, &data);
2009 extl_unref_table(subtab);
2012 extl_unref_table(substab);
2017 WRegion *mplex_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
2019 WMPlex *mplex=create_mplex(par, fp);
2021 mplex_load_contents(mplex, tab);
2022 return (WRegion*)mplex;
2029 /*{{{ Dynfuntab and class info */
2032 static DynFunTab mplex_dynfuntab[]={
2033 {region_do_set_focus,
2034 mplex_do_set_focus},
2036 {region_managed_remove,
2037 mplex_managed_remove},
2039 {region_managed_rqgeom,
2040 mplex_managed_rqgeom},
2042 {(DynFun*)region_managed_prepare_focus,
2043 (DynFun*)mplex_managed_prepare_focus},
2045 {(DynFun*)region_handle_drop,
2046 (DynFun*)mplex_handle_drop},
2048 {region_map, mplex_map},
2049 {region_unmap, mplex_unmap},
2051 {(DynFun*)region_prepare_manage,
2052 (DynFun*)mplex_prepare_manage},
2054 {(DynFun*)region_current,
2055 (DynFun*)mplex_current},
2057 {(DynFun*)region_rescue_clientwins,
2058 (DynFun*)mplex_rescue_clientwins},
2060 {(DynFun*)region_get_configuration,
2061 (DynFun*)mplex_get_configuration},
2063 {mplex_managed_geom,
2064 mplex_managed_geom_default},
2066 {(DynFun*)region_fitrep,
2067 (DynFun*)mplex_fitrep},
2069 {region_child_removed,
2070 mplex_child_removed},
2072 {(DynFun*)region_managed_get_pholder,
2073 (DynFun*)mplex_managed_get_pholder},
2075 {(DynFun*)region_get_rescue_pholder_for,
2076 (DynFun*)mplex_get_rescue_pholder_for},
2078 {(DynFun*)region_may_destroy,
2079 (DynFun*)mplex_may_destroy},
2081 {(DynFun*)region_navi_first,
2082 (DynFun*)mplex_navi_first},
2084 {(DynFun*)region_navi_next,
2085 (DynFun*)mplex_navi_next},
2087 {(DynFun*)region_managed_rqorder,
2088 (DynFun*)mplex_managed_rqorder},
2095 IMPLCLASS(WMPlex, WWindow, mplex_deinit, mplex_dynfuntab);