]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/grouppholder.c
Imported Upstream version 20090110
[ion3.git] / ioncore / grouppholder.c
index d92c5b4dbab0ad4c9ec27c01d14be16521f2b6f2..052f67725941761d643e4f2d1a286054146f607c 100644 (file)
 /*
  * ion/ioncore/grouppholder.c
  *
- * Copyright (c) Tuomo Valkonen 2005-2006
+ * Copyright (c) Tuomo Valkonen 2005-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 <libtu/objp.h>
 #include <libtu/obj.h>
 #include <libtu/pointer.h>
+#include <libmainloop/defer.h>
 
 #include <ioncore/common.h>
 #include "group.h"
+#include "group-cw.h"
 #include "grouppholder.h"
 
 
 static void group_watch_handler(Watch *watch, Obj *ws);
 
 
-/*{{{ Init/deinit */
+/*{{{ Primitives */
+
+
+void grouppholder_do_link(WGroupPHolder *ph, WGroup *group, WRegion *stack_above)
+{
+    ph->group=group;
+    
+    if(group!=NULL){
+        LINK_ITEM_FIRST(group->phs, ph, next, prev);
+    }else{
+        /* This seems very crucial for detached pholders... */
+        ph->next=NULL;
+        ph->prev=ph;
+    }
+    
+    /* We must move stack_above pointer into a Watch. */
+    if(stack_above!=NULL)
+        watch_setup(&(ph->stack_above_watch), (Obj*)stack_above, NULL);
+}
 
 
-static void group_watch_handler(Watch *watch, Obj *ws)
+static WGroupPHolder *get_head(WGroupPHolder *ph)
 {
-    WGroupPHolder *ph=FIELD_TO_STRUCT(WGroupPHolder, 
-                                      group_watch, watch);
-    pholder_redirect(&(ph->ph), (WRegion*)ws);
+    while(1){
+        /* ph->prev==NULL should not happen.. */
+        if(ph->prev==NULL || ph->prev->next==NULL)
+            break;
+        ph=ph->prev;
+    }
+    
+    return ph;
 }
 
 
+void grouppholder_do_unlink(WGroupPHolder *ph)
+{
+    WGroup *group=ph->group;
+    
+    watch_reset(&(ph->stack_above_watch));
+    
+    if(ph->recreate_pholder!=NULL){
+        if(ph->next!=NULL){
+            ph->next->recreate_pholder=ph->recreate_pholder;
+        }else{
+            /* It might be in use in attach chain! So defer. */
+            mainloop_defer_destroy((Obj*)ph->recreate_pholder);
+        }
+        ph->recreate_pholder=NULL;
+    }
+    
+    if(group!=NULL){
+        UNLINK_ITEM(group->phs, ph, next, prev);
+    }else if(ph->prev!=NULL){
+        WGroupPHolder *next=ph->next;
+        
+        ph->prev->next=next;
+
+        if(next==NULL){
+            next=get_head(ph);
+            assert(next->prev==ph);
+        }
+        next->prev=ph->prev;
+    }else{
+        /* ph should not be on a list, if prev pointer is NULL (whereas
+         * next alone can be NULL in our semi-doubly-linked lists).
+         */
+        assert(ph->next==NULL);
+    }
+    
+    ph->group=NULL;
+    ph->next=NULL;
+    ph->prev=NULL;
+}
+
+
+/*}}}*/
+
+
+/*{{{ Init/deinit */
+
 static WGroupAttachParams dummy_param=GROUPATTACHPARAMS_INIT;
 
 
@@ -39,22 +107,17 @@ bool grouppholder_init(WGroupPHolder *ph, WGroup *ws,
                        const WStacking *st,
                        const WGroupAttachParams *param)
 {
+    WRegion *stack_above=NULL;
+    
     pholder_init(&(ph->ph));
 
-    watch_init(&(ph->group_watch));
     watch_init(&(ph->stack_above_watch));
-    
-    if(ws!=NULL){
-        if(!watch_setup(&(ph->group_watch), (Obj*)ws, 
-                        group_watch_handler)){
-            pholder_deinit(&(ph->ph));
-            return FALSE;
-        }
-    }
-    
-    if(param==NULL)
-        param=&dummy_param;
-    
+    ph->next=NULL;
+    ph->prev=NULL;
+    ph->group=NULL;
+    ph->recreate_pholder=NULL;
+    ph->param=(param==NULL ? dummy_param : *param);
+
     if(st!=NULL){
         /* TODO? Just link to the stacking structure to remember 
          * stacking order? 
@@ -73,25 +136,19 @@ bool grouppholder_init(WGroupPHolder *ph, WGroup *ws,
         if(st->above!=NULL && st->above->reg!=NULL)
             ph->param.stack_above=st->above->reg;
         
-        ph->param.modal=FALSE;
         ph->param.bottom=(st==ws->bottom);
-        /*ph->passive=FALSE;*/
-    }else{
-        ph->param=*param;
     }
-
+    
     ph->param.switchto_set=FALSE;
-
-    if(ph->param.stack_above!=NULL){
-        /* We must move stack_above pointer into a Watch. */
-        watch_setup(&(ph->stack_above_watch), 
-                    (Obj*)ph->param.stack_above, NULL);
-        ph->param.stack_above=NULL;
-    }
+    
+    stack_above=ph->param.stack_above;
+    ph->param.stack_above=NULL;
+    
+    grouppholder_do_link(ph, ws, stack_above);
     
     return TRUE;
 }
+
 
 WGroupPHolder *create_grouppholder(WGroup *ws,
                                    const WStacking *st,
@@ -103,8 +160,8 @@ WGroupPHolder *create_grouppholder(WGroup *ws,
 
 void grouppholder_deinit(WGroupPHolder *ph)
 {
-    watch_reset(&(ph->group_watch));
-    watch_reset(&(ph->stack_above_watch));
+    grouppholder_do_unlink(ph);
+    
     pholder_deinit(&(ph->ph));
 }
 
@@ -115,15 +172,104 @@ void grouppholder_deinit(WGroupPHolder *ph)
 /*{{{ Dynfuns */
 
 
+static WPHolder *get_recreate_ph(WGroupPHolder *ph)
+{
+    return get_head(ph)->recreate_pholder;
+}
+
+
+typedef struct{
+    WGroupPHolder *ph, *ph_head;
+    WRegionAttachData *data;
+    WRegion *reg_ret;
+} RP;
+
+
+static WRegion *recreate_handler(WWindow *par, 
+                                 const WFitParams *fp, 
+                                 void *rp_)
+{
+    WGroupPHolder *phtmp;
+    RP *rp=(RP*)rp_;
+    WGroup *grp;
+    
+    grp=(WGroup*)create_groupcw(par, fp);
+    
+    if(grp==NULL)
+        return NULL;
+        
+    rp->ph->param.whatever=(fp->mode&REGION_FIT_WHATEVER ? 1 : 0);
+    
+    rp->reg_ret=group_do_attach(grp, &rp->ph->param, rp->data);
+    
+    rp->ph->param.whatever=0;
+    
+    if(rp->reg_ret==NULL){
+        destroy_obj((Obj*)grp);
+        return NULL;
+    }else{
+        grp->phs=rp->ph_head;
+        
+        for(phtmp=grp->phs; phtmp!=NULL; phtmp=phtmp->next)
+            phtmp->group=grp;
+    }
+    
+    if(fp->mode&REGION_FIT_WHATEVER)
+        REGION_GEOM(grp)=REGION_GEOM(rp->reg_ret);
+    
+    return (WRegion*)grp;
+}
+
+
+
+static WRegion *grouppholder_attach_recreate(WGroupPHolder *ph, int flags,
+                                             WRegionAttachData *data)
+{
+    WRegionAttachData data2;
+    WPHolder *root, *rph;
+    WRegion *res;
+    RP rp;
+    
+    rp.ph_head=get_head(ph);
+    
+    assert(rp.ph_head!=NULL);
+    
+    rph=rp.ph_head->recreate_pholder;
+    
+    if(rph==NULL)
+        return NULL;
+    
+    rp.ph=ph;
+    rp.data=data;
+    rp.reg_ret=NULL;
+    
+    data2.type=REGION_ATTACH_NEW;
+    data2.u.n.fn=recreate_handler;
+    data2.u.n.param=&rp;
+    
+    res=pholder_do_attach(rph, flags, &data2);
+    
+    if(res!=NULL){
+        rp.ph_head->recreate_pholder=NULL;
+        /* It might be in use in attach chain! So defer. */
+        mainloop_defer_destroy((Obj*)rph);
+    }
+
+    return (flags&PHOLDER_ATTACH_RETURN_CREATEROOT
+            ? (WRegion*)res
+            : rp.reg_ret);
+}
+
+
 WRegion *grouppholder_do_attach(WGroupPHolder *ph, int flags,
                                 WRegionAttachData *data)
 {
-    WGroup *ws=(WGroup*)ph->group_watch.obj;
+    WGroup *ws=ph->group;
     WRegion *reg;
 
     if(ws==NULL)
-        return FALSE;
-
+        return grouppholder_attach_recreate(ph, flags, data);
+    
     ph->param.switchto_set=1;
     ph->param.switchto=(flags&PHOLDER_ATTACH_SWITCHTO ? 1 : 0);
     
@@ -140,18 +286,21 @@ WRegion *grouppholder_do_attach(WGroupPHolder *ph, int flags,
 
 bool grouppholder_do_goto(WGroupPHolder *ph)
 {
-    WGroup *ws=(WGroup*)ph->group_watch.obj;
-    
-    if(ws!=NULL)
-        return region_goto((WRegion*)ws);
-    
-    return FALSE;
+    return (ph->group!=NULL
+            ? region_goto((WRegion*)ph->group)
+            : (ph->recreate_pholder!=NULL
+               ? pholder_do_goto(ph->recreate_pholder)
+               : FALSE));
 }
 
 
 WRegion *grouppholder_do_target(WGroupPHolder *ph)
 {
-    return (WRegion*)ph->group_watch.obj;
+    return (ph->group!=NULL
+            ? (WRegion*)ph->group
+            : (ph->recreate_pholder!=NULL
+               ? pholder_do_target(ph->recreate_pholder)
+               : NULL));
 }