]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/detach.c
[svn-upgrade] Integrating new upstream version, ion3 (20070203)
[ion3.git] / ioncore / detach.c
diff --git a/ioncore/detach.c b/ioncore/detach.c
new file mode 100644 (file)
index 0000000..c93ca0c
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * ion/ioncore/detach.c
+ *
+ * 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.
+ */
+
+#include <libtu/objp.h>
+#include <libtu/setparam.h>
+#include <libtu/minmax.h>
+
+#include <ioncore/common.h>
+#include <ioncore/mplex.h>
+#include <ioncore/focus.h>
+#include <ioncore/group.h>
+#include <ioncore/group-ws.h>
+#include <ioncore/framedpholder.h>
+#include <ioncore/return.h>
+
+
+static void get_relative_geom(WRectangle *g, WRegion *reg, WRegion *mgr)
+{
+    WWindow *rel=REGION_PARENT(mgr), *w;
+    
+    *g=REGION_GEOM(reg);
+    
+    for(w=REGION_PARENT(reg); 
+        w!=rel && (WRegion*)w!=mgr; 
+        w=REGION_PARENT(w)){
+        
+        g->x+=REGION_GEOM(w).x;
+        g->y+=REGION_GEOM(w).y;
+    }
+}
+
+
+bool ioncore_do_detach(WRegion *reg, WGroup *grp, WFrameMode framemode)
+{
+    WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
+    WRegionAttachData data;
+    WPHolder *ph;
+    bool newph=FALSE;
+    bool ret;
+    
+    ap.switchto_set=TRUE;
+    ap.switchto=region_may_control_focus(reg);
+    
+    data.type=REGION_ATTACH_REPARENT;
+    data.u.reg=reg;
+    
+    ph=region_unset_get_return(reg);
+    
+    if(ph==NULL){
+        ph=region_make_return_pholder(reg);
+        newph=TRUE;
+    }
+    
+    if(framemode!=FRAME_MODE_UNKNOWN){
+        WFramedParam fpa=FRAMEDPARAM_INIT;
+        
+        fpa.mode=framemode;
+        fpa.inner_geom_gravity_set=TRUE;
+        fpa.gravity=ForgetGravity;
+        
+        ap.geom_weak_set=TRUE;
+        ap.geom_weak=0;
+        
+        get_relative_geom(&fpa.inner_geom, reg, (WRegion*)grp);
+
+        ret=(region_attach_framed((WRegion*)grp, &fpa,
+                                  (WRegionAttachFn*)group_do_attach,
+                                  &ap, &data)!=NULL);
+    }else{
+        WStacking *st=ioncore_find_stacking(reg);
+        
+        if(st!=NULL){
+            ap.szplcy=st->szplcy;
+            ap.szplcy_set=TRUE;
+            
+            ap.level=maxof(st->level, STACKING_LEVEL_NORMAL);
+            ap.level_set=TRUE;
+        }
+        
+        ap.geom_set=TRUE;
+        get_relative_geom(&ap.geom, reg, (WRegion*)grp);
+        
+        ret=(group_do_attach(grp, &ap, &data)!=NULL);
+    }
+    
+    if(!ret && newph)
+        destroy_obj((Obj*)ph);
+    else if(!region_do_set_return(reg, ph))
+        destroy_obj((Obj*)ph);
+    
+    return ret;
+}
+
+
+static WRegion *check_mplex(WRegion *reg, WFrameMode *mode)
+{
+    WMPlex *mplex=REGION_MANAGER_CHK(reg, WMPlex);
+    
+    if(OBJ_IS(reg, WWindow) || mplex==NULL){
+        *mode=FRAME_MODE_UNKNOWN;
+        return reg;
+    }
+        
+    *mode=FRAME_MODE_FLOATING;
+    
+    if(OBJ_IS(mplex, WFrame)
+       && frame_mode((WFrame*)mplex)==FRAME_MODE_TRANSIENT){
+        *mode=FRAME_MODE_TRANSIENT;
+    }
+    
+    return (WRegion*)mplex;
+}
+
+
+static WGroup *find_group(WRegion *reg)
+{
+    WRegion *mgr=REGION_MANAGER(reg);
+    
+    while(mgr!=NULL){
+        mgr=REGION_MANAGER(mgr);
+        if(OBJ_IS(mgr, WGroup))
+            break;
+    }
+    
+    return (WGroup*)mgr;
+}
+
+
+bool ioncore_detach(WRegion *reg, int sp)
+{
+    WPHolder *ph=region_get_return(reg);
+    WFrameMode mode;
+    WGroup *grp;
+    bool set, nset;
+    
+    reg=region_group_if_bottom(reg);
+    
+    grp=find_group(check_mplex(reg, &mode));
+    
+    /* reg is only considered detached if there's no higher-level group
+     * to attach to, thus causing 'toggle' to cycle.
+     */
+    set=(grp==NULL);
+    nset=libtu_do_setparam(sp, set);
+    
+    if(!XOR(nset, set))
+        return set;
+
+    if(!set){
+        return ioncore_do_detach(reg, grp, mode);
+    }else{
+        WPHolder *ph=region_get_return(reg);
+        
+        if(ph!=NULL){
+            if(!pholder_attach_mcfgoto(ph, PHOLDER_ATTACH_SWITCHTO, reg)){
+                warn(TR("Failed to reattach."));    
+                return TRUE;
+            }
+            region_unset_return(reg);
+        }
+        
+        return FALSE;
+    }
+}
+
+
+/*EXTL_DOC
+ * Detach or reattach \var{reg}, depending on whether \var{how}
+ * is 'set'/'unset'/'toggle'. (Detaching means making \var{reg} 
+ * managed by its nearest ancestor \type{WGroup}, framed if \var{reg} is
+ * not itself \type{WFrame}. Reattaching means making it managed where
+ * it used to be managed, if a return-placeholder exists.)
+ * If \var{reg} is the 'bottom' of some group, the whole group is
+ * detached. If \var{reg} is a \type{WWindow}, it is put into a 
+ * frame.
+ */
+EXTL_EXPORT_AS(ioncore, detach)
+bool ioncore_detach_extl(WRegion *reg, const char *how)
+{
+    if(how==NULL)
+        how="set";
+    
+    return ioncore_detach(reg, libtu_string_to_setparam(how));
+}
+
+