/*
* ion/ioncore/mplex.c
*
- * Copyright (c) Tuomo Valkonen 1999-2007.
+ * Copyright (c) Tuomo Valkonen 1999-2008.
*
* See the included file LICENSE for details.
*/
#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) \
mplex->mx_list=NULL;
mplex->mx_current=NULL;
- mplex->mx_phs=NULL;
+ mplex->misc_phs=NULL;
mplex->mx_count=0;
mplex->mgd=NULL;
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);
/*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
/*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
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);
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)
}
+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);
+}
+
+
/*}}}*/
}
-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)
+ PtrList **hidelist, bool *within)
{
WGroup *grp=OBJ_CAST(node->reg, WGroup);
WStacking *st;
if(grp!=NULL){
if(to_try==NULL)
to_try=grp->current_managed;
+ /* Only will return stuff within 'node' */
st=mplex_find_to_focus(mplex, to_try, node, hidelist);
- if(st!=NULL || to_try!=NULL)
+ if(st!=NULL){
+ if(within!=NULL)
+ *within=TRUE;
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, hidelist);
+ st=mplex_find_to_focus(mplex, node, NULL, hidelist);
- if(st==node)
- return st;
-
- if(hidelist!=NULL)
- ptrlist_clear(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;
- return NULL;
+ if(st==node && within!=NULL)
+ *within=TRUE;
+
+ return st;
}
}
-static WStacking *mplex_to_focus(WMPlex *mplex)
+/* 1. Try keep focus in REGION_ACTIVE_SUB.
+ * 2. Try given `node`.
+ * 3. Choose something else, attempting previous in focus history
+ * (unless `node` was set).
+ */
+static WStacking *mplex_to_focus(WMPlex *mplex, WStacking *node)
{
- WStacking *to_try=NULL;
+ WStacking *foc=NULL, *fallback=NULL;
WRegion *reg=NULL;
+ bool within=FALSE;
WStacking *st;
- to_try=maybe_focusable(REGION_ACTIVE_SUB(mplex));
+ foc=maybe_focusable(REGION_ACTIVE_SUB(mplex));
- if(to_try==NULL){
- /* Search focus history */
+ if(foc==NULL && node==NULL){
+ /* Search focus history if no specific attempt set.*/
for(reg=ioncore_g.focus_current; reg!=NULL; reg=reg->active_next){
- to_try=has_stacking_within(mplex, reg);
- if(to_try!=NULL)
+ foc=has_stacking_within(mplex, reg);
+ if(foc!=NULL)
break;
}
}
- st=mplex_do_to_focus(mplex, to_try, NULL);
+ if(foc!=NULL){
+ /*fallback=mplex_find_to_focus(mplex, foc, NULL, NULL);*/
+ /* In the history search case, 'foc' might point to a group,
+ * since we don't properly try to find a stacking within it...
+ */
+ fallback=mplex_do_to_focus_on(mplex, foc, NULL, NULL, NULL);
+ if(fallback!=foc)
+ foc=NULL;
+ }
- return (st!=NULL
- ? st
- : (mplex->mx_current!=NULL
- ? mplex->mx_current->st
- : NULL));
+ if(foc==NULL && node!=NULL)
+ foc=mplex_do_to_focus_on(mplex, node, NULL, NULL, &within);
+
+ if(foc==NULL || !within)
+ foc=fallback;
+
+ return foc;
}
void mplex_do_set_focus(WMPlex *mplex, bool warp)
{
if(!MPLEX_MGD_UNVIEWABLE(mplex)){
- WStacking *st=mplex_to_focus(mplex);
+ WStacking *st=mplex_to_focus(mplex, NULL);
+
+ if(st==NULL){
+ st=(mplex->mx_current!=NULL
+ ? mplex->mx_current->st
+ : NULL);
+ }
if(st!=NULL){
region_do_set_focus(st->reg, warp);
}
+static void mplex_refocus(WMPlex *mplex, WStacking *node, bool warp)
+{
+ WStacking *foc=mplex_to_focus(mplex, node);
+
+ if(foc!=NULL)
+ region_maybewarp(foc->reg, warp);
+}
+
+
/*}}}*/
}
-static bool mplex_refocus(WMPlex *mplex, WStacking *node, bool warp)
-{
- WStacking *foc=NULL;
- bool ret=TRUE;
-
- if(node!=NULL){
- foc=mplex_do_to_focus_on(mplex, node, NULL, NULL);
- ret=(foc!=NULL);
- }
-
- if(foc==NULL){
- ret=FALSE;
- foc=mplex_to_focus(mplex);
- }
-
- if(foc!=NULL)
- region_maybewarp(foc->reg, warp);
-
- return ret;
-}
-
-
bool mplex_do_prepare_focus(WMPlex *mplex, WStacking *node,
WStacking *sub, int flags,
WPrepareFocusResult *res)
PtrList *hidelist=NULL;
PtrList **hidelistp=(ew ? NULL : &hidelist);
WStacking *foc;
+ /*bool within=FALSE;*/
if(sub==NULL && node==NULL)
return FALSE;
if(!region_prepare_focus((WRegion*)mplex, flags, res))
return FALSE;
- if(node!=NULL)
- foc=mplex_do_to_focus_on(mplex, node, sub, hidelistp);
- else
- foc=mplex_do_to_focus(mplex, sub, hidelistp);
+ foc=mplex_do_to_focus_on(mplex, node, sub, hidelistp, NULL /*&within*/);
if(foc!=NULL){
while(hidelist!=NULL){
res->reg=foc->reg;
res->flags=flags;
- if(sub==NULL)
- return (foc==node);
- else
- return (foc==sub);
+ return (foc==sub || (sub==NULL && foc==node));
}else{
return FALSE;
}
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)
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->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);
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,
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);
}
+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);
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;
+ mplex_attach_fp(mplex, &ph->param, &fp);
return region_attach_helper((WRegion*)mplex,
(WWindow*)mplex, &fp,
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;
* \var{hidden} & (boolean) Attach hidden, if not prevented
* by e.g. the mutually exclusive list being empty.
* This option overrides \var{switchto}. \\
+ * \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
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;
}
+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, info,
(WRegionIterator*)mplex_iter,
}
-
-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)
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);
}
data.type=REGION_ATTACH_LOAD;
data.u.tab=t;
-
+
stdisp=region_attach_helper((WRegion*)mplex,
(WWindow*)mplex, &fp,
do_attach_stdisp, NULL,
}
-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;
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);
}