X-Git-Url: https://git.decadent.org.uk/gitweb/?p=ion3.git;a=blobdiff_plain;f=ioncore%2Fmplex.c;h=5f0a87d3a5a8bd2cfe6786c42bd2ca32b977758c;hp=a202e7c51672b0565baacfb03f95539d230d3eb8;hb=HEAD;hpb=803afbc1cd633f6c025bcd9537e9b7e9aedadd0d diff --git a/ioncore/mplex.c b/ioncore/mplex.c index a202e7c..5f0a87d 100644 --- a/ioncore/mplex.c +++ b/ioncore/mplex.c @@ -1,12 +1,9 @@ /* * ion/ioncore/mplex.c * - * Copyright (c) Tuomo Valkonen 1999-2007. + * Copyright (c) Tuomo Valkonen 1999-2009. * - * Ion is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * See the included file LICENSE for details. */ #include @@ -36,13 +33,13 @@ #include "saveload.h" #include "xwindow.h" #include "mplexpholder.h" +#include "grouppholder.h" #include "llist.h" #include "names.h" #include "sizepolicy.h" #include "stacking.h" #include "group.h" #include "navi.h" -#include "groupedpholder.h" #define SUBS_MAY_BE_MAPPED(MPLEX) \ @@ -101,7 +98,7 @@ bool mplex_do_init(WMPlex *mplex, WWindow *parent, mplex->mx_list=NULL; mplex->mx_current=NULL; - mplex->mx_phs=NULL; + mplex->misc_phs=NULL; mplex->mx_count=0; mplex->mgd=NULL; @@ -150,25 +147,14 @@ void mplex_deinit(WMPlex *mplex) assert(mplex->mgd==NULL); assert(mplex->mx_list==NULL); - while(mplex->mx_phs!=NULL){ - assert(mplexpholder_move(mplex->mx_phs, NULL, NULL, NULL)); + while(mplex->misc_phs!=NULL){ + assert(mplexpholder_move(mplex->misc_phs, NULL, NULL, NULL)); } window_deinit((WWindow*)mplex); } -bool mplex_may_destroy(WMPlex *mplex) -{ - if(mplex->mgd!=NULL){ - warn(TR("Refusing to destroy - not empty.")); - return FALSE; - } - - return TRUE; -} - - /*}}}*/ @@ -245,8 +231,8 @@ WRegion *mplex_mx_current(WMPlex *mplex) /*EXTL_DOC - * Returns the \var{n}:th object managed by \var{mplex} on the - * \var{l}:th layer. + * Returns the \var{n}:th object on the mutually exclusive + * list of \var{mplex}. */ EXTL_SAFE EXTL_EXPORT_MEMBER @@ -260,7 +246,8 @@ WRegion *mplex_mx_nth(WMPlex *mplex, uint n) /*EXTL_DOC * Iterate over numbered/mutually exclusive region list of \var{mplex} * until \var{iterfn} returns \code{false}. - * The function itself returns \code{true} if it reaches the end of list + * The function is called in protected mode. + * This routine returns \code{true} if it reaches the end of list * without this happening. */ EXTL_SAFE @@ -277,7 +264,8 @@ bool mplex_mx_i(WMPlex *mplex, ExtlFn iterfn) /*EXTL_DOC * Iterate over managed regions of \var{mplex} until \var{iterfn} returns * \code{false}. - * The function itself returns \code{true} if it reaches the end of list + * The function is called in protected mode. + * This routine returns \code{true} if it reaches the end of list * without this happening. */ EXTL_SAFE @@ -292,8 +280,8 @@ bool mplex_managed_i(WMPlex *mplex, ExtlFn iterfn) /*EXTL_DOC - * Set index of \var{reg} within the multiplexer to \var{index} within - * the mutually exclusive list. Special values for \var{index} are: + * Set index of \var{reg} to \var{index} within the mutually exclusive + * list of \var{mplex}. Special values for \var{index} are: * \begin{tabularx}{\linewidth}{lX} * $-1$ & Last. \\ * $-2$ & After \fnref{WMPlex.mx_current}. \\ @@ -327,8 +315,6 @@ void mplex_set_index(WMPlex *mplex, WRegion *reg, int index) llist_unlink(&(mplex->mx_list), lnode); } - /* TODO: Support remove? */ - after=llist_index_to_after(mplex->mx_list, mplex->mx_current, index); llist_link_after(&(mplex->mx_list), after, lnode); mplex_managed_changed(mplex, MPLEX_CHANGE_REORDER, FALSE, reg); @@ -336,9 +322,9 @@ void mplex_set_index(WMPlex *mplex, WRegion *reg, int index) /*EXTL_DOC - * Get index of \var{reg} within the multiplexer on list 1. The first region - * managed by \var{mplex} has index zero. If \var{reg} is not managed by - * \var{mplex}, -1 is returned. + * Get index of \var{reg} on the mutually exclusive list of \var{mplex}. + * The indices begin from zero.. If \var{reg} is not on the list, + * -1 is returned. */ EXTL_SAFE EXTL_EXPORT_MEMBER @@ -359,7 +345,7 @@ int mplex_get_index(WMPlex *mplex, WRegion *reg) /*EXTL_DOC - * Move \var{r} ''right'' within objects managed by \var{mplex} on list 1. + * Move \var{r} ``right'' within objects managed by \var{mplex} on list 1. */ EXTL_EXPORT_MEMBER void mplex_inc_index(WMPlex *mplex, WRegion *r) @@ -372,7 +358,7 @@ void mplex_inc_index(WMPlex *mplex, WRegion *r) /*EXTL_DOC - * Move \var{r} ''right'' within objects managed by \var{mplex} on list 1. + * Move \var{r} ``left'' within objects managed by \var{mplex} on list 1. */ EXTL_EXPORT_MEMBER void mplex_dec_index(WMPlex *mplex, WRegion *r) @@ -448,7 +434,8 @@ bool mplex_fitrep(WMPlex *mplex, WWindow *par, const WFitParams *fp) bool wchg=(REGION_GEOM(mplex).w!=fp->g.w); bool hchg=(REGION_GEOM(mplex).h!=fp->g.h); - window_do_fitrep(&(mplex->win), par, &(fp->g)); + if(!window_fitrep(&(mplex->win), par, fp)) + return FALSE; if(wchg || hchg){ mplex_fit_managed(mplex); @@ -508,9 +495,10 @@ static void mplex_managed_rqgeom(WMPlex *mplex, WRegion *sub, node=mplex_find_stacking(mplex, sub); assert(node!=NULL); - + + fp.mode=0; mplex_managed_geom(mplex, &fp.g); - + sizepolicy(&node->szplcy, sub, &rq->geom, rq->flags, &fp); if(geomret!=NULL) @@ -521,94 +509,238 @@ static void mplex_managed_rqgeom(WMPlex *mplex, WRegion *sub, } +void mplex_set_szplcy(WMPlex *mplex, WRegion *sub, WSizePolicy szplcy) +{ + WStacking *node; + + node=mplex_find_stacking(mplex, sub); + + if(node!=NULL) + node->szplcy=szplcy; +} + + +WSizePolicy mplex_get_szplcy(WMPlex *mplex, WRegion *sub) +{ + WStacking *node; + + node=mplex_find_stacking(mplex, sub); + + return (node==NULL ? SIZEPOLICY_DEFAULT : node->szplcy); +} + + /*}}}*/ /*{{{ Focus */ -static WRegion *mplex_do_to_focus(WMPlex *mplex, WStacking *to_try) +typedef struct{ + WMPlex *mplex; + WStacking *to_try; + WStacking *group_st; + PtrList **hidelist; + bool try_hard; +} FiltData; + + +static WRegion *manager_within(WMPlex *mplex, WStacking *st) { - WStacking *stacking=mplex_get_stacking(mplex); - WStacking *st=NULL; - - if(stacking==NULL) - return NULL; + return region_managed_within((WRegion*)mplex, st->reg); +} - if(to_try!=NULL && (to_try->reg==NULL || !REGION_IS_MAPPED(to_try->reg))) - to_try=NULL; - st=stacking_find_to_focus_mapped(stacking, to_try, NULL); +static WStacking *stacking_within(WMPlex *mplex, WStacking *st) +{ + WRegion *reg=manager_within(mplex, st); - if(st!=NULL) - return st->reg; - else if(mplex->mx_current!=NULL) - return mplex->mx_current->st->reg; - else - return NULL; + return (reg==NULL + ? NULL + : (reg==st->reg + ? st + : ioncore_find_stacking(reg))); } -WRegion *mplex_to_focus(WMPlex *mplex) +/* Mutually exclusive regions can't be pseudomodal */ +#define IS_PSEUDOMODAL(ST) ((ST)->lnode==NULL && (ST)->pseudomodal) + + +static bool mapped_pseudomodal_include_filt(WStacking *st, void *data_) { - WRegion *reg=REGION_ACTIVE_SUB(mplex); - WStacking *to_try=NULL; + FiltData *data=(FiltData*)data_; + WStacking *stw; - if(reg!=NULL) - to_try=ioncore_find_stacking(reg); + if(st->reg==NULL || !REGION_IS_MAPPED(st->reg)) + return FALSE; + + if(!data->hidelist + || (data->to_try==NULL && data->group_st==NULL) + || st->levelmplex, st); + + /* This should not happen */ + if(stw==NULL || stw->reg==NULL) + return FALSE; + + /* The node is within the same group, so it can not be hidden. + * Latter case should not happen. + */ + if(stw==data->group_st || stw==data->to_try) + return TRUE; + + if(IS_PSEUDOMODAL(stw)){ + /* Don't insert multiple times. */ + return !ptrlist_reinsert_first(data->hidelist, stw); + } + + return TRUE; +} + - return mplex_do_to_focus(mplex, to_try); +static bool mgr_pseudomodal_approve_filt(WStacking *st, void *data_) +{ + FiltData *data=(FiltData*)data_; + + return (data->group_st==NULL || st==data->group_st || + manager_within(data->mplex, st)==data->group_st->reg); } -static WRegion *mplex_do_to_focus_on(WMPlex *mplex, WStacking *node, - WStacking *to_try) +WStacking *mplex_find_to_focus(WMPlex *mplex, + WStacking *to_try, + WStacking *group_st, + PtrList **hidelist) { + WStackingFilter *fi=mapped_pseudomodal_include_filt; + WStackingFilter *fa=mgr_pseudomodal_approve_filt; WStacking *stacking=mplex_get_stacking(mplex); - WStacking *st=NULL; + FiltData data; + WStacking *st; if(stacking==NULL) return NULL; - + if(to_try!=NULL && (to_try->reg==NULL || !REGION_IS_MAPPED(to_try->reg))) to_try=NULL; - st=stacking_find_to_focus_mapped(stacking, to_try, node->reg); + data.mplex=mplex; + data.to_try=to_try; + data.group_st=group_st; + data.hidelist=hidelist; - return (st!=NULL ? st->reg : NULL); + st=stacking_find_to_focus(stacking, to_try, fi, fa, &data); + + if(st==NULL && hidelist!=NULL) + ptrlist_clear(hidelist); + + return st; } -static WRegion *mplex_to_focus_on(WMPlex *mplex, WStacking *node, - WStacking *to_try) +static WStacking *mplex_do_to_focus_on(WMPlex *mplex, WStacking *node, + WStacking *to_try, + PtrList **hidelist, bool *within) { - WRegion *reg; WGroup *grp=OBJ_CAST(node->reg, WGroup); + WStacking *st; if(grp!=NULL){ if(to_try==NULL) to_try=grp->current_managed; - reg=mplex_do_to_focus_on(mplex, node, to_try); - if(reg!=NULL || to_try!=NULL) - return reg; - /* We don't know whether something is blocking focus here, - * or if there was nothing to focus (as node->reg itself - * isn't on the stacking list). - */ + /* Only will return stuff within 'node' */ + st=mplex_find_to_focus(mplex, to_try, node, hidelist); + if(st!=NULL){ + if(within!=NULL) + *within=TRUE; + return st; + } + } + + st=mplex_find_to_focus(mplex, node, NULL, hidelist); + + /* If 'node' points to a group, it isn't actually on the stacking list. + * Give it the focus, if there's nothing "proper" that could be focussed. + */ + if(st==NULL && grp!=NULL && REGION_IS_MAPPED(grp)) + st=node; + + if(st==node && within!=NULL) + *within=TRUE; + + return st; +} + + +static WStacking *maybe_focusable(WRegion *reg) +{ + if(reg==NULL || !REGION_IS_MAPPED(reg)) + return NULL; + + return ioncore_find_stacking(reg); +} + + +static WStacking *has_stacking_within(WMPlex *mplex, WRegion *reg) +{ + while(reg!=NULL && REGION_MANAGER(reg)!=(WRegion*)mplex) + reg=REGION_MANAGER(reg); + + return maybe_focusable(reg); +} + + +/* 1. Try keep focus in REGION_ACTIVE_SUB. + * 2. Choose something else, attempting previous in focus history. + */ +static WStacking *mplex_to_focus(WMPlex *mplex) +{ + WStacking *foc=NULL, *fallback=NULL; + WRegion *reg=NULL; + + foc=maybe_focusable(REGION_ACTIVE_SUB(mplex)); + + if(foc==NULL){ + /* Search focus history if no specific attempt set.*/ + for(reg=ioncore_g.focus_current; reg!=NULL; reg=reg->active_next){ + foc=has_stacking_within(mplex, reg); + if(foc!=NULL) + break; + } } - reg=mplex_do_to_focus(mplex, node); - return (reg==node->reg ? reg : NULL); + if(foc!=NULL){ + /* In the history search case, 'foc' might point to a group, + * since we don't properly try to find a stacking within it... + */ + return mplex_do_to_focus_on(mplex, foc, NULL, NULL, NULL); + }else{ + return mplex_find_to_focus(mplex, NULL, NULL, NULL); + } } void mplex_do_set_focus(WMPlex *mplex, bool warp) { if(!MPLEX_MGD_UNVIEWABLE(mplex)){ - WRegion *reg=mplex_to_focus(mplex); + WStacking *st=mplex_to_focus(mplex); - if(reg!=NULL){ - region_do_set_focus(reg, warp); + if(st==NULL){ + st=(mplex->mx_current!=NULL + ? mplex->mx_current->st + : NULL); + } + + if(st!=NULL){ + region_do_set_focus(st->reg, warp); return; } } @@ -617,6 +749,22 @@ void mplex_do_set_focus(WMPlex *mplex, bool warp) } +static void mplex_refocus(WMPlex *mplex, WStacking *node, bool warp) +{ + bool within=FALSE; + WStacking *foc=NULL; + + if(node!=NULL) + foc=mplex_do_to_focus_on(mplex, node, NULL, NULL, &within); + + if(foc==NULL || !within) + foc=mplex_to_focus(mplex); + + if(foc!=NULL) + region_maybewarp(foc->reg, warp); +} + + /*}}}*/ @@ -630,25 +778,19 @@ static void mplex_do_remanage_stdisp(WMPlex *mplex, WRegion *sub) /* Move stdisp */ if(sub!=NULL && CAN_MANAGE_STDISP(sub)){ if(stdisp!=NULL){ - WRegion *mgrw=region_managed_within((WRegion*)mplex, stdisp); - if(mgrw!=sub){ - WRegion *mgr=REGION_MANAGER(stdisp); - if(mgr!=NULL){ - if(CAN_MANAGE_STDISP(mgr)) - region_unmanage_stdisp(mgr, FALSE, FALSE); - region_detach_manager(stdisp); - } - - region_manage_stdisp(sub, stdisp, - &(mplex->stdispinfo)); + WRegion *omgr=REGION_MANAGER(stdisp); + if(omgr!=sub && omgr!=NULL){ + if(CAN_MANAGE_STDISP(omgr)) + region_unmanage_stdisp(omgr, FALSE, FALSE); + region_detach_manager(stdisp); } + + region_manage_stdisp(sub, stdisp, + &(mplex->stdispinfo)); }else{ region_unmanage_stdisp(sub, TRUE, FALSE); } - }/*else if(stdisp!=NULL){ - region_detach_manager(stdisp); - region_unmap(stdisp); - }*/ + } } @@ -699,11 +841,13 @@ static void mplex_do_node_display(WMPlex *mplex, WStacking *node, * no visible netscape windows. */ { - #warning "TODO: less ugly hack" WGroup *grp=(WGroup*)OBJ_CAST(sub, WGroupCW); - if(grp!=NULL && grp->bottom!=NULL){ - region_managed_rqorder((WRegion*)grp, grp->bottom->reg, - REGION_ORDER_BACK); + if(grp!=NULL){ + WRegion *bottom=group_bottom(grp); + if(bottom!=NULL){ + region_managed_rqorder((WRegion*)grp, bottom, + REGION_ORDER_BACK); + } } } @@ -713,57 +857,46 @@ static void mplex_do_node_display(WMPlex *mplex, WStacking *node, } -static bool mplex_refocus(WMPlex *mplex, WStacking *node, bool warp) -{ - WRegion *foc=NULL; - bool ret=TRUE; - - if(node!=NULL){ - foc=mplex_to_focus_on(mplex, node, NULL); - ret=(foc!=NULL); - } - - if(foc==NULL){ - ret=FALSE; - foc=mplex_to_focus(mplex); - } - - if(foc!=NULL /* && !REGION_IS_ACTIVE(foc) */ ) - region_maybewarp(foc, warp); - - return ret; -} - - bool mplex_do_prepare_focus(WMPlex *mplex, WStacking *node, WStacking *sub, int flags, WPrepareFocusResult *res) { - WRegion *foc; + bool ew=(flags®ION_GOTO_ENTERWINDOW); + PtrList *hidelist=NULL; + PtrList **hidelistp=(ew ? NULL : &hidelist); + WStacking *foc; + /*bool within=FALSE;*/ if(sub==NULL && node==NULL) return FALSE; /* Display the node in any case */ - if(node!=NULL && !(flags®ION_GOTO_ENTERWINDOW)) + if(node!=NULL && !ew) mplex_do_node_display(mplex, node, TRUE); if(!region_prepare_focus((WRegion*)mplex, flags, res)) return FALSE; - if(node!=NULL) - foc=mplex_to_focus_on(mplex, node, sub); - else - foc=mplex_do_to_focus(mplex, sub); + foc=mplex_do_to_focus_on(mplex, node, sub, hidelistp, NULL /*&within*/); if(foc!=NULL){ - res->reg=foc; + while(hidelist!=NULL){ + WStacking *st=(WStacking*)ptrlist_take_first(&hidelist); + st->hidden=TRUE; + region_unmap(st->reg); + } + + if(ioncore_g.autoraise && + !(flags®ION_GOTO_ENTERWINDOW) && + foc->level>STACKING_LEVEL_BOTTOM){ + WStacking **stackingp=mplex_get_stackingp(mplex); + stacking_restack(stackingp, foc, None, NULL, NULL, FALSE); + } + + res->reg=foc->reg; res->flags=flags; - if(sub==NULL) - return (foc==node->reg); - else - return (foc==sub->reg); + return (foc==sub || (sub==NULL && foc==node)); }else{ return FALSE; } @@ -869,7 +1002,8 @@ bool mplex_set_hidden(WMPlex *mplex, WRegion *reg, int sp) /*EXTL_DOC * Set the visibility of the region \var{reg} on \var{mplex} - * as specified with the parameter \var{how} (set/unset/toggle). + * as specified with the parameter \var{how} + * (one of \codestr{set}, \codestr{unset}, or \codestr{toggle}). * The resulting state is returned. */ EXTL_EXPORT_AS(WMPlex, set_hidden) @@ -940,13 +1074,8 @@ static WRegion *do_navi(WMPlex *mplex, WStacking *sti, if(OBJ_IS(st->reg, WGroup)){ /* WGroup navigation code should respect modal stuff. */ WRegion *res=region_navi_cont((WRegion*)mplex, st->reg, data); - if(res!=NULL){ - if(res!=st->reg){ - return res; - }else{ - #warning "TODO: What to do?" - } - } + if(res!=NULL && res!=st->reg) + return res; }else{ if(st->level>=min_level && !PASSIVE(st)) return region_navi_cont((WRegion*)mplex, st->reg, data); @@ -1050,7 +1179,6 @@ bool mplex_managed_rqorder(WMPlex *mplex, WRegion *reg, WRegionOrder order) static bool mplex_stack(WMPlex *mplex, WStacking *st) { WStacking *tmp=NULL; - Window bottom=None, top=None; WStacking **stackingp=mplex_get_stackingp(mplex); if(stackingp==NULL) @@ -1084,23 +1212,28 @@ bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph) WLListNode *lnode=NULL; WMPlexAttachParams *param=&ph->param; bool mx_was_empty, sw, modal, mcf, hidden; + WSizePolicy szplcy; uint level; mcf=region_may_control_focus((WRegion*)mplex); mx_was_empty=(mplex->mx_list==NULL); + szplcy=((param->flags&MPLEX_ATTACH_SIZEPOLICY && + param->szplcy!=SIZEPOLICY_DEFAULT) + ? param->szplcy + : (param->flags&MPLEX_ATTACH_UNNUMBERED + ? SIZEPOLICY_FULL_BOUNDS + : SIZEPOLICY_FULL_EXACT)); + modal=(param->flags&MPLEX_ATTACH_LEVEL - ? param->level>=STACKING_LEVEL_MODAL1 - : param->flags&MPLEX_ATTACH_MODAL); + && param->level>=STACKING_LEVEL_MODAL1); level=(param->flags&MPLEX_ATTACH_LEVEL ? param->level - : (param->flags&MPLEX_ATTACH_MODAL - ? STACKING_LEVEL_MODAL1 - : (param->flags&MPLEX_ATTACH_UNNUMBERED - ? STACKING_LEVEL_NORMAL - : STACKING_LEVEL_BOTTOM))); + : (param->flags&MPLEX_ATTACH_UNNUMBERED + ? STACKING_LEVEL_NORMAL + : STACKING_LEVEL_BOTTOM)); hidden=(param->flags&MPLEX_ATTACH_HIDDEN && (param->flags&MPLEX_ATTACH_UNNUMBERED @@ -1108,12 +1241,11 @@ bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph) sw=(!hidden && (param->flags&MPLEX_ATTACH_SWITCHTO || (param->flags&MPLEX_ATTACH_UNNUMBERED - ? modal + ? FALSE : (mplex_current_node(mplex)==NULL)))); hidden=(hidden || (!sw && !(param->flags&MPLEX_ATTACH_UNNUMBERED))); - node=create_stacking(); if(node==NULL) @@ -1142,18 +1274,24 @@ bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph) } node->hidden=TRUE; - node->szplcy=param->szplcy; + node->szplcy=szplcy; node->level=level; + node->pseudomodal=(param->flags&MPLEX_ATTACH_PSEUDOMODAL ? 1 : 0); if(lnode!=NULL){ + WMPlexPHolder *ph2, *phn, *php; + llist_link_after(&(mplex->mx_list), (ph!=NULL ? ph->after : NULL), lnode); mplex->mx_count++; - /* Move following placeholders after new node */ - while(ph->next!=NULL) - mplexpholder_move(ph->next, mplex, NULL, lnode); + + /* Move placeholders after new node */ + for(php=NULL, ph2=ph; ph2!=NULL; php=ph2, ph2=phn){ + phn=ph2->next; + mplexpholder_move(ph2, mplex, php, lnode); + } } LINK_ITEM(mplex->mgd, node, mgr_next, mgr_prev); @@ -1163,13 +1301,45 @@ bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph) region_set_manager(reg, (WRegion*)mplex); + if(param->flags&MPLEX_ATTACH_PASSIVE) + reg->flags|=REGION_SKIP_FOCUS; + + if(!(param->flags&MPLEX_ATTACH_WHATEVER)){ + WFitParams fp; + + fp.mode=0; + mplex_managed_geom(mplex, &(fp.g)); + + sizepolicy(&node->szplcy, reg, + (param->flags&MPLEX_ATTACH_GEOM ? &(param->geom) : NULL), + 0, &fp); + + if(rectangle_compare(&fp.g, ®ION_GEOM(reg))!=RECTANGLE_SAME) + region_fitrep(reg, NULL, &fp); + } + if(!hidden) mplex_do_node_display(mplex, node, FALSE); else region_unmap(reg); - - if(sw && mcf) - mplex_refocus(mplex, node, FALSE); + + if(mcf){ + if(sw){ + mplex_refocus(mplex, node, FALSE); + }else if(!hidden && + (level>=STACKING_LEVEL_MODAL1 || OBJ_IS(reg, WGroup))){ + /* New modal regions may require focusing, so try to + * give focus back to currently active object. + * (There seems to be some problem with uncontained + * client windows still..) + */ + mplex_refocus(mplex, NULL, FALSE); + }else if(!hidden){ + region_pointer_focus_hack(reg); + } + }else if(!hidden){ + region_pointer_focus_hack(reg); + } if(lnode!=NULL) mplex_managed_changed(mplex, MPLEX_CHANGE_ADD, sw, reg); @@ -1178,41 +1348,29 @@ bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph) } +static void mplex_attach_fp(WMPlex *mplex, const WMPlexAttachParams *param, + WFitParams *fp) +{ + if(param->flags&MPLEX_ATTACH_GEOM) + fp->g=param->geom; + else + mplex_managed_geom(mplex, &(fp->g)); + + fp->mode=REGION_FIT_WHATEVER|REGION_FIT_BOUNDS; +} + + WRegion *mplex_do_attach_pholder(WMPlex *mplex, WMPlexPHolder *ph, WRegionAttachData *data) { - WMPlexAttachParams *param=&(ph->param); - WSizePolicy szplcy=param->szplcy; WFitParams fp; - WRegion *reg; - param->szplcy=(param->flags&MPLEX_ATTACH_SIZEPOLICY && - param->szplcy!=SIZEPOLICY_DEFAULT - ? param->szplcy - : (param->flags&MPLEX_ATTACH_UNNUMBERED - ? SIZEPOLICY_FULL_BOUNDS - : SIZEPOLICY_FULL_EXACT)); + mplex_attach_fp(mplex, &ph->param, &fp); - mplex_managed_geom(mplex, &(fp.g)); - - sizepolicy(¶m->szplcy, NULL, - (param->flags&MPLEX_ATTACH_GEOM - ? &(param->geom) - : NULL), - 0, &fp); - - if(param->flags&MPLEX_ATTACH_WHATEVER) - fp.mode|=REGION_FIT_WHATEVER; - - reg=region_attach_helper((WRegion*)mplex, - (WWindow*)mplex, &fp, - (WRegionDoAttachFn*)mplex_do_attach_final, - (void*)ph, data); - - /* restore */ - ph->param.szplcy=szplcy; - - return reg; + return region_attach_helper((WRegion*)mplex, + (WWindow*)mplex, &fp, + (WRegionDoAttachFn*)mplex_do_attach_final, + (void*)ph, data); } @@ -1270,28 +1428,21 @@ WRegion *mplex_attach_simple(WMPlex *mplex, WRegion *reg, int flags) static void get_params(WMPlex *mplex, ExtlTab tab, int mask, WMPlexAttachParams *par) { - int layer=1; int tmp; + char *tmpstr; int ok=~mask; - if(mask==0 && extl_table_gets_i(tab, "layer", &tmp)){ - /* backwards compatibility. No need to consider masked cases */ - if(tmp==2){ - par->flags|=MPLEX_ATTACH_UNNUMBERED; - if(!extl_table_is_bool_set(tab, "passive")) - par->flags|=MPLEX_ATTACH_MODAL; - } - } - - if(extl_table_gets_i(tab, "level", &tmp)){ - if(tmp>=0 && ok&MPLEX_ATTACH_LEVEL){ - par->flags|=MPLEX_ATTACH_LEVEL; - par->level=tmp; + if(ok&MPLEX_ATTACH_LEVEL){ + if(extl_table_gets_i(tab, "level", &tmp)){ + if(tmp>=0){ + par->flags|=MPLEX_ATTACH_LEVEL; + par->level=tmp; + } } - } - if(extl_table_is_bool_set(tab, "modal")) - par->flags|=MPLEX_ATTACH_MODAL&ok; + if(extl_table_is_bool_set(tab, "modal")) + par->level=maxof(par->level, STACKING_LEVEL_MODAL1); + } if(extl_table_is_bool_set(tab, "unnumbered")) par->flags|=MPLEX_ATTACH_UNNUMBERED&ok; @@ -1301,12 +1452,26 @@ static void get_params(WMPlex *mplex, ExtlTab tab, int mask, if(extl_table_is_bool_set(tab, "hidden")) par->flags|=MPLEX_ATTACH_HIDDEN&ok; + + if(extl_table_is_bool_set(tab, "passive")) + par->flags|=MPLEX_ATTACH_PASSIVE&ok; + + if(extl_table_is_bool_set(tab, "pseudomodal")) + par->flags|=MPLEX_ATTACH_PSEUDOMODAL&ok; if(extl_table_gets_i(tab, "index", &(par->index))) par->flags|=MPLEX_ATTACH_INDEX&ok; - if(extl_table_gets_i(tab, "sizepolicy", &tmp)){ - if(ok&MPLEX_ATTACH_SIZEPOLICY){ + if(ok&MPLEX_ATTACH_SIZEPOLICY){ + if(extl_table_gets_s(tab, "sizepolicy", &tmpstr)){ + WSizePolicy tmpp; + if(string2sizepolicy(tmpstr, &tmpp)){ + par->flags|=MPLEX_ATTACH_SIZEPOLICY; + par->szplcy=tmpp; + } + free(tmpstr); + }else if(extl_table_gets_i(tab, "sizepolicy", &tmp)){ + /* Backwards compat. numeric version */ par->flags|=MPLEX_ATTACH_SIZEPOLICY; par->szplcy=tmp; } @@ -1372,8 +1537,12 @@ WRegion *mplex_attach_new_(WMPlex *mplex, WMPlexAttachParams *par, * \var{hidden} & (boolean) Attach hidden, if not prevented * by e.g. the mutually exclusive list being empty. * This option overrides \var{switchto}. \\ - * \var{sizepolicy} & (integer) Size policy. - * (TODO: document them somewhere.) \\ + * \var{passive} & (boolean) Skip in certain focusing operations. \\ + * \var{pseudomodal} & (boolean) The attached region is ``pseudomodal'' + * if the stacking level dictates it to be modal. + * This means that the region may be hidden to display + * regions with lesser stacking levels. \\ + * \var{sizepolicy} & (string) Size policy; see Section \ref{sec:sizepolicies}. \\ * \var{geom} & (table) Geometry specification. \\ * \end{tabularx} * @@ -1389,22 +1558,6 @@ WRegion *mplex_attach_new(WMPlex *mplex, ExtlTab param) } -/*EXTL_DOC - * Attach all tagged regions to \var{mplex}. - */ -EXTL_EXPORT_MEMBER -void mplex_attach_tagged(WMPlex *mplex) -{ - WRegion *reg; - int flags=MPLEX_ATTACH_SWITCHTO; - - while((reg=ioncore_tagged_take_first())!=NULL){ - mplex_attach_simple(mplex, reg, flags); - /*flags=0;*/ - } -} - - static bool mplex_handle_drop(WMPlex *mplex, int x, int y, WRegion *dropped) { @@ -1425,45 +1578,54 @@ static bool mplex_handle_drop(WMPlex *mplex, int x, int y, WPHolder *mplex_prepare_manage(WMPlex *mplex, const WClientWin *cwin, - const WManageParams *param, int redir) + const WManageParams *param, int priority) { + int cpriority=MANAGE_PRIORITY_SUB(priority, MANAGE_PRIORITY_NORMAL); WMPlexAttachParams ap; WPHolder *ph=NULL; WMPlexPHolder *mph; WLListNode *after; - if(redir==MANAGE_REDIR_STRICT_YES || redir==MANAGE_REDIR_PREFER_YES){ + /* Check current */ { WStacking *cur=mplex_current_node(mplex); if(cur!=NULL){ - ph=region_prepare_manage(cur->reg, cwin, param, - MANAGE_REDIR_PREFER_YES); + ph=region_prepare_manage(cur->reg, cwin, param, cpriority); if(ph!=NULL) return ph; } if(mplex->mx_current!=NULL && mplex->mx_current->st!=cur){ ph=region_prepare_manage(mplex->mx_current->st->reg, - cwin, param, - MANAGE_REDIR_PREFER_YES); + cwin, param, cpriority); if(ph!=NULL) return ph; } } - if(redir==MANAGE_REDIR_STRICT_YES) + if(!MANAGE_PRIORITY_OK(priority, MANAGE_PRIORITY_NORMAL)) return NULL; ap.flags=((param->switchto ? MPLEX_ATTACH_SWITCHTO : 0) |MPLEX_ATTACH_SIZEPOLICY); - ap.szplcy=SIZEPOLICY_FULL_BOUNDS; + ap.szplcy=SIZEPOLICY_FULL_EXACT; mph=create_mplexpholder(mplex, NULL, &ap); if(mph!=NULL){ - WGroupedPHolder *gph=create_groupedpholder((WPHolder*)mph); - if(gph!=NULL) + WGroupPHolder *gph; + WGroupAttachParams gp=GROUPATTACHPARAMS_INIT; + + gp.switchto_set=1; + gp.switchto=1; + gp.bottom=1; + + gph=create_grouppholder(NULL, NULL, &gp); + + if(gph!=NULL){ + gph->recreate_pholder=(WPHolder*)mph; return (WPHolder*)gph; + } } return (WPHolder*)mph; @@ -1546,56 +1708,56 @@ void mplex_managed_remove(WMPlex *mplex, WRegion *sub) } -bool mplex_rescue_clientwins(WMPlex *mplex, WPHolder *ph) +void mplex_child_removed(WMPlex *mplex, WRegion *sub) +{ + if(sub!=NULL && sub==(WRegion*)(mplex->stdispwatch.obj)){ + watch_reset(&(mplex->stdispwatch)); + mplex_set_stdisp(mplex, NULL, NULL); + } +} + + +/*}}}*/ + + +/*{{{ Rescue */ + + +bool mplex_rescue_clientwins(WMPlex *mplex, WRescueInfo *info) { bool ret1, ret2; WMPlexIterTmp tmp; + WLListIterTmp ltmp; + WLListNode *lnode, *was_current=mplex->mx_current; + + + /* First all mx stuff to move them nicely to another mplex (when that + * is the case), switching to the current region in the target if + * allowed by ph_flags_mask region_rescue. + */ + FOR_ALL_NODES_ON_LLIST(lnode, mplex->mx_list, ltmp){ + int sw=(lnode==was_current ? PHOLDER_ATTACH_SWITCHTO : 0); + region_do_rescue_this(lnode->st->reg, info, sw); + } + /* Then the rest (possibly retrying failed mx stuff). + */ mplex_iter_init(&tmp, mplex); - ret1=region_rescue_some_clientwins((WRegion*)mplex, ph, + ret1=region_rescue_some_clientwins((WRegion*)mplex, info, (WRegionIterator*)mplex_iter, &tmp); - ret2=region_rescue_child_clientwins((WRegion*)mplex, ph); + ret2=region_rescue_child_clientwins((WRegion*)mplex, info); return (ret1 && ret2); } - -void mplex_child_removed(WMPlex *mplex, WRegion *sub) -{ - if(sub!=NULL && sub==(WRegion*)(mplex->stdispwatch.obj)){ - watch_reset(&(mplex->stdispwatch)); - mplex_set_stdisp(mplex, NULL, NULL); - } -} - - /*}}}*/ /*{{{ Status display support */ -#ifndef offsetof -# define offsetof(T,F) ((size_t)((char*)&((T*)0L)->F-(char*)0L)) -#endif - -#define STRUCTOF(T, F, FADDR) \ - ((T*)((char*)(FADDR)-offsetof(T, F))) - - -static void stdisp_watch_handler(Watch *watch, Obj *obj) -{ - /*WMPlex *mplex=STRUCTOF(WMPlex, stdispinfo, - STRUCTOF(WMPlexSTDispInfo, regwatch, watch)); - WMPlexSTDispInfo *di=&(mplex->stdispinfo); - WGenWS *ws=OBJ_CAST(REGION_MANAGER(obj), WGenWS); - * - if(ioncore_g.opmode!=IONCORE_OPMODE_DEINIT && ws!=NULL) - genws_unmanage_stdisp(ws, TRUE, FALSE);*/ -} - bool mplex_set_stdisp(WMPlex *mplex, WRegion *reg, const WMPlexSTDispInfo *din) @@ -1626,13 +1788,13 @@ bool mplex_set_stdisp(WMPlex *mplex, WRegion *reg, region_detach_manager(oldstdisp); } }else{ - watch_setup(&(mplex->stdispwatch), (Obj*)reg, stdisp_watch_handler); + watch_setup(&(mplex->stdispwatch), (Obj*)reg, NULL); mplex_remanage_stdisp(mplex); } if(oldstdisp!=NULL && oldstdisp!=reg) - region_dispose((WRegion*)oldstdisp, FALSE); + mainloop_defer_destroy((Obj*)oldstdisp); return TRUE; } @@ -1669,13 +1831,15 @@ static bool do_attach_stdisp(WRegion *mplex, WRegion *reg, void *unused) * * \begin{tabularx}{\linewidth}{lX} * \tabhead{Field & Description} - * \var{pos} & The corner of the screen to place the status display - * in. One of \code{tl}, \code{tr}, \var{bl} or \var{br}. \\ - * \var{action} & If this field is set to \code{keep}, \var{corner} - * and \var{orientation} are changed for the existing - * status display. If this field is set to \var{remove}, + * \var{pos} & (string) The corner of the screen to place the status + * display in: one of \codestr{tl}, \codestr{tr}, \codestr{bl} + * or \codestr{br}. \\ + * \var{fullsize} & (boolean) Waste all available space. \\ + * \var{action} & (string) If this field is set to \codestr{keep}, + * \var{pos} and \var{fullsize} are changed for the existing + * status display. If this field is set to \codestr{remove}, * the existing status display is removed. If this - * field is not set or is set to \code{replace}, a + * field is not set or is set to \codestr{replace}, a * new status display is created and the old, if any, * removed. \\ * \end{tabularx} @@ -1718,7 +1882,7 @@ WRegion *mplex_set_stdisp_extl(WMPlex *mplex, ExtlTab t) data.type=REGION_ATTACH_LOAD; data.u.tab=t; - + stdisp=region_attach_helper((WRegion*)mplex, (WWindow*)mplex, &fp, do_attach_stdisp, NULL, @@ -1904,16 +2068,18 @@ static void save_node(WMPlex *mplex, ExtlTab subs, int *n, st=region_get_configuration(node->reg); if(st!=extl_table_none()){ - /*"TODO: better switchto saving? */ if(mplex->mx_current!=NULL && node==mplex->mx_current->st) extl_table_sets_b(st, "switchto", TRUE); - extl_table_sets_i(st, "sizepolicy", node->szplcy); + extl_table_sets_s(st, "sizepolicy", + sizepolicy2string(node->szplcy)); extl_table_sets_i(st, "level", node->level); g=extl_table_from_rectangle(®ION_GEOM(node->reg)); extl_table_sets_t(st, "geom", g); extl_unref_table(g); if(STACKING_IS_HIDDEN(node)) extl_table_sets_b(st, "hidden", TRUE); + if(STACKING_IS_PSEUDOMODAL(node)) + extl_table_sets_b(st, "pseudomodal", TRUE); if(unnumbered) extl_table_sets_b(st, "unnumbered", TRUE); @@ -1959,16 +2125,6 @@ ExtlTab mplex_get_configuration(WMPlex *mplex) } -static WMPlex *tmp_mplex=NULL; -static WMPlexAttachParams *tmp_par=NULL; - -static WPHolder *pholder_callback() -{ - assert(tmp_mplex!=NULL); - return (WPHolder*)create_mplexpholder(tmp_mplex, NULL, tmp_par); -} - - void mplex_load_contents(WMPlex *mplex, ExtlTab tab) { ExtlTab substab, subtab; @@ -1984,27 +2140,26 @@ void mplex_load_contents(WMPlex *mplex, ExtlTab tab) n=extl_table_get_n(substab); for(i=1; i<=n; i++){ if(extl_table_geti_t(substab, i, &subtab)){ - /*mplex_attach_new(mplex, subtab);*/ WMPlexAttachParams par=MPLEXATTACHPARAMS_INIT; - WRegionAttachData data; - char *tmp=NULL; + WFitParams fp; + WPHolder *ph; get_params(mplex, subtab, 0, &par); + mplex_attach_fp(mplex, &par, &fp); par.flags|=MPLEX_ATTACH_INDEX; par.index=LLIST_INDEX_LAST; - tmp_par=∥ - tmp_mplex=mplex; + ph=(WPHolder*)create_mplexpholder(mplex, NULL, &par); - data.type=REGION_ATTACH_LOAD; - data.u.tab=subtab; - - ioncore_set_sm_pholder_callback(pholder_callback); - - mplex_do_attach(mplex, &par, &data); - - tmp_mplex=NULL; + if(ph!=NULL){ + region_attach_load_helper((WRegion*)mplex, (WWindow*)mplex, &fp, + (WRegionDoAttachFn*)mplex_do_attach_final, + (void*)ph, subtab, &ph); + + if(ph!=NULL) + destroy_obj((Obj*)ph); + } extl_unref_table(subtab); } @@ -2075,9 +2230,6 @@ static DynFunTab mplex_dynfuntab[]={ {(DynFun*)region_get_rescue_pholder_for, (DynFun*)mplex_get_rescue_pholder_for}, - {(DynFun*)region_may_destroy, - (DynFun*)mplex_may_destroy}, - {(DynFun*)region_navi_first, (DynFun*)mplex_navi_first},