]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/group.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / group.c
index 591fcd757dd4f1a609f658a12de71d597f527f5c..3db079526e8ece8bbcb89b258207e12cd4bb7227 100644 (file)
@@ -1,12 +1,9 @@
 /*
  * ion/ioncore/group.c
  *
- * Copyright (c) Tuomo Valkonen 1999-2006
+ * 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 <string.h>
 #include "grouppholder.h"
 #include "frame.h"
 #include "float-placement.h"
+#include "return.h"
 
 
 static void group_place_stdisp(WGroup *ws, WWindow *parent,
                                  int pos, WRegion *stdisp);
 
+static void group_remanage_stdisp(WGroup *ws);
+
+static void group_do_set_bottom(WGroup *grp, WStacking *st);
 
 
 /*{{{ Stacking list stuff */
@@ -233,26 +234,9 @@ static WStacking *find_to_focus(WGroup *ws, WStacking *st, bool group_only)
 }
 
 
-static bool group_refocus_(WGroup *ws, WStacking *st)
-{
-    if(st!=ws->current_managed && st->reg!=NULL){
-        if(region_may_control_focus((WRegion*)ws))
-            region_set_focus(st->reg);
-        else
-            ws->current_managed=st;
-        return TRUE;
-    }
-    
-    return FALSE;
-}
-
-
 static void group_do_set_focus(WGroup *ws, bool warp)
 {
-    WStacking *st=ws->current_managed;
-    
-    if(st==NULL || st->reg==NULL)
-        st=find_to_focus(ws, NULL, TRUE);
+    WStacking *st=find_to_focus(ws, ws->current_managed, FALSE);
     
     if(st!=NULL && st->reg!=NULL)
         region_do_set_focus(st->reg, warp);
@@ -279,19 +263,21 @@ static bool group_managed_prepare_focus(WGroup *ws, WRegion *reg,
         return mplex_do_prepare_focus(mplex, node, st,
                                       flags, res);
     }else{
-        WStacking *stacking;
-        
         if(!region_prepare_focus((WRegion*)ws, flags, res))
             return FALSE;
 
-        stacking=group_get_stacking(ws);
         st=find_to_focus(ws, st, FALSE);
         
-#warning "TODO: raise in some cases (not enter-window)?"
-        
         if(st==NULL)
             return FALSE;
         
+        if(ioncore_g.autoraise && 
+           !(flags&REGION_GOTO_ENTERWINDOW) &&
+           st->level>STACKING_LEVEL_BOTTOM){
+            WStacking **stackingp=group_get_stackingp(ws);
+            stacking_restack(stackingp, st, None, NULL, NULL, FALSE);
+        }
+        
         res->reg=st->reg;
         res->flags=flags;
         
@@ -300,87 +286,61 @@ static bool group_managed_prepare_focus(WGroup *ws, WRegion *reg,
 }
 
 
-static bool group_essentially_empty(WGroup *ws)
-{
-    WGroupIterTmp tmp;
-    WStacking *st;
-    
-    FOR_ALL_NODES_IN_GROUP(ws, st, tmp){
-        if(st!=ws->managed_stdisp)
-            return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
 void group_managed_remove(WGroup *ws, WRegion *reg)
 {
     bool mcf=region_may_control_focus((WRegion*)ws);
-    bool ds=OBJ_IS_BEING_DESTROYED(ws);
     WStacking *st, *next_st=NULL;
     bool was_stdisp=FALSE, was_bottom=FALSE;
-    bool dest=FALSE;
-    bool cur=FALSE;
+    bool was_current=FALSE;
     
     st=group_find_stacking(ws, reg);
 
     if(st!=NULL){
-        next_st=stacking_unstack(REGION_PARENT(ws), st);
-        
-        UNLINK_ITEM(ws->managed_list, st, mgr_next, mgr_prev);
+        if(st==ws->bottom){
+            was_bottom=TRUE;
+            group_do_set_bottom(ws, NULL);
+        }
         
         if(st==ws->managed_stdisp){
             ws->managed_stdisp=NULL;
             was_stdisp=TRUE;
         }
-        
-        if(st==ws->bottom){
-            ws->bottom=NULL;
-            was_bottom=TRUE;
-            if(ws->bottom_last_close && group_essentially_empty(ws))
-                dest=TRUE;
-        }
             
         if(st==ws->current_managed){
-            cur=TRUE;
             ws->current_managed=NULL;
+            was_current=TRUE;
         }
         
+        next_st=stacking_unstack(REGION_PARENT(ws), st);
+        UNLINK_ITEM(ws->managed_list, st, mgr_next, mgr_prev);
         stacking_unassoc(st);
         stacking_free(st);
     }
     
     region_unset_manager(reg, (WRegion*)ws);
-
-    if(!dest && !ds){
-        if(was_bottom && !was_stdisp && ws->managed_stdisp==NULL){
-            /* We should probably be managing any stdisp, that 'bottom' 
-             * was managing.
-             */
-            WMPlex *mplex=OBJ_CAST(REGION_MANAGER(ws), WMPlex);
-            
-            if(mplex!=NULL 
-               && mplex->mx_current!=NULL 
-               && mplex->mx_current->st->reg==(WRegion*)ws){
-                mplex_remanage_stdisp(mplex);
-            }
-        }
-        
-        if(cur){
-            WStacking *stf=find_to_focus(ws, next_st, TRUE);
-            if(stf!=NULL)
-                region_warp(stf->reg);
+    
+    if(!OBJ_IS_BEING_DESTROYED(ws) && was_current){
+        /* This may still potentially cause problems when focus
+         * change is pending. Perhaps we should use region_await_focus,
+         * if it is pointing to our child (and region_may_control_focus 
+         * fail if it is pointing somewhere else).
+         */
+        WStacking *stf=find_to_focus(ws, next_st, TRUE);
+        if(stf!=NULL && mcf){
+            region_maybewarp_now(stf->reg, FALSE);
+        }else{
+            ws->current_managed=stf;
         }
-    }else if(dest && !ds){
-        mainloop_defer_destroy((Obj*)ws);
     }
 }
 
 
-static void group_managed_activated(WGroup *ws, WRegion *reg)
+void group_managed_notify(WGroup *ws, WRegion *reg, WRegionNotify how)
 {
-    ws->current_managed=group_find_stacking(ws, reg);
+    if(how==ioncore_g.notifies.activated || 
+       how==ioncore_g.notifies.pseudoactivated){
+        ws->current_managed=group_find_stacking(ws, reg);
+    }
 }
 
 
@@ -396,6 +356,7 @@ bool group_init(WGroup *ws, WWindow *par, const WFitParams *fp)
     ws->managed_stdisp=NULL;
     ws->bottom=NULL;
     ws->managed_list=NULL;
+    ws->phs=NULL;
     
     ws->dummywin=XCreateWindow(ioncore_g.dpy, par->win,
                                 fp->g.x, fp->g.y, 1, 1, 0,
@@ -446,43 +407,131 @@ void group_deinit(WGroup *ws)
     XDeleteContext(ioncore_g.dpy, ws->dummywin, ioncore_g.win_context);
     XDestroyWindow(ioncore_g.dpy, ws->dummywin);
     ws->dummywin=None;
-
+    
+    while(ws->phs!=NULL)
+        grouppholder_do_unlink(ws->phs);
+    
     region_deinit(&ws->reg);
 }
 
 
-    
-bool group_rescue_clientwins(WGroup *ws, WPHolder *ph)
+bool group_rescue_clientwins(WGroup *ws, WRescueInfo *info)
 {
     WGroupIterTmp tmp;
     
     group_iter_init_nostdisp(&tmp, ws);
     
-    return region_rescue_some_clientwins((WRegion*)ws, ph,
+    return region_rescue_some_clientwins((WRegion*)ws, info,
                                          (WRegionIterator*)group_iter,
                                          &tmp);
 }
 
 
-bool group_may_destroy(WGroup *ws)
+WPHolder *group_get_rescue_pholder_for(WGroup *ws, 
+                                       WRegion *forwhat)
+{
+    WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
+    WFramedParam fp=FRAMEDPARAM_INIT;
+    WPHolder *ph;
+    
+    ap.geom_set=TRUE;
+    ap.geom=REGION_GEOM(forwhat);
+
+    ap.geom_weak_set=1;
+    
+    if(REGION_PARENT(forwhat)==REGION_PARENT(ws)){
+        ap.geom.x-=REGION_GEOM(ws).x;
+        ap.geom.y-=REGION_GEOM(ws).y;
+    }else{
+        ap.geom_weak=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
+    }
+    
+    /* frame mode */
+    /*{
+        WFrame *frame=OBJ_CAST(forwhat, WFrame);
+        if(frame!=NULL)
+            fp.mode=frame->mode;
+    }*/
+    
+    ph=(WPHolder*)create_grouppholder(ws, NULL, &ap);
+    
+    return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
+}
+
+
+
+/*}}}*/
+
+
+/*{{{ Bottom */
+
+
+void group_bottom_set(WGroup *grp)
 {
-    bool ret=group_essentially_empty(ws);
-    if(!ret)
-        warn(TR("Workspace not empty - refusing to destroy."));
-    return ret;
+    CALL_DYN(group_bottom_set, grp, (grp));
+}
+
+
+static void group_do_set_bottom(WGroup *grp, WStacking *st)
+{
+    WStacking *was=grp->bottom;
+    WStacking *std=grp->managed_stdisp;
+    
+    grp->bottom=st;
+    
+    if(!OBJ_IS_BEING_DESTROYED(grp)){
+        bool noremanage=((was==st) ||
+                         (was==NULL && std==NULL) || 
+                         (st!=NULL && st==std) || 
+                         (st==NULL && was==std));
+        
+        if(!noremanage &&
+           (st==NULL || HAS_DYN(st->reg, region_manage_stdisp))){
+            group_remanage_stdisp(grp);
+        }
+        
+        group_bottom_set(grp);
+    }
 }
 
 
-static bool group_managed_may_destroy(WGroup *ws, WRegion *reg)
+/*EXTL_DOC
+ * Sets the `bottom' of \var{ws}. The region \var{reg} must already
+ * be managed by \var{ws}, unless \code{nil}.
+ */
+EXTL_EXPORT_MEMBER
+bool group_set_bottom(WGroup *ws, WRegion *reg)
 {
+    WStacking *st=NULL;
+    
+    if(reg!=NULL){
+        st=group_find_stacking(ws, reg);
+        
+        if(st==NULL)
+            return FALSE;
+    }
+        
+    group_do_set_bottom(ws, st);
+    
     return TRUE;
 }
 
 
+/*EXTL_DOC
+ * Returns the `bottom' of \var{ws}.
+ */
+EXTL_SAFE
+EXTL_EXPORT_MEMBER
+WRegion *group_bottom(WGroup *ws)
+{
+    return (ws->bottom!=NULL ? ws->bottom->reg : NULL);
+}
+
+
 /*}}}*/
 
 
-/*{{{ attach */
+/*{{{ Attach */
 
 
 WStacking *group_do_add_managed(WGroup *ws, WRegion *reg, int level,
@@ -518,8 +567,7 @@ WStacking *group_do_add_managed_default(WGroup *ws, WRegion *reg, int level,
     
     frame=OBJ_CAST(reg, WFrame);
     if(frame!=NULL){
-        WFrameMode m=frame_mode(frame);
-        if(m!=FRAME_MODE_FLOATING && m!=FRAME_MODE_TRANSIENT)
+        if(framemode_unalt(frame_mode(frame))==FRAME_MODE_TILED)
             frame_set_mode(frame, FRAME_MODE_FLOATING);
     }
 
@@ -550,6 +598,14 @@ static void geom_group_to_parent(WGroup *ws, const WRectangle *g,
 }
 
 
+static int group_must_focus(WGroup *ws, WStacking *st)
+{
+    WStacking *stacking=group_get_stacking(ws);
+    
+    return (stacking!=NULL && stacking_must_focus(stacking, st));
+}
+
+
 bool group_do_attach_final(WGroup *ws, 
                            WRegion *reg,
                            const WGroupAttachParams *param)
@@ -562,60 +618,67 @@ bool group_do_attach_final(WGroup *ws,
     int weak;
     bool sw;
     
+    /* Stacking  */
+    if(param->stack_above!=NULL)
+        stabove=group_find_stacking(ws, param->stack_above);
+
+    level=(stabove!=NULL
+           ? stabove->level
+           : (param->level_set 
+              ? param->level 
+              : STACKING_LEVEL_NORMAL));
+    
     /* Fit */
     szplcy=(param->szplcy_set
             ? param->szplcy
             : (param->bottom
                ? SIZEPOLICY_FULL_EXACT
-               : SIZEPOLICY_UNCONSTRAINED));
-    
-    weak=(param->geom_weak_set
-          ? param->geom_weak
-          : (param->geom_set
-             ? 0
-             : REGION_RQGEOM_WEAK_ALL));
-    
-    if(param->geom_set)
-        geom_group_to_parent(ws, &param->geom, &g);
-    else
-        g=REGION_GEOM(reg);
-    
-    /* If the requested geometry does not overlap the workspaces's geometry, 
-     * position request is never honoured.
-     */
-    if((g.x+g.w<=REGION_GEOM(ws).x) ||
-       (g.y+g.h<=REGION_GEOM(ws).y) ||
-       (g.x>=REGION_GEOM(ws).x+REGION_GEOM(ws).w) ||
-       (g.y>=REGION_GEOM(ws).y+REGION_GEOM(ws).h)){
-        weak|=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_X;
-    }
+               : SIZEPOLICY_VISIBILITY_CONSTRAINED));
+    
+    if(!param->whatever){
+        weak=(param->geom_weak_set
+              ? param->geom_weak
+              : (param->geom_set
+                 ? 0
+                 : REGION_RQGEOM_WEAK_ALL));
+        
+        if(param->geom_set)
+            geom_group_to_parent(ws, &param->geom, &g);
+        else
+            g=REGION_GEOM(reg);
+        
+        /* If the requested geometry does not overlap the workspaces's geometry, 
+         * position request is never honoured.
+         */
+        if((g.x+g.w<=REGION_GEOM(ws).x) ||
+           (g.x>=REGION_GEOM(ws).x+REGION_GEOM(ws).w)){
+            weak|=REGION_RQGEOM_WEAK_X;
+        }
+           
+        if((g.y+g.h<=REGION_GEOM(ws).y) ||
+           (g.y>=REGION_GEOM(ws).y+REGION_GEOM(ws).h)){
+            weak|=REGION_RQGEOM_WEAK_Y;
+        }
 
-    if((weak&(REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y))
-       ==(REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y) &&
-        (szplcy==SIZEPOLICY_UNCONSTRAINED ||
-         szplcy==SIZEPOLICY_FREE ||
-         szplcy==SIZEPOLICY_FREE_GLUE /* without flags */)){
-        group_calc_placement(ws, &g);
-    }
+        if(weak&(REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y) &&
+            (szplcy==SIZEPOLICY_UNCONSTRAINED ||
+             szplcy==SIZEPOLICY_VISIBILITY_CONSTRAINED ||
+             szplcy==SIZEPOLICY_FREE ||
+             szplcy==SIZEPOLICY_FREE_GLUE /* without flags */)){
+            /* TODO: use 'weak'? */
+            group_calc_placement(ws, level, &g);
+        }
 
-    fp.g=REGION_GEOM(ws);
-    fp.mode=REGION_FIT_EXACT;
+        fp.g=REGION_GEOM(ws);
+        fp.mode=REGION_FIT_EXACT;
 
-    sizepolicy(&szplcy, reg, &g, weak, &fp);
+        sizepolicy(&szplcy, reg, &g, weak, &fp);
 
-    if(rectangle_compare(&fp.g, &REGION_GEOM(reg))!=RECTANGLE_SAME)
-        region_fitrep(reg, NULL, &fp);
+        if(rectangle_compare(&fp.g, &REGION_GEOM(reg))!=RECTANGLE_SAME)
+            region_fitrep(reg, NULL, &fp);
+    }
     
-    /* Stacking & add */
-    if(param->stack_above!=NULL)
-        stabove=group_find_stacking(ws, param->stack_above);
-
-    level=(stabove!=NULL
-           ? stabove->level
-           : (param->level_set 
-              ? param->level 
-              : STACKING_LEVEL_NORMAL));
-
+    /* Add */
     st=group_do_add_managed(ws, reg, level, szplcy);
     
     if(st==NULL)
@@ -624,74 +687,66 @@ bool group_do_attach_final(WGroup *ws,
     if(stabove!=NULL)
         st->above=stabove;
 
-    /* Misc. */
-    if(param->bottom){
-        ws->bottom=st;
-        
-        if(HAS_DYN(reg, region_manage_stdisp) && ws->managed_stdisp!=NULL){
-            WMPlex *mplex=OBJ_CAST(REGION_MANAGER(ws), WMPlex);
-            if(mplex!=NULL){ /* should always hold */
-                WMPlexSTDispInfo di;
-                WRegion *stdisp=NULL;
-                mplex_get_stdisp(mplex, &stdisp, &di);
-                if(stdisp!=NULL){
-                    assert(stdisp==ws->managed_stdisp->reg);
-                    /* WARNING! Calls back to group code (managed_remove). */
-                    region_manage_stdisp(reg, stdisp, &di);
-                }
-            }
-        }
-    }
+    if(param->bottom)
+        group_do_set_bottom(ws, st);
     
-    sw=(param->switchto_set ? param->switchto : ioncore_g.switchto_new);
+    /* Focus */
+    sw=((param->switchto_set ? param->switchto : ioncore_g.switchto_new)
+        ? st==find_to_focus(ws, st, FALSE)
+        : group_must_focus(ws, st));
     
-    if(sw || st->level>=STACKING_LEVEL_MODAL1){
-        WStacking *stf=find_to_focus(ws, st, FALSE);
-        
-        if(stf==st){
-            /* Ok, the new region can be focused */
-            group_refocus_(ws, stf);
-        }
+    if(sw){
+        if(region_may_control_focus((WRegion*)ws))
+            region_set_focus(st->reg);
+        else
+            ws->current_managed=st;
+    }else if(region_is_fully_mapped(reg)){
+        region_pointer_focus_hack(reg);
     }
-    
+
     return TRUE;
 }
 
 
+static void group_attach_fp(WGroup *ws, const WGroupAttachParams *param,
+                            WFitParams *fp)
+{
+    if(param->geom_set){
+        geom_group_to_parent(ws, &param->geom, &fp->g);
+        fp->mode=REGION_FIT_EXACT;
+    }else{
+        fp->g=REGION_GEOM(ws);
+        fp->mode=REGION_FIT_BOUNDS|REGION_FIT_WHATEVER;
+    }
+}
+
+
 WRegion *group_do_attach(WGroup *ws, 
                          /*const*/ WGroupAttachParams *param,
                          WRegionAttachData *data)
 {
     WFitParams fp;
-    WWindow *par;
     WRegion *reg;
-
+    
     if(ws->bottom!=NULL && param->bottom){
         warn(TR("'bottom' already set."));
         return NULL;
     }
     
-    par=REGION_PARENT(ws);
-    assert(par!=NULL);
-
-    if(param->geom_set){
-        geom_group_to_parent(ws, &param->geom, &fp.g);
-        fp.mode=REGION_FIT_EXACT;
-    }else{
-        fp.g=REGION_GEOM(ws);
-        fp.mode=REGION_FIT_BOUNDS|REGION_FIT_WHATEVER;
-    }
-
-    return region_attach_helper((WRegion*) ws, par, &fp, 
+    group_attach_fp(ws, param, &fp);
+    
+    return region_attach_helper((WRegion*) ws, REGION_PARENT(ws), &fp, 
                                 (WRegionDoAttachFn*)group_do_attach_final,
                                 /*(const WRegionAttachParams*)*/param, data);
     /*                            ^^^^ doesn't seem to work. */
 }
 
 
-static void get_params(WGroup *ws, ExtlTab tab, WGroupAttachParams *par)
+void group_get_attach_params(WGroup *ws, ExtlTab tab, 
+                             WGroupAttachParams *par)
 {
     int tmp;
+    bool tmpb;
     char *tmps;
     ExtlTab g;
     
@@ -701,27 +756,29 @@ static void get_params(WGroup *ws, ExtlTab tab, WGroupAttachParams *par)
     par->geom_set=0;
     par->bottom=0;
     
-    if(extl_table_gets_i(tab, "level", &tmp)){
-        if(tmp>=0){
-            par->level_set=STACKING_LEVEL_NORMAL;
-            par->level=tmp;
-        }
-    }
-    
     if(extl_table_is_bool_set(tab, "bottom")){
         par->level=STACKING_LEVEL_BOTTOM;
         par->level_set=1;
         par->bottom=1;
     }
     
+    if(extl_table_gets_i(tab, "level", &tmp)){
+        if(tmp>=0){
+            par->level_set=1;
+            par->level=tmp;
+        }
+    }
+    
     if(!par->level_set && extl_table_is_bool_set(tab, "modal")){
         par->level=STACKING_LEVEL_MODAL1;
         par->level_set=1;
     }
     
-    if(extl_table_is_bool_set(tab, "switchto"))
-        par->switchto=1;
-
+    if(extl_table_gets_b(tab, "switchto", &tmpb)){
+        par->switchto=(tmpb!=0);
+        par->switchto_set=1;
+    }
+    
     if(extl_table_gets_i(tab, "sizepolicy", &tmp)){
         par->szplcy_set=1;
         par->szplcy=tmp;
@@ -766,7 +823,7 @@ WRegion *group_attach(WGroup *ws, WRegion *reg, ExtlTab param)
     if(reg==NULL)
         return NULL;
     
-    get_params(ws, param, &par);
+    group_get_attach_params(ws, param, &par);
     
     data.type=REGION_ATTACH_REPARENT;
     data.u.reg=reg;
@@ -781,12 +838,14 @@ WRegion *group_attach(WGroup *ws, WRegion *reg, ExtlTab param)
  * 
  * \begin{tabularx}{\linewidth}{lX}
  *  \tabhead{Field & Description}
- *  \var{type} & Class name (a string) of the object to be created. Mandatory. \\
- *  \var{name} & Name of the object to be created (a string). Optional. \\
- *  \var{switchto} & Should the region be switched to (boolean)? Optional. \\
- *  \var{level} & Stacking level; default is 1. \\
- *  \var{modal} & Make object modal; ignored if level is set. \\
- *  \var{sizepolicy} & Size policy. \\
+ *  \var{type} & (string) Class of the object to be created. Mandatory. \\
+ *  \var{name} & (string) Name of the object to be created. \\
+ *  \var{switchto} & (boolean) Should the region be switched to? \\
+ *  \var{level} & (integer) Stacking level; default is 1. \\
+ *  \var{modal} & (boolean) Make object modal; ignored if level is set. \\
+ *  \var{sizepolicy} & (string) Size policy; see Section \ref{sec:sizepolicies}. \\
+ *  \var{bottom} & (boolean) Mark the attached region as the
+ *                 ``bottom'' of \var{ws}. \\
  * \end{tabularx}
  * 
  * In addition parameters to the region to be created are passed in this 
@@ -798,7 +857,7 @@ WRegion *group_attach_new(WGroup *ws, ExtlTab param)
     WGroupAttachParams par=GROUPATTACHPARAMS_INIT;
     WRegionAttachData data;
 
-    get_params(ws, param, &par);
+    group_get_attach_params(ws, param, &par);
     
     data.type=REGION_ATTACH_LOAD;
     data.u.tab=param;
@@ -816,29 +875,34 @@ WRegion *group_attach_new(WGroup *ws, ExtlTab param)
 static int stdisp_szplcy(const WMPlexSTDispInfo *di, WRegion *stdisp)
 {
     int pos=di->pos;
+    int policy=0, gravity=0;
     
     if(di->fullsize){
         if(region_orientation(stdisp)==REGION_ORIENTATION_VERTICAL){
             if(pos==MPLEX_STDISP_TL || pos==MPLEX_STDISP_BL)
-                return SIZEPOLICY_STRETCH_LEFT;
+                policy=SIZEPOLICY_STRETCH_LEFT;
             else
-                return SIZEPOLICY_STRETCH_RIGHT;
+                policy=SIZEPOLICY_STRETCH_RIGHT;
         }else{
             if(pos==MPLEX_STDISP_TL || pos==MPLEX_STDISP_TR)
-                return SIZEPOLICY_STRETCH_TOP;
+                policy=SIZEPOLICY_STRETCH_TOP;
             else
-                return SIZEPOLICY_STRETCH_BOTTOM;
+                policy=SIZEPOLICY_STRETCH_BOTTOM;
         }
     }else{
-        if(pos==MPLEX_STDISP_TL)
-            return SIZEPOLICY_GRAVITY_NORTHWEST;
-        else if(pos==MPLEX_STDISP_BL)
-            return SIZEPOLICY_GRAVITY_SOUTHWEST;
-        else if(pos==MPLEX_STDISP_TR)
-            return SIZEPOLICY_GRAVITY_NORTHEAST;
-        else /*if(pos=MPLEX_STDISP_BR)*/
-            return SIZEPOLICY_GRAVITY_SOUTHEAST;
+        policy=SIZEPOLICY_GRAVITY;
     }
+    
+    if(pos==MPLEX_STDISP_TL)
+        gravity=SIZEPOLICY_VERT_TOP|SIZEPOLICY_HORIZ_LEFT;
+    else if(pos==MPLEX_STDISP_BL)
+        gravity=SIZEPOLICY_VERT_BOTTOM|SIZEPOLICY_HORIZ_LEFT;
+    else if(pos==MPLEX_STDISP_TR)
+        gravity=SIZEPOLICY_VERT_TOP|SIZEPOLICY_HORIZ_RIGHT;
+    else /*if(pos=MPLEX_STDISP_BR)*/
+        gravity=SIZEPOLICY_VERT_BOTTOM|SIZEPOLICY_HORIZ_RIGHT;
+    
+    return (policy|gravity);
 }
 
 
@@ -872,14 +936,36 @@ void group_manage_stdisp(WGroup *ws, WRegion *stdisp,
                                                 STACKING_LEVEL_ON_TOP, 
                                                 szplcy);
     }
-
+    
+    stdisp->flags|=REGION_SKIP_FOCUS;
+    
     fp.g=REGION_GEOM(ws);
+    fp.mode=0;
+    
     sizepolicy(&ws->managed_stdisp->szplcy, stdisp, NULL, 0, &fp);
 
     region_fitrep(stdisp, NULL, &fp);
 }
 
 
+static void group_remanage_stdisp(WGroup *ws)
+{
+    WMPlex *mplex=OBJ_CAST(REGION_MANAGER(ws), WMPlex);
+    
+    if(mplex!=NULL && 
+       mplex->mx_current!=NULL && 
+       mplex->mx_current->st->reg==(WRegion*)ws){
+        mplex_remanage_stdisp(mplex);
+    }
+}
+
+
+/*}}}*/
+
+
+/*{{{ Geometry requests */
+
+
 void group_managed_rqgeom(WGroup *ws, WRegion *reg,
                           const WRQGeomParams *rq,
                           WRectangle *geomret)
@@ -894,6 +980,7 @@ void group_managed_rqgeom(WGroup *ws, WRegion *reg,
         fp.mode=REGION_FIT_EXACT;
     }else{
         fp.g=REGION_GEOM(ws);
+        fp.mode=0;
         sizepolicy(&st->szplcy, reg, &rq->geom, rq->flags, &fp);
     }
     
@@ -947,12 +1034,6 @@ static WStacking *prv(WGroup *ws, WStacking *st, bool wrap)
 typedef WStacking *NxtFn(WGroup *ws, WStacking *st, bool wrap);
 
 
-static bool mapped_filt(WStacking *st, void *unused)
-{
-    return (st->reg!=NULL && REGION_IS_MAPPED(st->reg));
-}
-
-
 static bool focusable(WGroup *ws, WStacking *st, uint min_level)
 {
     return (st->reg!=NULL
@@ -971,7 +1052,7 @@ static WStacking *do_get_next(WGroup *ws, WStacking *sti,
     stacking=group_get_stacking(ws);
     
     if(stacking!=NULL)
-        min_level=stacking_min_level(stacking, mapped_filt, NULL);
+        min_level=stacking_min_level_mapped(stacking);
 
     st=sti;
     while(1){
@@ -985,7 +1066,7 @@ static WStacking *do_get_next(WGroup *ws, WStacking *sti,
     }
 
     if(sti_ok && focusable(ws, sti, min_level))
-        return st;
+        return sti;
     
     return NULL;
 }
@@ -1082,8 +1163,6 @@ void group_restack(WGroup *ws, Window other, int mode)
 
 WStacking *group_find_stacking(WGroup *ws, WRegion *r)
 {
-    WStacking *st;
-    
     if(r==NULL || REGION_MANAGER(r)!=(WRegion*)ws)
         return NULL;
     
@@ -1136,26 +1215,20 @@ bool group_managed_rqorder(WGroup *grp, WRegion *reg, WRegionOrder order)
 
 
 /*EXTL_DOC
- * Returns the 'bottom' of \var{ws}.
- */
-EXTL_EXPORT_MEMBER
-WRegion *group_bottom(WGroup *ws)
-{
-    return (ws->bottom!=NULL ? ws->bottom->reg : NULL);
-}
-
-
-/*EXTL_DOC
- * Returns a list of regions managed by the workspace (frames, mostly).
+ * Iterate over managed regions of \var{ws} until \var{iterfn} returns
+ * \code{false}.
+ * 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_EXPORT_MEMBER
-ExtlTab group_managed_list(WGroup *ws)
+bool group_managed_i(WGroup *ws, ExtlFn iterfn)
 {
     WGroupIterTmp tmp;
     group_iter_init(&tmp, ws);
     
-    return extl_obj_iterable_to_table((ObjIterator*)group_iter, &tmp);
+    return extl_iter_objlist_(iterfn, (ObjIterator*)group_iter, &tmp);
 }
 
 
@@ -1182,6 +1255,34 @@ Window group_xwindow(const WGroup *ws)
 }
 
 
+/*EXTL_DOC
+ * Returns the group of \var{reg}, if it is managed by one,
+ * and \var{reg} itself otherwise.
+ */
+/*EXTL_EXPORT_MEMBER
+WRegion *region_group_of(WRegion *reg)
+{
+    WRegion *mgr=REGION_MANAGER(reg);
+    
+    return (OBJ_IS(mgr, WGroup) ? mgr : reg);
+}*/
+
+
+/*EXTL_DOC
+ * Returns the group of \var{reg}, if \var{reg} is its bottom,
+ * and \var{reg} itself otherwise.
+ */
+EXTL_EXPORT_MEMBER
+WRegion *region_groupleader_of(WRegion *reg)
+{
+    WGroup *grp=REGION_MANAGER_CHK(reg, WGroup);
+    
+    return ((grp!=NULL && group_bottom(grp)==reg)
+            ? (WRegion*)grp
+            : reg);
+}
+
+
 /*}}}*/
 
 
@@ -1212,7 +1313,8 @@ static ExtlTab group_get_configuration(WGroup *ws)
         subtab=region_get_configuration(st->reg);
 
         if(subtab!=extl_table_none()){
-            extl_table_sets_i(subtab, "sizepolicy", st->szplcy);
+            extl_table_sets_s(subtab, "sizepolicy", 
+                              sizepolicy2string(st->szplcy));
             extl_table_sets_i(subtab, "level", st->level);
         
             tmpg=REGION_GEOM(st->reg);
@@ -1236,7 +1338,7 @@ static ExtlTab group_get_configuration(WGroup *ws)
     return tab;
 }
 
-
+    
 void group_do_load(WGroup *ws, ExtlTab tab)
 {
     ExtlTab substab, subtab;
@@ -1246,15 +1348,29 @@ void group_do_load(WGroup *ws, ExtlTab tab)
         n=extl_table_get_n(substab);
         for(i=1; i<=n; i++){
             if(extl_table_geti_t(substab, i, &subtab)){
-                group_attach_new(ws, subtab);
+                WGroupAttachParams par=GROUPATTACHPARAMS_INIT;
+                WRegionAttachData data;
+                WFitParams fp;
+                WPHolder *ph;
+                
+                group_get_attach_params(ws, subtab, &par);
+                group_attach_fp(ws, &par, &fp);
+                
+                ph=(WPHolder*)create_grouppholder(ws, NULL, &par);
+                
+                region_attach_load_helper((WRegion*)ws, REGION_PARENT(ws), &fp,
+                                          (WRegionDoAttachFn*)group_do_attach_final,
+                                          (void*)&par, subtab, &ph);
+                                              
+                if(ph!=NULL)
+                    destroy_obj((Obj*)ph);
+                
                 extl_unref_table(subtab);
             }
         }
         
         extl_unref_table(substab);
     }
-
-    ws->bottom_last_close=extl_table_is_bool_set(tab, "bottom_last_close");
 }
 
 
@@ -1295,8 +1411,8 @@ static DynFunTab group_dynfuntab[]={
     {region_do_set_focus, 
      group_do_set_focus},
     
-    {region_managed_activated
-     group_managed_activated},
+    {region_managed_notify
+     group_managed_notify},
     
     {region_managed_remove,
      group_managed_remove},
@@ -1304,12 +1420,6 @@ static DynFunTab group_dynfuntab[]={
     {(DynFun*)region_get_configuration, 
      (DynFun*)group_get_configuration},
 
-    {(DynFun*)region_may_destroy,
-     (DynFun*)group_may_destroy},
-
-    {(DynFun*)region_managed_may_destroy,
-     (DynFun*)group_managed_may_destroy},
-
     {(DynFun*)region_current,
      (DynFun*)group_current},
     
@@ -1348,6 +1458,9 @@ static DynFunTab group_dynfuntab[]={
     
     {(DynFun*)region_managed_rqorder,
      (DynFun*)group_managed_rqorder},
+     
+    {(DynFun*)region_get_rescue_pholder_for,
+     (DynFun*)group_get_rescue_pholder_for},
     
     END_DYNFUNTAB
 };