]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/mplexpholder.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / mplexpholder.c
index 51166f77edbbc478a41368f20d77e73e20ac4588..2c8461eeade2e9d93d001d973b159ee9ec81e521 100644 (file)
@@ -1,25 +1,22 @@
 /*
  * ion/ioncore/mplexpholder.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 "common.h"
 #include "mplex.h"
 #include "mplexpholder.h"
 #include "llist.h"
-
-
-static void mplex_watch_handler(Watch *watch, Obj *mplex);
+#include "framedpholder.h"
+#include "basicpholder.h"
 
 
 /*{{{ Primitives */
@@ -36,7 +33,7 @@ static void mplexpholder_do_link(WMPlexPHolder *ph,
                                  WMPlexPHolder *after,
                                  WLListNode *or_after)
 {
-    assert(mplex==(WMPlex*)ph->mplex_watch.obj && mplex!=NULL);
+    assert(mplex==(WMPlex*)ph->mplex && mplex!=NULL);
     
     if(after!=NULL){
         assert(after->after==or_after);
@@ -44,28 +41,64 @@ static void mplexpholder_do_link(WMPlexPHolder *ph,
         if(after->after!=NULL){
             LINK_ITEM_AFTER(after->after->phs, after, ph, next, prev);
         }else{
-            assert(on_ph_list(mplex->mx_phs, after));
-            LINK_ITEM_AFTER(mplex->mx_phs, after, ph, next, prev);
+            assert(on_ph_list(mplex->misc_phs, after));
+            LINK_ITEM_AFTER(mplex->misc_phs, after, ph, next, prev);
         }
         ph->after=after->after;
     }else if(or_after!=NULL){
         LINK_ITEM_FIRST(or_after->phs, ph, next, prev);
         ph->after=or_after;
     }else{
-        LINK_ITEM_FIRST(mplex->mx_phs, ph, next, prev);
+        LINK_ITEM_FIRST(mplex->misc_phs, ph, next, prev);
         ph->after=NULL;
     }
 }
 
 
+static WMPlexPHolder *get_head(WMPlexPHolder *ph)
+{
+    while(1){
+        /* ph->prev==NULL should not happen.. */
+        if(ph->prev==NULL || ph->prev->next==NULL)
+            break;
+        ph=ph->prev;
+    }
+    
+    return ph;
+}
+
+
 void mplexpholder_do_unlink(WMPlexPHolder *ph, WMPlex *mplex)
 {
+    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(ph->after!=NULL){
         UNLINK_ITEM(ph->after->phs, ph, next, prev);
-    }else if(mplex!=NULL && on_ph_list(mplex->mx_phs, ph)){
-        UNLINK_ITEM(mplex->mx_phs, ph, next, prev);
+    }else if(mplex!=NULL && on_ph_list(mplex->misc_phs, ph)){
+        UNLINK_ITEM(mplex->misc_phs, ph, next, prev);
+    }else if(ph->prev!=NULL){
+        WMPlexPHolder *next=ph->next;
+
+        ph->prev->next=next;
+
+        if(next==NULL){
+            next=get_head(ph);
+            assert(next->prev==ph);
+        }
+        next->prev=ph->prev;
     }else{
-        assert(ph->next==NULL && ph->prev==NULL);
+        /* 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->after=NULL;
@@ -80,70 +113,65 @@ void mplexpholder_do_unlink(WMPlexPHolder *ph, WMPlex *mplex)
 /*{{{ Init/deinit */
 
 
-static void mplex_watch_handler(Watch *watch, Obj *mplex)
+static void mplex_get_attach_params(WMPlex *mplex, WStacking *st,
+                                    WMPlexAttachParams *param)
 {
-    WMPlexPHolder *ph=FIELD_TO_STRUCT(WMPlexPHolder, mplex_watch, watch);
-    mplexpholder_do_unlink(ph, (WMPlex*)mplex);
-    pholder_redirect(&(ph->ph), (WRegion*)mplex);
+    param->flags=(MPLEX_ATTACH_SIZEPOLICY|
+                  MPLEX_ATTACH_GEOM|
+                  MPLEX_ATTACH_LEVEL|
+                  (st->hidden ? MPLEX_ATTACH_HIDDEN : 0)|
+                  (st->lnode==NULL ? MPLEX_ATTACH_UNNUMBERED : 0));
+    param->szplcy=st->szplcy;
+    param->geom=REGION_GEOM(st->reg);
+    param->level=st->level;
 }
 
 
-static WMPlexAttachParams dummy_param={0, 0, {0, 0, 0, 0}, 0, 0};
-
-
 bool mplexpholder_init(WMPlexPHolder *ph, WMPlex *mplex, WStacking *st,
                        WMPlexAttachParams *param)
 {
+    WLListNode *or_after=NULL;
+    WMPlexPHolder *after=NULL;
+    
     pholder_init(&(ph->ph));
 
-    watch_init(&(ph->mplex_watch));
+    ph->mplex=mplex;
     ph->after=NULL;
     ph->next=NULL;
     ph->prev=NULL;
     ph->param.flags=0;
-    
-    if(!watch_setup(&(ph->mplex_watch), (Obj*)mplex, mplex_watch_handler)){
-        pholder_deinit(&(ph->ph));
-        return FALSE;
-    }
+    ph->recreate_pholder=NULL;
 
-    if(param==NULL)
-        param=&dummy_param;
-    
     if(st!=NULL){
-        if(st->lnode!=NULL)
-            mplexpholder_do_link(ph, mplex, 
-                                 LIST_LAST(st->lnode->phs, next, prev), 
-                                 st->lnode);
-        else
-            ph->param.flags|=MPLEX_ATTACH_UNNUMBERED;
+        mplex_get_attach_params(mplex, st, &ph->param);
         
-        ph->param.flags|=(MPLEX_ATTACH_SIZEPOLICY|
-                          MPLEX_ATTACH_GEOM|
-                          MPLEX_ATTACH_LEVEL|
-                          (st->hidden ? MPLEX_ATTACH_HIDDEN : 0));
-        ph->param.szplcy=st->szplcy;
-        ph->param.geom=REGION_GEOM(st->reg);
-        ph->param.level=st->level;
+        if(st->lnode!=NULL){
+            after=LIST_LAST(st->lnode->phs, next, prev);
+            or_after=st->lnode;
+        }
     }else{
+        static WMPlexAttachParams dummy_param={0, 0, {0, 0, 0, 0}, 0, 0};
+        
+        if(param==NULL)
+            param=&dummy_param;
+        
         ph->param=*param;
         
         if(!(param->flags&MPLEX_ATTACH_UNNUMBERED)){
             int index=(param->flags&MPLEX_ATTACH_INDEX
                        ? param->index
                        : mplex_default_index(mplex));
-            WLListNode *or_after=llist_index_to_after(mplex->mx_list, 
-                                                      mplex->mx_current, 
-                                                      index);
-            WMPlexPHolder *after=(index==LLIST_INDEX_LAST
-                                  ? (or_after!=NULL
-                                     ? LIST_LAST(or_after->phs, next, prev) 
-                                     : LIST_LAST(mplex->mx_phs, next, prev))
-                                  : NULL);
-
-            mplexpholder_do_link(ph, mplex, after, or_after);
+            or_after=llist_index_to_after(mplex->mx_list, 
+                                          mplex->mx_current, index);
+            after=(index==LLIST_INDEX_LAST
+                   ? (or_after!=NULL
+                      ? LIST_LAST(or_after->phs, next, prev) 
+                      : LIST_LAST(mplex->misc_phs, next, prev))
+                   : NULL);
         }
     }
+
+    mplexpholder_do_link(ph, mplex, after, or_after);
     
     return TRUE;
 }
@@ -159,8 +187,7 @@ WMPlexPHolder *create_mplexpholder(WMPlex *mplex,
 
 void mplexpholder_deinit(WMPlexPHolder *ph)
 {
-    mplexpholder_do_unlink(ph, (WMPlex*)ph->mplex_watch.obj);
-    watch_reset(&(ph->mplex_watch));
+    mplexpholder_do_unlink(ph, ph->mplex);
     pholder_deinit(&(ph->ph));
 }
 
@@ -168,17 +195,117 @@ void mplexpholder_deinit(WMPlexPHolder *ph)
 /*}}}*/
 
 
-/*{{{ Move, attach, layer */
+/*{{{ Move, attach */
+
+
+typedef struct{
+    WMPlexPHolder *ph, *ph_head;
+    WRegionAttachData *data;
+    WFramedParam *param;
+    WRegion *reg_ret;
+} RP;
+
+
+static WRegion *recreate_handler(WWindow *par, 
+                                 const WFitParams *fp, 
+                                 void *rp_)
+{
+    RP *rp=(RP*)rp_;
+    WMPlexPHolder *ph=rp->ph, *ph_head=rp->ph_head, *phtmp;
+    WFramedParam *param=rp->param;
+    WFrame *frame;
+    
+    frame=create_frame(par, fp, param->mode);
+    
+    if(frame==NULL)
+        return NULL;
+    
+    /* Move pholders to frame */
+    frame->mplex.misc_phs=ph_head;
+    
+    for(phtmp=frame->mplex.misc_phs; phtmp!=NULL; phtmp=phtmp->next)
+        phtmp->mplex=&frame->mplex;
+        
+    /* Attach */
+    if(fp->mode&(REGION_FIT_BOUNDS|REGION_FIT_WHATEVER))
+        ph->param.flags|=MPLEX_ATTACH_WHATEVER;
+    
+    rp->reg_ret=mplex_do_attach_pholder(&frame->mplex, ph, rp->data);
+
+    ph->param.flags&=~MPLEX_ATTACH_WHATEVER;
+
+    if(rp->reg_ret==NULL){
+        /* Try to recover */
+        for(phtmp=frame->mplex.misc_phs; phtmp!=NULL; phtmp=phtmp->next)
+            phtmp->mplex=NULL;
+        
+        frame->mplex.misc_phs=NULL;
+    
+        destroy_obj((Obj*)frame);
+        
+        return NULL;
+    }else{
+        frame_adjust_to_initial(frame, fp, param, rp->reg_ret);
+        
+        return (WRegion*)frame;
+    }
+}
+
+
+static WFramedPHolder *get_recreate_ph(WMPlexPHolder *ph)
+{
+    return get_head(ph)->recreate_pholder;
+}
+
+    
+static WRegion *mplexpholder_attach_recreate(WMPlexPHolder *ph, int flags,
+                                             WRegionAttachData *data)
+{
+    WRegionAttachData data2;
+    WFramedPHolder *fph;
+    WPHolder *root;
+    WRegion *res;
+    RP rp;
+    
+    rp.ph_head=get_head(ph);
+    
+    assert(rp.ph_head!=NULL);
+    
+    fph=rp.ph_head->recreate_pholder;
+    
+    if(fph==NULL)
+        return NULL;
+    
+    rp.ph=ph;
+    rp.data=data;
+    rp.param=&fph->param;
+    rp.reg_ret=NULL;
+    
+    data2.type=REGION_ATTACH_NEW;
+    data2.u.n.fn=recreate_handler;
+    data2.u.n.param=&rp;
+    
+    res=pholder_do_attach(fph->cont, 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*)fph);
+    }
+    
+    return (flags&PHOLDER_ATTACH_RETURN_CREATEROOT
+            ? (WRegion*)res
+            : rp.reg_ret);
+}
 
 
 WRegion *mplexpholder_do_attach(WMPlexPHolder *ph, int flags,
                                 WRegionAttachData *data)
 {
-    WMPlex *mplex=(WMPlex*)ph->mplex_watch.obj;
-    WRegion *reg=NULL;
+    WMPlex *mplex=ph->mplex;
     
     if(mplex==NULL)
-        return FALSE;
+        return mplexpholder_attach_recreate(ph, flags, data);
     
     if(flags&PHOLDER_ATTACH_SWITCHTO)
         ph->param.flags|=MPLEX_ATTACH_SWITCHTO;
@@ -192,18 +319,14 @@ WRegion *mplexpholder_do_attach(WMPlexPHolder *ph, int flags,
 bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex, 
                        WMPlexPHolder *after,
                        WLListNode *or_after)
-
 {
-    mplexpholder_do_unlink(ph, (WMPlex*)ph->mplex_watch.obj);
+    mplexpholder_do_unlink(ph, ph->mplex);
 
-    watch_reset(&(ph->mplex_watch));
-    
+    ph->mplex=mplex;
+        
     if(mplex==NULL)
         return TRUE;
     
-    if(!watch_setup(&(ph->mplex_watch), (Obj*)mplex, mplex_watch_handler))
-        return FALSE;
-
     mplexpholder_do_link(ph, mplex, after, or_after);
     
     return TRUE;
@@ -212,18 +335,47 @@ bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex,
 
 bool mplexpholder_do_goto(WMPlexPHolder *ph)
 {
-    WMPlex *mplex=(WMPlex*)ph->mplex_watch.obj;
-    
-    if(mplex!=NULL)
-        return region_goto((WRegion*)mplex);
+    WRegion *reg=(WRegion*)ph->mplex;
     
-    return FALSE;
+    if(reg!=NULL){
+        return region_goto(reg);
+    }else{
+        WFramedPHolder *fph=get_recreate_ph(ph);
+        
+        return (fph!=NULL
+                ? pholder_do_goto((WPHolder*)fph)
+                : FALSE);
+    }
 }
 
 
 WRegion *mplexpholder_do_target(WMPlexPHolder *ph)
 {
-    return (WRegion*)ph->mplex_watch.obj;
+    WRegion *reg=(WRegion*)ph->mplex;
+    
+    if(reg!=NULL){
+        return reg;
+    }else{
+        WFramedPHolder *fph=get_recreate_ph(ph);
+        
+        return (fph!=NULL
+                ? pholder_do_target((WPHolder*)fph)
+                : NULL);
+    }
+}
+
+
+bool mplexpholder_stale(WMPlexPHolder *ph)
+{
+    WRegion *reg=(WRegion*)ph->mplex;
+    
+    if(reg!=NULL){
+        return FALSE;
+    }else{
+        WFramedPHolder *fph=get_recreate_ph(ph);
+        
+        return (fph==NULL || pholder_stale((WPHolder*)fph));
+    }
 }
 
 
@@ -260,7 +412,7 @@ void mplex_move_phs_before(WMPlex *mplex, WLListNode *node)
                          
     after=(or_after!=NULL
            ? LIST_LAST(or_after->phs, next, prev)
-           : LIST_LAST(mplex->mx_phs, next, prev));
+           : LIST_LAST(mplex->misc_phs, next, prev));
         
     mplex_move_phs(mplex, node, after, or_after);
 }
@@ -277,11 +429,78 @@ WMPlexPHolder *mplex_managed_get_pholder(WMPlex *mplex, WRegion *mgd)
 }
 
 
-WMPlexPHolder *mplex_get_rescue_pholder_for(WMPlex *mplex, WRegion *mgd)
+void mplex_flatten_phs(WMPlex *mplex)
+{
+    WLListNode *node;
+    WLListIterTmp tmp;
+
+    FOR_ALL_NODES_ON_LLIST(node, mplex->mx_list, tmp){
+        WMPlexPHolder *last=(mplex->misc_phs==NULL ? NULL : mplex->misc_phs->prev);
+        mplex_move_phs(mplex, node, last, NULL);
+    }
+}
+
+
+void mplex_migrate_phs(WMPlex *src, WMPlex *dst)
+{
+    WLListNode *or_after=LIST_LAST(dst->mx_list, next, prev);
+    WMPlexPHolder *after=(or_after!=NULL
+                          ? LIST_LAST(or_after->phs, next, prev)
+                          : LIST_LAST(dst->misc_phs, next, prev));
+    
+    while(src->misc_phs!=NULL){
+        WMPlexPHolder *ph=src->misc_phs;
+        mplexpholder_move(ph, dst, after, or_after);
+        after=ph;
+    }
+}
+
+
+/*}}}*/
+
+
+/*{{ Rescue */
+
+
+WRegion *mplex_rescue_attach(WMPlex *mplex, int flags, WRegionAttachData *data)
+{
+    WMPlexAttachParams param;
+    
+    param.flags=0;
+    
+    /* Improved attach parametrisation hack for WMPlex source */
+    if(data->type==REGION_ATTACH_REPARENT){
+        WRegion *reg=data->u.reg;
+        WMPlex *src_mplex=REGION_MANAGER_CHK(reg, WMPlex);
+        if(src_mplex!=NULL){
+            WStacking *st=ioncore_find_stacking(reg);
+            if(st!=NULL)
+                mplex_get_attach_params(src_mplex, st, &param);
+        }
+    }
+    
+    param.flags|=(MPLEX_ATTACH_INDEX|
+                  (flags&PHOLDER_ATTACH_SWITCHTO ? MPLEX_ATTACH_SWITCHTO : 0));
+    param.index=LLIST_INDEX_LAST;
+
+    return mplex_do_attach(mplex, &param, data);
+}
+
+
+WPHolder *mplex_get_rescue_pholder_for(WMPlex *mplex, WRegion *mgd)
 {
+#if 0
     WStacking *st=mplex_find_stacking(mplex, mgd);
+    WMPlexAttachParams param;
+    
+    param.flags=MPLEX_ATTACH_INDEX;
+    param.index=LLIST_INDEX_LAST;
     
-    return create_mplexpholder(mplex, st, NULL);
+    return create_mplexpholder(mplex, st, &param);
+#else
+    return (WPHolder*)create_basicpholder((WRegion*)mplex, 
+                                          (WBasicPHolderHandler*)mplex_rescue_attach);
+#endif
 }
 
 
@@ -300,6 +519,9 @@ static DynFunTab mplexpholder_dynfuntab[]={
 
     {(DynFun*)pholder_do_target, 
      (DynFun*)mplexpholder_do_target},
+     
+    {(DynFun*)pholder_stale, 
+     (DynFun*)mplexpholder_stale},
 
     END_DYNFUNTAB
 };