X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=ioncore%2Fmplex.c;h=013917615513532b7740835337589b4c91fa8e4f;hb=7c392448b0d2efcc6bb959063dcaa8b2c5ea0964;hp=28dc48a1a58fe92a18ba812c3afb35ea92894fc3;hpb=768d45580fc176cedd04db0b05621cdf596751d5;p=ion3.git diff --git a/ioncore/mplex.c b/ioncore/mplex.c index 28dc48a..0139176 100644 --- a/ioncore/mplex.c +++ b/ioncore/mplex.c @@ -3,10 +3,7 @@ * * Copyright (c) Tuomo Valkonen 1999-2007. * - * 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 @@ -234,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 @@ -346,7 +343,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) @@ -359,7 +356,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) @@ -514,84 +511,126 @@ static void mplex_managed_rqgeom(WMPlex *mplex, WRegion *sub, /*{{{ Focus */ -static WStacking *mplex_do_to_focus(WMPlex *mplex, WStacking *to_try) -{ - WStacking *stacking=mplex_get_stacking(mplex); - WStacking *st=NULL; - - if(stacking==NULL) - return NULL; +typedef struct{ + WMPlex *mplex; + WStacking *to_try; + WStacking *group_st; + PtrList **hidelist; + bool try_hard; +} FiltData; - 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); - - if(st!=NULL) - return st; - else if(mplex->mx_current!=NULL) - return mplex->mx_current->st; - else - return NULL; -} - - -static WStacking *maybe_focusable(WRegion *reg) +static WRegion *manager_within(WMPlex *mplex, WStacking *st) { - if(reg==NULL || !REGION_IS_MAPPED(reg)) - return NULL; - - return ioncore_find_stacking(reg); + return region_managed_within((WRegion*)mplex, st->reg); } -static WStacking *stacking_within(WMPlex *mplex, WRegion *reg) +static WStacking *stacking_within(WMPlex *mplex, WStacking *st) { - while(reg!=NULL && REGION_MANAGER(reg)!=(WRegion*)mplex) - reg=REGION_MANAGER(reg); + WRegion *reg=manager_within(mplex, st); - return maybe_focusable(reg); + return (reg==NULL + ? NULL + : (reg==st->reg + ? st + : ioncore_find_stacking(reg))); } -static WStacking *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_) { - WStacking *to_try=NULL; - WRegion *reg=NULL; + FiltData *data=(FiltData*)data_; + WStacking *stw; - to_try=maybe_focusable(REGION_ACTIVE_SUB(mplex)); + if(st->reg==NULL || !REGION_IS_MAPPED(st->reg)) + return FALSE; + + if(!data->hidelist + || (data->to_try==NULL && data->group_st==NULL) + || st->levelactive_next){ - to_try=stacking_within(mplex, reg); - if(to_try!=NULL) - break; - } + /* Ok, modal node in the way. Let's see if it is pseudomodal + * and can be hidden. + */ + + stw=stacking_within(data->mplex, 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; +} + + +static bool mgr_pseudomodal_approve_filt(WStacking *st, void *data_) +{ + FiltData *data=(FiltData*)data_; - return mplex_do_to_focus(mplex, to_try); + return (data->group_st==NULL || st==data->group_st || + manager_within(data->mplex, st)==data->group_st->reg); } -static WStacking *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; - return 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; + + st=stacking_find_to_focus(stacking, to_try, fi, fa, &data); + + if(st==NULL && hidelist!=NULL) + ptrlist_clear(hidelist); + + return st; } -static WStacking *mplex_to_focus_on(WMPlex *mplex, WStacking *node, - WStacking *to_try) +static WStacking *mplex_do_to_focus(WMPlex *mplex, WStacking *to_try, + PtrList **hidelist) +{ + return mplex_find_to_focus(mplex, to_try, NULL, hidelist); +} + + +static WStacking *mplex_do_to_focus_on(WMPlex *mplex, WStacking *node, + WStacking *to_try, + PtrList **hidelist) { WGroup *grp=OBJ_CAST(node->reg, WGroup); WStacking *st; @@ -599,17 +638,71 @@ static WStacking *mplex_to_focus_on(WMPlex *mplex, WStacking *node, if(grp!=NULL){ if(to_try==NULL) to_try=grp->current_managed; - st=mplex_do_to_focus_on(mplex, node, to_try); + st=mplex_find_to_focus(mplex, to_try, node, hidelist); if(st!=NULL || to_try!=NULL) return st; + if(hidelist!=NULL) + ptrlist_clear(hidelist); /* 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). */ } - st=mplex_do_to_focus(mplex, node); - return (st==node ? st : NULL); + st=mplex_do_to_focus(mplex, node, hidelist); + + if(st==node) + return st; + + if(hidelist!=NULL) + ptrlist_clear(hidelist); + + return NULL; +} + + +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); +} + + +static WStacking *mplex_to_focus(WMPlex *mplex) +{ + WStacking *to_try=NULL; + WRegion *reg=NULL; + WStacking *st; + + to_try=maybe_focusable(REGION_ACTIVE_SUB(mplex)); + + if(to_try==NULL){ + /* Search focus history */ + for(reg=ioncore_g.focus_current; reg!=NULL; reg=reg->active_next){ + to_try=has_stacking_within(mplex, reg); + if(to_try!=NULL) + break; + } + } + + st=mplex_do_to_focus(mplex, to_try, NULL); + + return (st!=NULL + ? st + : (mplex->mx_current!=NULL + ? mplex->mx_current->st + : NULL)); } @@ -726,7 +819,7 @@ static bool mplex_refocus(WMPlex *mplex, WStacking *node, bool warp) bool ret=TRUE; if(node!=NULL){ - foc=mplex_to_focus_on(mplex, node, NULL); + foc=mplex_do_to_focus_on(mplex, node, NULL, NULL); ret=(foc!=NULL); } @@ -746,24 +839,33 @@ bool mplex_do_prepare_focus(WMPlex *mplex, WStacking *node, WStacking *sub, int flags, WPrepareFocusResult *res) { + bool ew=(flags®ION_GOTO_ENTERWINDOW); + PtrList *hidelist=NULL; + PtrList **hidelistp=(ew ? NULL : &hidelist); WStacking *foc; 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); + foc=mplex_do_to_focus_on(mplex, node, sub, hidelistp); else - foc=mplex_do_to_focus(mplex, sub); + foc=mplex_do_to_focus(mplex, sub, hidelistp); if(foc!=NULL){ + 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){ @@ -883,7 +985,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) @@ -1108,16 +1211,13 @@ bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph) : 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 @@ -1160,6 +1260,7 @@ bool mplex_do_attach_final(WMPlex *mplex, WRegion *reg, WMPlexPHolder *ph) node->hidden=TRUE; node->szplcy=szplcy; node->level=level; + node->pseudomodal=(param->flags&MPLEX_ATTACH_PSEUDOMODAL ? 1 : 0); if(lnode!=NULL){ llist_link_after(&(mplex->mx_list), @@ -1281,19 +1382,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(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; @@ -1303,12 +1406,23 @@ 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, "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; } @@ -1374,7 +1488,11 @@ 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. \\ + * \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} * @@ -1410,33 +1528,32 @@ 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) @@ -1654,13 +1771,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} @@ -1891,13 +2010,16 @@ static void save_node(WMPlex *mplex, ExtlTab subs, int *n, if(st!=extl_table_none()){ 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);