]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/mplexpholder.c
Update cfg_kludge_flash for Flash 10
[ion3.git] / ioncore / mplexpholder.c
index c3a57ce5979b178fe5415c2d6f6278d4bdd7609d..2c8461eeade2e9d93d001d973b159ee9ec81e521 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ion/ioncore/mplexpholder.c
  *
- * Copyright (c) Tuomo Valkonen 2005-2007
+ * Copyright (c) Tuomo Valkonen 2005-2009
  *
  * See the included file LICENSE for details.
  */
@@ -9,15 +9,14 @@
 #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"
 #include "framedpholder.h"
-
-
-static void mplex_watch_handler(Watch *watch, Obj *mplex);
+#include "basicpholder.h"
 
 
 /*{{{ Primitives */
@@ -34,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);
@@ -42,44 +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->prev!=NULL)
-            ph->prev->recreate_pholder=ph->recreate_pholder;
-        else
-            destroy_obj((Obj*)ph->recreate_pholder);
+        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{
+    }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;
-    
-        assert((ph->next==NULL && ph->prev==NULL)
-               || ph->mplex_watch.obj==NULL);
-        
-        if(ph->next!=NULL)
-            ph->next->prev=ph->prev;
-        if(ph->prev!=NULL)
-            ph->prev->next=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->after=NULL;
@@ -94,71 +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;
     ph->recreate_pholder=NULL;
-    
-    if(!watch_setup(&(ph->mplex_watch), (Obj*)mplex, mplex_watch_handler)){
-        pholder_deinit(&(ph->ph));
-        return FALSE;
-    }
 
-    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;
 }
@@ -174,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));
 }
 
@@ -190,18 +202,18 @@ typedef struct{
     WMPlexPHolder *ph, *ph_head;
     WRegionAttachData *data;
     WFramedParam *param;
+    WRegion *reg_ret;
 } RP;
 
 
-WRegion *recreate_handler(WWindow *par, 
-                          const WFitParams *fp, 
-                          void *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;
-    WRegion *reg;
     
     frame=create_frame(par, fp, param->mode);
     
@@ -209,49 +221,37 @@ WRegion *recreate_handler(WWindow *par,
         return NULL;
     
     /* Move pholders to frame */
-    frame->mplex.mx_phs=ph_head;
+    frame->mplex.misc_phs=ph_head;
     
-    for(phtmp=frame->mplex.mx_phs; phtmp!=NULL; phtmp=phtmp->next)
-        watch_setup(&(phtmp->mplex_watch), (Obj*)frame, mplex_watch_handler);
+    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;
     
-    reg=mplex_do_attach_pholder(&frame->mplex, ph, rp->data);
+    rp->reg_ret=mplex_do_attach_pholder(&frame->mplex, ph, rp->data);
 
     ph->param.flags&=~MPLEX_ATTACH_WHATEVER;
 
-    if(reg==NULL){
+    if(rp->reg_ret==NULL){
         /* Try to recover */
-        for(phtmp=frame->mplex.mx_phs; phtmp!=NULL; phtmp=phtmp->next)
-            watch_reset(&(phtmp->mplex_watch));
-        frame->mplex.mx_phs=NULL;
+        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, reg);
+        frame_adjust_to_initial(frame, fp, param, rp->reg_ret);
         
         return (WRegion*)frame;
     }
 }
 
 
-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;
-}
-
-
 static WFramedPHolder *get_recreate_ph(WMPlexPHolder *ph)
 {
     return get_head(ph)->recreate_pholder;
@@ -264,7 +264,7 @@ static WRegion *mplexpholder_attach_recreate(WMPlexPHolder *ph, int flags,
     WRegionAttachData data2;
     WFramedPHolder *fph;
     WPHolder *root;
-    WRegion *reg;
+    WRegion *res;
     RP rp;
     
     rp.ph_head=get_head(ph);
@@ -279,26 +279,30 @@ static WRegion *mplexpholder_attach_recreate(WMPlexPHolder *ph, int flags,
     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;
     
-    reg=pholder_do_attach(fph->cont, flags, &data2); /* == frame */
+    res=pholder_do_attach(fph->cont, flags, &data2);
     
-    if(reg!=NULL){
-        destroy_obj((Obj*)fph);
+    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 reg;
+    
+    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;
+    WMPlex *mplex=ph->mplex;
     
     if(mplex==NULL)
         return mplexpholder_attach_recreate(ph, flags, data);
@@ -315,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;
@@ -335,7 +335,7 @@ bool mplexpholder_move(WMPlexPHolder *ph, WMPlex *mplex,
 
 bool mplexpholder_do_goto(WMPlexPHolder *ph)
 {
-    WRegion *reg=(WRegion*)ph->mplex_watch.obj;
+    WRegion *reg=(WRegion*)ph->mplex;
     
     if(reg!=NULL){
         return region_goto(reg);
@@ -351,7 +351,7 @@ bool mplexpholder_do_goto(WMPlexPHolder *ph)
 
 WRegion *mplexpholder_do_target(WMPlexPHolder *ph)
 {
-    WRegion *reg=(WRegion*)ph->mplex_watch.obj;
+    WRegion *reg=(WRegion*)ph->mplex;
     
     if(reg!=NULL){
         return reg;
@@ -365,24 +365,16 @@ WRegion *mplexpholder_do_target(WMPlexPHolder *ph)
 }
 
 
-WPHolder *mplexpholder_do_root(WMPlexPHolder *ph)
+bool mplexpholder_stale(WMPlexPHolder *ph)
 {
-    WRegion *reg=(WRegion*)ph->mplex_watch.obj;
+    WRegion *reg=(WRegion*)ph->mplex;
     
     if(reg!=NULL){
-        return &ph->ph;
+        return FALSE;
     }else{
         WFramedPHolder *fph=get_recreate_ph(ph);
-        WPHolder *root;
         
-        if(fph==NULL)
-            return NULL;
-    
-        root=pholder_root((WPHolder*)fph);
-    
-        return (root!=(WPHolder*)fph
-                ? root
-                : &ph->ph);
+        return (fph==NULL || pholder_stale((WPHolder*)fph));
     }
 }
 
@@ -420,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);
 }
@@ -437,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
 }
 
 
@@ -461,8 +520,8 @@ static DynFunTab mplexpholder_dynfuntab[]={
     {(DynFun*)pholder_do_target, 
      (DynFun*)mplexpholder_do_target},
      
-    {(DynFun*)pholder_do_root
-     (DynFun*)mplexpholder_do_root},
+    {(DynFun*)pholder_stale
+     (DynFun*)mplexpholder_stale},
 
     END_DYNFUNTAB
 };