]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/clientwin.c
Merge commit '20070318' into HEAD
[ion3.git] / ioncore / clientwin.c
index 4b4dbe4a56ab4011a5f28071b9d3a423e0f00855..4a5b4dacfd40ae08492058395d0d826df1b6c6dc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ion/ioncore/clientwin.c
  *
- * Copyright (c) Tuomo Valkonen 1999-2006
+ * 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
@@ -41,6 +41,9 @@
 #include "netwm.h"
 #include "xwindow.h"
 #include "bindmaps.h"
+#include "return.h"
+#include "conf.h"
+#include "group.h"
 
 
 static void set_clientwin_state(WClientWin *cwin, int state);
@@ -78,22 +81,6 @@ void clientwin_get_protocols(WClientWin *cwin)
 }
 
 
-static bool get_winprop_fn_set=FALSE;
-static ExtlFn get_winprop_fn;
-
-/*EXTL_DOC
- * Set function used to look up winprops.
- */
-EXTL_EXPORT
-void ioncore_set_get_winprop_fn(ExtlFn fn)
-{
-    if(get_winprop_fn_set)
-        extl_unref_fn(get_winprop_fn);
-    get_winprop_fn=extl_ref_fn(fn);
-    get_winprop_fn_set=TRUE;
-}
-
-
 static WSizePolicy get_sizepolicy_winprop(WClientWin *cwin,
                                           const char *propname,
                                           WSizePolicy value)
@@ -108,27 +95,38 @@ static WSizePolicy get_sizepolicy_winprop(WClientWin *cwin,
 }
 
 
-#define SIZEHINT_PROPS (CLIENTWIN_PROP_MAXSIZE| \
-                        CLIENTWIN_PROP_MINSIZE| \
-                        CLIENTWIN_PROP_ASPECT| \
-                        CLIENTWIN_PROP_IGNORE_RSZINC)
+#define SIZEHINT_PROPS (CLIENTWIN_PROP_MAXSIZE|   \
+                        CLIENTWIN_PROP_MINSIZE|   \
+                        CLIENTWIN_PROP_ASPECT|    \
+                        CLIENTWIN_PROP_RSZINC|    \
+                        CLIENTWIN_PROP_I_MAXSIZE| \
+                        CLIENTWIN_PROP_I_MINSIZE| \
+                        CLIENTWIN_PROP_I_ASPECT|  \
+                        CLIENTWIN_PROP_I_RSZINC)
+
+
+#define DO_SZH(NAME, FLAG, IFLAG, SZHFLAG, W, H, C)  \
+    if(extl_table_is_bool_set(tab, "ignore_" NAME)){ \
+        cwin->flags|=IFLAG;                          \
+    }else if(extl_table_gets_t(tab, NAME, &tab2)){   \
+        if(extl_table_gets_i(tab2, "w", &i1) &&      \
+           extl_table_gets_i(tab2, "h", &i2)){       \
+            cwin->size_hints.W=i1;                   \
+            cwin->size_hints.H=i2;                   \
+            C                                        \
+            cwin->size_hints.flags|=SZHFLAG;         \
+            cwin->flags|=FLAG;                       \
+        }                                            \
+        extl_unref_table(tab2);                      \
+    }
 
 
 static void clientwin_get_winprops(WClientWin *cwin)
 {
     ExtlTab tab, tab2;
     int i1, i2;
-    bool ret;
-    
-    if(!get_winprop_fn_set)
-        return;
     
-    extl_protect(NULL);
-    ret=extl_call(get_winprop_fn, "o", "t", cwin, &tab);
-    extl_unprotect(NULL);
-
-    if(!ret)
-        return;
+    tab=ioncore_get_winprop(cwin);
     
     cwin->proptab=tab;
     
@@ -141,44 +139,21 @@ static void clientwin_get_winprops(WClientWin *cwin)
     if(extl_table_is_bool_set(tab, "acrobatic"))
         cwin->flags|=CLIENTWIN_PROP_ACROBATIC;
     
-    if(extl_table_gets_t(tab, "max_size", &tab2)){
-        if(extl_table_gets_i(tab2, "w", &i1) &&
-           extl_table_gets_i(tab2, "h", &i2)){
-            cwin->size_hints.max_width=i1;
-            cwin->size_hints.max_height=i2;
-            cwin->size_hints.flags|=PMaxSize;
-            cwin->flags|=CLIENTWIN_PROP_MAXSIZE;
-        }
-        extl_unref_table(tab2);
-    }
-
-    if(extl_table_gets_t(tab, "min_size", &tab2)){
-        if(extl_table_gets_i(tab2, "w", &i1) &&
-           extl_table_gets_i(tab2, "h", &i2)){
-            cwin->size_hints.min_width=i1;
-            cwin->size_hints.min_height=i2;
-            cwin->size_hints.flags|=PMinSize;
-            cwin->flags|=CLIENTWIN_PROP_MINSIZE;
-        }
-        extl_unref_table(tab2);
-    }
-
-    if(extl_table_gets_t(tab, "aspect", &tab2)){
-        if(extl_table_gets_i(tab2, "w", &i1) &&
-           extl_table_gets_i(tab2, "h", &i2)){
-            cwin->size_hints.min_aspect.x=i1;
-            cwin->size_hints.max_aspect.x=i1;
-            cwin->size_hints.min_aspect.y=i2;
-            cwin->size_hints.max_aspect.y=i2;
-            cwin->size_hints.flags|=PAspect;
-            cwin->flags|=CLIENTWIN_PROP_ASPECT;
-        }
-        extl_unref_table(tab2);
-    }
-    
-    if(extl_table_is_bool_set(tab, "ignore_resizeinc"))
-        cwin->flags|=CLIENTWIN_PROP_IGNORE_RSZINC;
-
+    DO_SZH("max_size", CLIENTWIN_PROP_MAXSIZE, CLIENTWIN_PROP_I_MAXSIZE,
+           PMaxSize, max_width, max_height, );
+           
+    DO_SZH("min_size", CLIENTWIN_PROP_MINSIZE, CLIENTWIN_PROP_I_MINSIZE,
+           PMinSize, min_width, min_height, );
+           
+    DO_SZH("resizeinc", CLIENTWIN_PROP_RSZINC, CLIENTWIN_PROP_I_RSZINC,
+           PResizeInc, width_inc, height_inc, );
+
+    DO_SZH("aspect", CLIENTWIN_PROP_ASPECT, CLIENTWIN_PROP_I_ASPECT,
+           PAspect, min_aspect.x, min_aspect.y, 
+           { cwin->size_hints.max_aspect.x=i1;
+             cwin->size_hints.max_aspect.y=i2;
+           });
+           
     if(extl_table_is_bool_set(tab, "ignore_cfgrq"))
         cwin->flags|=CLIENTWIN_PROP_IGNORE_CFGRQ;
 
@@ -198,26 +173,37 @@ void clientwin_get_size_hints(WClientWin *cwin)
     
     xwindow_get_sizehints(cwin->win, &(cwin->size_hints));
     
-    if(cwin->flags&CLIENTWIN_PROP_MAXSIZE){
+    if(cwin->flags&CLIENTWIN_PROP_I_MAXSIZE){
+        cwin->size_hints.flags&=~PMaxSize;
+    }else if(cwin->flags&CLIENTWIN_PROP_MAXSIZE){
         cwin->size_hints.max_width=tmp.max_width;
         cwin->size_hints.max_height=tmp.max_height;
         cwin->size_hints.flags|=PMaxSize;
     }
-
-    if(cwin->flags&CLIENTWIN_PROP_MINSIZE){
+    
+    if(cwin->flags&CLIENTWIN_PROP_I_MINSIZE){
+        cwin->size_hints.flags&=~PMinSize;
+    }else if(cwin->flags&CLIENTWIN_PROP_MINSIZE){
         cwin->size_hints.min_width=tmp.min_width;
         cwin->size_hints.min_height=tmp.min_height;
         cwin->size_hints.flags|=PMinSize;
     }
     
-    if(cwin->flags&CLIENTWIN_PROP_ASPECT){
+    if(cwin->flags&CLIENTWIN_PROP_I_ASPECT){
+        cwin->size_hints.flags&=~PAspect;
+    }else if(cwin->flags&CLIENTWIN_PROP_ASPECT){
         cwin->size_hints.min_aspect=tmp.min_aspect;
         cwin->size_hints.max_aspect=tmp.max_aspect;
         cwin->size_hints.flags|=PAspect;
     }
     
-    if(cwin->flags&CLIENTWIN_PROP_IGNORE_RSZINC)
+    if(cwin->flags&CLIENTWIN_PROP_I_RSZINC){
         cwin->size_hints.flags&=~PResizeInc;
+    }else if(cwin->flags&CLIENTWIN_PROP_RSZINC){
+        cwin->size_hints.width_inc=tmp.width_inc;
+        cwin->size_hints.height_inc=tmp.height_inc;
+        cwin->size_hints.flags|=PResizeInc;
+    }
 }
 
 
@@ -346,8 +332,6 @@ static bool clientwin_init(WClientWin *cwin, WWindow *par, Window win,
     cwin->n_cmapwins=0;
     cwin->event_mask=IONCORE_EVENTMASK_CLIENTWIN;
 
-    cwin->fs_pholder=NULL;
-
     region_init(&(cwin->region), par, &fp);
 
     cwin->region.flags|=REGION_GRAB_ON_PARENT;
@@ -376,26 +360,6 @@ static WClientWin *create_clientwin(WWindow *par, Window win,
 }
 
 
-static bool handle_target_prop(WClientWin *cwin, const WManageParams *param)
-{
-    WRegion *r=NULL;
-    char *target_name=NULL;
-    
-    if(extl_table_gets_s(cwin->proptab, "target", &target_name)){
-        r=ioncore_lookup_region(target_name, NULL);
-        
-        free(target_name);
-    
-        if(r!=NULL){
-            if(region_manage_clientwin(r, cwin, param, 
-                                       MANAGE_REDIR_PREFER_NO))
-                return TRUE;
-        }
-    }
-    
-    return FALSE;
-}
-
 
 WClientWin *clientwin_get_transient_for(const WClientWin *cwin)
 {
@@ -484,6 +448,7 @@ WClientWin* ioncore_manage_clientwin(Window win, bool maprq)
     XWMHints *hints;
     int init_state=NormalState;
     WManageParams param=MANAGEPARAMS_INIT;
+    void *mrshpm[2];
 
     param.dockapp=FALSE;
     
@@ -564,7 +529,6 @@ again:
 
     param.geom=REGION_GEOM(cwin);
     param.maprq=maprq;
-    param.userpos=(cwin->size_hints.flags&USPosition);
     param.switchto=(init_state!=IconicState && clientwin_get_switchto(cwin));
     param.jumpto=extl_table_is_bool_set(cwin->proptab, "jumpto");
     param.gravity=(cwin->size_hints.flags&PWinGravity
@@ -572,6 +536,9 @@ again:
                    : ForgetGravity);
     param.tfor=clientwin_get_transient_for(cwin);
     
+    if(!extl_table_gets_b(cwin->proptab, "userpos", &param.userpos))
+        param.userpos=(cwin->size_hints.flags&USPosition);
+    
     if(cwin->flags&SIZEHINT_PROPS){
         /* If size hints have been messed with, readjust requested geometry
          * here. If programs themselves give incompatible geometries and
@@ -581,21 +548,14 @@ again:
                                   FALSE);
     }
 
-    if(!handle_target_prop(cwin, &param)){
-        bool managed;
-        void *mrshpm[2];
+    mrshpm[0]=cwin;
+    mrshpm[1]=&param;
         
-        mrshpm[0]=cwin;
-        mrshpm[1]=&param;
-        
-        managed=hook_call_alt(clientwin_do_manage_alt, &mrshpm, 
-                              (WHookMarshall*)do_manage_mrsh,
-                              (WHookMarshallExtl*)do_manage_mrsh_extl);
-
-        if(!managed){
-            warn(TR("Unable to manage client window %#x."), win);
-            goto failure;
-        }
+    if(!hook_call_alt(clientwin_do_manage_alt, &mrshpm, 
+                      (WHookMarshall*)do_manage_mrsh,
+                      (WHookMarshallExtl*)do_manage_mrsh_extl)){
+        warn(TR("Unable to manage client window %#x."), win);
+        goto failure;
     }
     
     if(ioncore_g.opmode==IONCORE_OPMODE_NORMAL &&
@@ -604,7 +564,6 @@ again:
         region_set_activity((WRegion*)cwin, SETPARAM_SET);
     }
     
-    
     if(postmanage_check(cwin, &attr)){
         if(param.jumpto && ioncore_g.focus_next==NULL)
             region_goto((WRegion*)cwin);
@@ -696,6 +655,8 @@ void clientwin_deinit(WClientWin *cwin)
     WRegion *reg;
     
     if(cwin->win!=None){
+        region_pointer_focus_hack(&cwin->region);
+
         xwindow_unmanaged_selectinput(cwin->win, 0);
         XUnmapWindow(ioncore_g.dpy, cwin->win);
         
@@ -721,12 +682,6 @@ void clientwin_deinit(WClientWin *cwin)
     
     clientwin_clear_colormaps(cwin);
     
-    if(cwin->fs_pholder!=NULL){
-        WPHolder *ph=cwin->fs_pholder;
-        cwin->fs_pholder=NULL;
-        destroy_obj((Obj*)ph);
-    }
-    
     region_deinit((WRegion*)cwin);
 }
 
@@ -747,12 +702,13 @@ static bool mrsh_u_extl(ExtlFn fn, void *param)
 
 static void clientwin_do_unmapped(WClientWin *cwin, Window win)
 {
-    bool mcf=region_may_control_focus((WRegion*)cwin);
-
-    if(mcf && cwin->fs_pholder!=NULL)
-        pholder_goto(cwin->fs_pholder);
+    cwin->flags|=CLIENTWIN_UNMAP_RQ;
     
-    destroy_obj((Obj*)cwin);
+    /* First try a graceful chain-dispose */
+    if(!region_rqdispose((WRegion*)cwin)){
+        /* But force dispose anyway */
+        region_dispose((WRegion*)cwin);
+    }
     
     hook_call(clientwin_unmapped_hook, &win, mrsh_u_c, mrsh_u_extl);
 }
@@ -808,7 +764,7 @@ void clientwin_kill(WClientWin *cwin)
 }
 
 
-bool clientwin_rqclose(WClientWin *cwin, bool relocate_ignored)
+void clientwin_rqclose(WClientWin *cwin, bool relocate_ignored)
 {
     /* Ignore relocate parameter -- client windows can always be 
      * destroyed by the application in any case, so way may just as
@@ -818,10 +774,8 @@ bool clientwin_rqclose(WClientWin *cwin, bool relocate_ignored)
     if(cwin->flags&CLIENTWIN_P_WM_DELETE){
         send_clientmsg(cwin->win, ioncore_g.atom_wm_delete, 
                        ioncore_get_timestamp());
-        return TRUE;
     }else{
         warn(TR("Client does not support the WM_DELETE protocol."));
-        return FALSE;
     }
 }
 
@@ -843,6 +797,8 @@ static void set_clientwin_state(WClientWin *cwin, int state)
 
 static void hide_clientwin(WClientWin *cwin)
 {
+    region_pointer_focus_hack(&cwin->region);
+
     if(cwin->flags&CLIENTWIN_PROP_ACROBATIC){
         XMoveWindow(ioncore_g.dpy, cwin->win,
                     -2*REGION_GEOM(cwin).w, -2*REGION_GEOM(cwin).h);
@@ -981,15 +937,8 @@ static bool clientwin_fitrep(WClientWin *cwin, WWindow *np,
         region_set_parent((WRegion*)cwin, np);
         sendconfig_clientwin(cwin);
         
-        if(!REGION_IS_FULLSCREEN(cwin) && cwin->fs_pholder!=NULL){
-            WPHolder *ph=cwin->fs_pholder;
-            cwin->fs_pholder=NULL;
+        if(!REGION_IS_FULLSCREEN(cwin))
             cwin->flags&=~CLIENTWIN_FS_RQ;
-            /* Can't destroy it yet - messes up mplex placeholder
-             * reorganisation.
-             */
-            mainloop_defer_destroy((Obj*)ph);
-        }
 
         netwm_update_state(cwin);
     }
@@ -1122,26 +1071,31 @@ ExtlTab clientwin_get_ident(WClientWin *cwin)
 /*{{{ ConfigureRequest */
 
 
-void clientwin_handle_configure_request(WClientWin *cwin,
-                                        XConfigureRequestEvent *ev)
+static bool check_fs_cfgrq(WClientWin *cwin, XConfigureRequestEvent *ev)
 {
-    if(ev->value_mask&CWBorderWidth)
-        cwin->orig_bw=ev->border_width;
-    
-    if(cwin->flags&CLIENTWIN_PROP_IGNORE_CFGRQ){
-        sendconfig_clientwin(cwin);
-        return;
-    }
-
     /* check full screen request */
     if((ev->value_mask&(CWWidth|CWHeight))==(CWWidth|CWHeight)){
-        bool sw=clientwin_fullscreen_may_switchto(cwin);
-        if(clientwin_check_fullscreen_request(cwin, ev->width, ev->height, sw))
-            return;
+        WRegion *grp=region_groupleader_of((WRegion*)cwin);
+        WScreen *scr=clientwin_fullscreen_chkrq(cwin, ev->width, ev->height);
+        
+        if(scr!=NULL && REGION_MANAGER(grp)!=(WRegion*)scr){
+            bool sw=clientwin_fullscreen_may_switchto(cwin);
+            
+            cwin->flags|=CLIENTWIN_FS_RQ;
+            
+            if(!region_fullscreen_scr(grp, scr, sw))
+                cwin->flags&=~CLIENTWIN_FS_RQ;
+        }
+        
+        return TRUE;
     }
 
-    cwin->flags|=CLIENTWIN_NEED_CFGNTFY;
+    return FALSE;
+}
 
+
+static bool check_normal_cfgrq(WClientWin *cwin, XConfigureRequestEvent *ev)
+{
     if(ev->value_mask&(CWX|CWY|CWWidth|CWHeight)){
         WRQGeomParams rq=RQGEOMPARAMS_INIT;
         int gdx=0, gdy=0;
@@ -1196,6 +1150,25 @@ void clientwin_handle_configure_request(WClientWin *cwin,
         }
         
         region_rqgeom((WRegion*)cwin, &rq, NULL);
+        
+        return TRUE;
+    }
+    
+    return FALSE;
+}
+
+
+void clientwin_handle_configure_request(WClientWin *cwin,
+                                        XConfigureRequestEvent *ev)
+{
+    if(ev->value_mask&CWBorderWidth)
+        cwin->orig_bw=ev->border_width;
+    
+    cwin->flags|=CLIENTWIN_NEED_CFGNTFY;
+
+    if(!(cwin->flags&CLIENTWIN_PROP_IGNORE_CFGRQ)){
+        if(!check_fs_cfgrq(cwin, ev))
+            check_normal_cfgrq(cwin, ev);
     }
 
     if(cwin->flags&CLIENTWIN_NEED_CFGNTFY){