]> git.decadent.org.uk Git - ion3.git/blobdiff - ioncore/rootwin.c
Imported Upstream version 20090110
[ion3.git] / ioncore / rootwin.c
index 5fc4891aff5c60fb1958b85772f413d2a3f4063d..c206e3d9587ac56ae55c1042f051a9a24b438435 100644 (file)
@@ -1,12 +1,9 @@
 /*
  * ion/ioncore/rootwin.c
  *
- * Copyright (c) Tuomo Valkonen 1999-2006
+ * Copyright (c) Tuomo Valkonen 1999-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 <unistd.h>
 #include <stdio.h>
 #include <X11/Xlib.h>
 #include <X11/Xproto.h>
-/*#include <X11/Xmu/Error.h>*/
-#ifdef CF_XINERAMA
-#include <X11/extensions/Xinerama.h>
-#elif defined(CF_SUN_XINERAMA)
-#include <X11/extensions/xinerama.h>
-#endif
 
 #include <libtu/objp.h>
 #include "common.h"
@@ -68,9 +59,13 @@ static int my_error_handler(Display *dpy, XErrorEvent *ev)
     
     /* Just ignore bad window and similar errors; makes the rest of
      * the code simpler.
+     * 
+     * Apparently XGetWindowProperty can return BadMatch on a race
+     * condition where the server is already reusing the XID for a 
+     * non-window drawable, so let's just ignore BadMatch entirely...
      */
     if((ev->error_code==BadWindow ||
-        (ev->error_code==BadMatch && ev->request_code==X_SetInputFocus) ||
+        (ev->error_code==BadMatch /*&& ev->request_code==X_SetInputFocus*/) ||
         (ev->error_code==BadDrawable && ev->request_code==X_GetGeometry)) &&
        ignore_badwindow)
         return 0;
@@ -201,13 +196,14 @@ static void preinit_gr(WRootWin *rootwin)
 }
 
 
-static WRootWin *preinit_rootwin(int xscr)
+static Atom net_virtual_roots=None;
+
+
+static bool rootwin_init(WRootWin *rootwin, int xscr)
 {
     Display *dpy=ioncore_g.dpy;
-    WRootWin *rootwin;
     WFitParams fp;
     Window root;
-    int i;
     
     /* Try to select input on the root window */
     root=RootWindow(dpy, xscr);
@@ -215,24 +211,16 @@ static WRootWin *preinit_rootwin(int xscr)
     redirect_error=FALSE;
 
     XSetErrorHandler(my_redirect_error_handler);
-    XSelectInput(dpy, root, IONCORE_EVENTMASK_ROOT);
+    XSelectInput(dpy, root, IONCORE_EVENTMASK_ROOT|IONCORE_EVENTMASK_SCREEN);
     XSync(dpy, 0);
     XSetErrorHandler(my_error_handler);
 
     if(redirect_error){
         warn(TR("Unable to redirect root window events for screen %d."),
              xscr);
-        return NULL;
+        return FALSE;
     }
     
-    rootwin=ALLOC(WRootWin);
-    
-    if(rootwin==NULL)
-        return NULL;
-    
-    /* Init the struct */
-    OBJ_INIT(rootwin, WRootWin);
-
     rootwin->xscr=xscr;
     rootwin->default_cmap=DefaultColormap(dpy, xscr);
     rootwin->tmpwins=NULL;
@@ -245,14 +233,12 @@ static WRootWin *preinit_rootwin(int xscr)
     fp.g.w=DisplayWidth(dpy, xscr);
     fp.g.h=DisplayHeight(dpy, xscr);
     
-    if(!window_do_init((WWindow*)rootwin, NULL, root, &fp)){
+    if(!screen_init((WScreen*)rootwin, NULL, &fp, xscr, root)){
         free(rootwin);
-        return NULL;
+        return FALSE;
     }
 
-    /* Note: this mask isn't right if some WScreen auses the same window. */
-    ((WWindow*)rootwin)->event_mask=IONCORE_EVENTMASK_ROOT;
-    
+    ((WWindow*)rootwin)->event_mask=IONCORE_EVENTMASK_ROOT|IONCORE_EVENTMASK_SCREEN;
     ((WRegion*)rootwin)->flags|=REGION_BINDINGS_ARE_GRABBED|REGION_PLEASE_WARP;
     ((WRegion*)rootwin)->rootwin=rootwin;
     
@@ -264,218 +250,20 @@ static WRootWin *preinit_rootwin(int xscr)
     preinit_gr(rootwin);
     netwm_init_rootwin(rootwin);
     
-    region_add_bindmap((WRegion*)rootwin, ioncore_rootwin_bindmap);
-    
-    return rootwin;
-}
-
-
-static Atom net_virtual_roots=None;
-
+    net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
+    XDeleteProperty(ioncore_g.dpy, root, net_virtual_roots);
 
-static WScreen *add_screen(WRootWin *rw, int id, const WRectangle *geom, 
-                           bool useroot)
-{
-    WScreen *scr;
-    CARD32 p[1];
-    WFitParams fp;
-    
-    fp.g=*geom;
-    fp.mode=REGION_FIT_EXACT;
-    
-#ifdef CF_ALWAYS_VIRTUAL_ROOT
-    useroot=FALSE;
-#endif
+    LINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rootwin, p_next, p_prev);
 
-    scr=create_screen(rw, id, &fp, useroot);
+    xwindow_set_cursor(root, IONCORE_CURSOR_DEFAULT);
     
-    if(scr==NULL)
-        return NULL;
-    
-    region_set_manager((WRegion*)scr, (WRegion*)rw);
-    
-    region_map((WRegion*)scr);
-
-    if(!useroot){
-        p[0]=region_xwindow((WRegion*)scr);
-        XChangeProperty(ioncore_g.dpy, WROOTWIN_ROOT(rw), net_virtual_roots,
-                        XA_WINDOW, 32, PropModeAppend, (uchar*)&(p[0]), 1);
-    }
-
-    return scr;
-}
-
-
-#ifdef CF_XINERAMA
-static bool xinerama_sanity_check(XineramaScreenInfo *xi, int nxi)
-{
-    int i, j;
-
-    for(i=0; i<nxi; i++){
-        for(j=0; j<nxi; j++){
-            if(i!=j &&
-               (xi[j].x_org>=xi[i].x_org && xi[j].x_org<xi[i].x_org+xi[i].width) &&
-               (xi[j].y_org>=xi[i].y_org && xi[j].y_org<xi[i].y_org+xi[i].height)){
-                warn(TR("Xinerama sanity check failed; overlapping "
-                        "screens detected."));
-                return FALSE;
-            }
-        }
-        
-        if(xi[i].width<=0 || xi[i].height<=0){
-            warn(TR("Xinerama sanity check failed; zero size detected."));
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-#elif defined(CF_SUN_XINERAMA)
-static bool xinerama_sanity_check(XRectangle *monitors, int nxi)
-{
-    int i, j;
-
-    for(i=0; i<nxi; i++){
-        for(j=0; j<nxi; j++){
-            if(i!=j &&
-               (monitors[j].x>=monitors[i].x &&
-                monitors[j].x<monitors[i].x+monitors[i].width) &&
-               (monitors[j].y>=monitors[i].y &&
-                monitors[j].y<monitors[i].y+monitors[i].height)){
-                warn(TR("Xinerama sanity check failed; overlapping "
-                        "screens detected."));
-                return FALSE;
-            }
-        }
-        
-        if(monitors[i].width<=0 || monitors[i].height<=0){
-            warn(TR("Xinerama sanity check failed; zero size detected."));
-            return FALSE;
-        }
-    }
     return TRUE;
 }
-#endif
 
 
-WRootWin *ioncore_manage_rootwin(int xscr, bool noxinerama)
+WRootWin *create_rootwin(int xscr)
 {
-    WRootWin *rootwin;
-    int nxi=0, fail=0;
-#ifdef CF_XINERAMA
-    XineramaScreenInfo *xi=NULL;
-    int i;
-    int event_base, error_base;
-#elif defined(CF_SUN_XINERAMA)
-    XRectangle monitors[MAXFRAMEBUFFERS];
-    int i;
-#endif
-
-    if(!noxinerama){
-#ifdef CF_XINERAMA
-        if(XineramaQueryExtension(ioncore_g.dpy, &event_base, &error_base)){
-            xi=XineramaQueryScreens(ioncore_g.dpy, &nxi);
-
-            if(xi!=NULL && ioncore_g.rootwins!=NULL){
-                warn(TR("Don't know how to get Xinerama information for "
-                        "multiple X root windows."));
-                XFree(xi);
-                xi=NULL;
-                nxi=0;
-            }
-        }
-#elif defined(CF_SUN_XINERAMA)
-        if(XineramaGetState(ioncore_g.dpy, xscr)){
-            unsigned char hints[16];
-            int num;
-
-            if(XineramaGetInfo(ioncore_g.dpy, xscr, monitors, hints,
-                               &nxi)==0){
-                warn(TR("Error retrieving Xinerama information."));
-                nxi=0;
-            }else{
-                if(ioncore_g.rootwins!=NULL){
-                    warn(TR("Don't know how to get Xinerama information for "
-                            "multiple X root windows."));
-                    nxi=0;
-                }
-            }
-        }
-#endif
-    }
-
-    rootwin=preinit_rootwin(xscr);
-
-    if(rootwin==NULL){
-#ifdef CF_XINERAMA
-        if(xi!=NULL)
-            XFree(xi);
-#endif
-        return NULL;
-    }
-
-    net_virtual_roots=XInternAtom(ioncore_g.dpy, "_NET_VIRTUAL_ROOTS", False);
-    XDeleteProperty(ioncore_g.dpy, WROOTWIN_ROOT(rootwin), net_virtual_roots);
-
-#ifdef CF_XINERAMA
-    if(xi!=NULL && nxi!=0 && xinerama_sanity_check(xi, nxi)){
-        bool useroot=FALSE;
-        WRectangle geom;
-
-        for(i=0; i<nxi; i++){
-            geom.x=xi[i].x_org;
-            geom.y=xi[i].y_org;
-            geom.w=xi[i].width;
-            geom.h=xi[i].height;
-            /*if(nxi==1)
-                useroot=(geom.x==0 && geom.y==0);*/
-            if(!add_screen(rootwin, i, &geom, useroot)){
-                warn(TR("Unable to setup Xinerama screen %d."), i);
-                fail++;
-            }
-        }
-        XFree(xi);
-    }else
-#elif defined(CF_SUN_XINERAMA)
-    if(nxi!=0 && xinerama_sanity_check(monitors, nxi)){
-        bool useroot=FALSE;
-        WRectangle geom;
-
-        for(i=0; i<nxi; i++){
-            geom.x=monitors[i].x;
-            geom.y=monitors[i].y;
-            geom.w=monitors[i].width;
-            geom.h=monitors[i].height;
-            /*if(nxi==1)
-                useroot=(geom.x==0 && geom.y==0);*/
-            if(!add_screen(rootwin, i, &geom, useroot)){
-                warn(TR("Unable to setup Xinerama screen %d."), i);
-                fail++;
-            }
-        }
-    }else
-#endif
-    {
-        nxi=1;
-        if(!add_screen(rootwin, xscr, &REGION_GEOM(rootwin), TRUE))
-            fail++;
-    }
-    
-    if(fail==nxi){
-        warn(TR("Unable to setup X screen %d."), xscr);
-        destroy_obj((Obj*)rootwin);
-        return NULL;
-    }
-    
-    /* */ {
-        /* TODO: typed LINK_ITEM */
-        WRegion *tmp=(WRegion*)ioncore_g.rootwins;
-        LINK_ITEM(tmp, (WRegion*)rootwin, p_next, p_prev);
-        ioncore_g.rootwins=(WRootWin*)tmp;
-    }
-
-    xwindow_set_cursor(WROOTWIN_ROOT(rootwin), IONCORE_CURSOR_DEFAULT);
-    
-    return rootwin;
+    CREATEOBJ_IMPL(WRootWin, rootwin, (p, xscr));
 }
 
 
@@ -488,17 +276,15 @@ void rootwin_deinit(WRootWin *rw)
             destroy_obj((Obj*)scr);
     }
     
-    /* */ {
-        WRegion *tmp=(WRegion*)ioncore_g.rootwins;
-        UNLINK_ITEM(tmp, (WRegion*)rw, p_next, p_prev);
-        ioncore_g.rootwins=(WRootWin*)tmp;
-    }
+    UNLINK_ITEM(*(WRegion**)&ioncore_g.rootwins, (WRegion*)rw, p_next, p_prev);
     
     XSelectInput(ioncore_g.dpy, WROOTWIN_ROOT(rw), 0);
     
     XFreeGC(ioncore_g.dpy, rw->xor_gc);
     
-    window_deinit((WWindow*)rw);
+    rw->scr.mplex.win.win=None;
+
+    screen_deinit(&rw->scr);
 }
 
 
@@ -508,29 +294,6 @@ void rootwin_deinit(WRootWin *rw)
 /*{{{ region dynfun implementations */
 
 
-static void rootwin_do_set_focus(WRootWin *rootwin, bool warp)
-{
-    WRegion *sub;
-    
-    sub=REGION_ACTIVE_SUB(rootwin);
-    
-    if(sub==NULL || !REGION_IS_MAPPED(sub)){
-        WScreen *scr;
-        FOR_ALL_SCREENS(scr){
-            if(REGION_IS_MAPPED(scr)){
-                sub=(WRegion*)scr;
-                break;
-            }
-        }
-    }
-
-    if(sub!=NULL)
-        region_do_set_focus(sub, warp);
-    else
-        window_do_set_focus((WWindow*)rootwin, warp);
-}
-
-
 static bool rootwin_fitrep(WRootWin *rootwin, WWindow *par, 
                            const WFitParams *fp)
 {
@@ -551,30 +314,12 @@ static void rootwin_unmap(WRootWin *rootwin)
 }
 
 
-static void rootwin_managed_remove(WRootWin *rootwin, WRegion *reg)
-{
-    region_unset_manager(reg, (WRegion*)rootwin);
-}
-
-
-static Window rootwin_x_window(WRootWin *rootwin)
-{
-    return WROOTWIN_ROOT(rootwin);
-}
-
-
 /*}}}*/
 
 
 /*{{{ Misc */
 
 
-static bool scr_ok(WRegion *r)
-{
-    return (OBJ_IS(r, WScreen) && REGION_IS_MAPPED(r));
-}
-
-
 /*EXTL_DOC
  * Returns previously active screen on root window \var{rootwin}.
  */
@@ -582,22 +327,17 @@ EXTL_SAFE
 EXTL_EXPORT_MEMBER
 WScreen *rootwin_current_scr(WRootWin *rootwin)
 {
-    WRegion *r=REGION_ACTIVE_SUB(rootwin);
-    WScreen *scr;
-    
-    /* There should be no non-WScreen as children or managed by us, but... */
-    
-    if(r!=NULL && scr_ok(r))
-        return (WScreen*)r;
+    WScreen *scr, *fb=NULL;
     
     FOR_ALL_SCREENS(scr){
-        if(REGION_MANAGER(scr)==(WRegion*)rootwin
-           && REGION_IS_MAPPED(scr)){
-            break;
+        if(REGION_MANAGER(scr)==(WRegion*)rootwin && REGION_IS_MAPPED(scr)){
+            fb=scr;
+            if(REGION_IS_ACTIVE(scr))
+                return scr;
         }
     }
     
-    return scr;
+    return (fb ? fb : &rootwin->scr);
 }
 
 
@@ -610,16 +350,13 @@ WScreen *rootwin_current_scr(WRootWin *rootwin)
 static DynFunTab rootwin_dynfuntab[]={
     {region_map, rootwin_map},
     {region_unmap, rootwin_unmap},
-    {region_do_set_focus, rootwin_do_set_focus},
-    {(DynFun*)region_xwindow, (DynFun*)rootwin_x_window},
     {(DynFun*)region_fitrep, (DynFun*)rootwin_fitrep},
-    {region_managed_remove, rootwin_managed_remove},
     END_DYNFUNTAB
 };
 
 
 EXTL_EXPORT
-IMPLCLASS(WRootWin, WWindow, rootwin_deinit, rootwin_dynfuntab);
+IMPLCLASS(WRootWin, WScreen, rootwin_deinit, rootwin_dynfuntab);
 
     
 /*}}}*/