don't request hard-coded atoms from the server, it won't work
[dana/dcompmgr.git] / display.c
index c937103..65adc2a 100644 (file)
--- a/display.c
+++ b/display.c
@@ -1,5 +1,11 @@
+#include "efence.h"
+
 #include "display.h"
+#include "screen.h"
+#include "list.h"
+#include "gettext.h"
 #include <stdlib.h>
+#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 
 #include <xcb/xfixes.h>
 #include <xcb/composite.h>
 
-typedef xcb_void_cookie_t
-(*query_version_func_t)(xcb_connection_t *c,
-                        uint32_t major,
-                        uint32_t minor);
-
-typedef struct {
-    d_display_ext_t      *ext;
-    xcb_extension_t      *xcb;
-    query_version_func_t  ver;
-    int                   major;
-    int                   minor;
-    xcb_void_cookie_t     ck;
-} d_extension_query_t;
-
 typedef struct {
     xcb_atom_t               *atom;
     const char               *name;
     xcb_intern_atom_cookie_t  ck;
 } d_atom_query_t;
 
-static void
-query_extension(d_display_t *dpy, d_extension_query_t *q)
-{
-    const xcb_query_extension_reply_t *rep;
+#define setup_extension(name) \
+    xcb_##name##_query_version_cookie_t ck_##name;
 
-    xcb_prefetch_extension_data(dpy->conn, q->xcb);
-    rep = xcb_get_extension_data(dpy->conn, q->xcb);
-    q->ext->present = rep && rep->present;
-    q->ext->error   = rep && rep->first_error;
-    q->ext->event   = rep && rep->first_event;
-    q->ext->opcode  = rep && rep->major_opcode;
+#define find_extension_xfixes(dpy) &dpy->xfixes;
+#define find_extension_render(dpy) &dpy->render;
+#define find_extension_composite(dpy) &dpy->composite;
+#define find_extension_damage(dpy) &dpy->damage;
 
-    if (q->ext->present) {
-        q->ck = q->ver(dpy->conn, q->major, q->minor);
-    }
+#define version_extension_xfixes \
+  XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MAJOR_VERSION
+#define version_extension_render \
+  XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MAJOR_VERSION
+#define version_extension_composite \
+  XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MAJOR_VERSION
+#define version_extension_damage \
+  XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MAJOR_VERSION
+
+#define query_extension(dpy, name) \
+{ \
+    const xcb_query_extension_reply_t *rep;          \
+    d_display_ext_t *ext; \
+\
+    xcb_prefetch_extension_data(dpy->conn, &xcb_##name##_id);  \
+    rep = xcb_get_extension_data(dpy->conn, &xcb_##name##_id); \
+\
+    ext = find_extension_##name(dpy) \
+    ext->present = rep && rep->present;          \
+    ext->error   = rep ? rep->first_error : 0;   \
+    ext->event   = rep ? rep->first_event : 0;   \
+    ext->opcode  = rep ? rep->major_opcode : 0;  \
+\
+    if (ext->present) \
+        ck_##name = xcb_##name##_query_version(dpy->conn, \
+                                               version_extension_##name); \
+}
+
+#define reply_extension(dpy, name) \
+{ \
+    xcb_##name##_query_version_reply_t *rep; \
+    d_display_ext_t *ext; \
+\
+    ext = find_extension_##name(dpy) \
+    if (ext->present) { \
+        rep = xcb_##name##_query_version_reply(dpy->conn, ck_##name, NULL); \
+        if (rep) { \
+            ext->major_version = rep->major_version; \
+            ext->minor_version = rep->minor_version; \
+            free(rep); \
+        } \
+        else { \
+            printf("error querying the %s extension's version\n", "##name##");\
+            ext->present = FALSE; \
+        } \
+    } \
 }
 
 static void
@@ -52,50 +83,26 @@ query_atom(d_display_t *dpy, d_atom_query_t *q)
 }
 
 static void
+reply_atom(d_display_t *dpy, d_atom_query_t *q)
+{
+    xcb_intern_atom_reply_t *rep;
+    rep = xcb_intern_atom_reply(dpy->conn, q->ck, NULL);
+    if (rep) {
+        *q->atom = rep->atom;
+        free(rep);
+    }
+    else {
+        printf("unable to query atom %s\n", q->name);
+        *q->atom = 0;
+    }
+}
+
+static void
 query_statics(d_display_t *dpy)
 {
-    d_extension_query_t extensions[] = {
-        {
-            .ext = &dpy->xfixes,
-            .xcb = &xcb_xfixes_id,
-            .ver = (query_version_func_t)xcb_xfixes_query_version,
-            .major = XCB_XFIXES_MAJOR_VERSION,
-            .minor = XCB_XFIXES_MINOR_VERSION
-        },
-        {
-            .ext = &dpy->render,
-            .xcb = &xcb_render_id,
-            .ver = (query_version_func_t)xcb_render_query_version,
-            .major = XCB_RENDER_MAJOR_VERSION,
-            .minor = XCB_RENDER_MINOR_VERSION
-        },
-        {
-            .ext = &dpy->damage,
-            .xcb = &xcb_damage_id,
-            .ver = (query_version_func_t)xcb_damage_query_version,
-            .major = XCB_DAMAGE_MAJOR_VERSION,
-            .minor = XCB_DAMAGE_MINOR_VERSION
-        },
-        {
-            .ext = &dpy->composite,
-            .xcb = &xcb_composite_id,
-            .ver = (query_version_func_t)xcb_composite_query_version,
-            .major = XCB_COMPOSITE_MAJOR_VERSION,
-            .minor = XCB_COMPOSITE_MINOR_VERSION
-        },
-        { .ext = NULL }
-    };
     d_atom_query_t atoms[] = {
-        { .atom = &dpy->a.atom,
-          .name = "ATOM" },
-        { .atom = &dpy->a.cardinal,
-          .name = "CARDINAL" },
         { .atom = &dpy->a.utf8_string,
           .name = "UTF8_STRING" },
-        { .atom = &dpy->a.string,
-          .name = "STRING" },
-        { .atom = &dpy->a.pixmap,
-          .name = "PIXMAP" },
         { .atom = &dpy->a.net_wm_window_type,
           .name = "_NET_WM_WINDOW_TYPE" },
         { .atom = &dpy->a.net_wm_window_type_desktop,
@@ -127,12 +134,34 @@ query_statics(d_display_t *dpy)
         { .atom = NULL }
     };
     int i;
+    setup_extension(xfixes);
+    setup_extension(render);
+    setup_extension(composite);
+    setup_extension(damage);
+
+    query_extension(dpy, xfixes);
+    query_extension(dpy, render);
+    query_extension(dpy, composite);
+    query_extension(dpy, damage);
 
-    for (i = 0; extensions[i].ext != NULL; ++i)
-        query_extension(dpy, &extensions[i]);
     for (i = 0; atoms[i].atom != NULL; ++i)
         query_atom(dpy, &atoms[i]);
 
+    xcb_flush(dpy->conn);
+
+    reply_extension(dpy, xfixes);
+    reply_extension(dpy, render);
+    reply_extension(dpy, composite);
+    reply_extension(dpy, damage);
+
+    for (i = 0; atoms[i].atom != NULL; ++i)
+        reply_atom(dpy, &atoms[i]);
+
+    /* hard-coded ones, you can't request  these */
+    dpy->a.atom = 4;
+    dpy->a.cardinal = 6;
+    dpy->a.pixmap = 20;
+    dpy->a.string = 31;
 }
 
 d_display_t*
@@ -142,10 +171,12 @@ display_open(const char *name)
     xcb_connection_t *conn;
 
     conn = xcb_connect(name, NULL);
-    if (conn) {
+    if (conn && !xcb_connection_has_error(conn)) {
         dpy = malloc(sizeof(d_display_t));
         dpy->conn = conn;
         dpy->ref = 1;
+        dpy->fd = xcb_get_file_descriptor(conn);
+        dpy->screens = list_new();
 
         query_statics(dpy);
     }
@@ -162,6 +193,12 @@ void
 display_unref(d_display_t *dpy)
 {
     if (dpy && --dpy->ref == 0) {
+        d_list_it_t *it;
+
+        for (it = list_top(dpy->screens); it; it = it->next)
+            screen_unref(it->data);
+        list_unref(dpy->screens);
+
         xcb_disconnect(dpy->conn);
         free(dpy);
     }
@@ -209,6 +246,7 @@ display_error(d_display_t *dpy, xcb_generic_error_t *ev)
         default: break;
         }
 
+    req = NULL;
     if (major_opcode <= 127)
         switch (major_opcode) {
         case 1:  req = "CreateWindow";           break;
@@ -228,6 +266,65 @@ display_error(d_display_t *dpy, xcb_generic_error_t *ev)
         case 72: req = "PutImage";               break;
         default: break; 
         }
+    else if (major_opcode == dpy->damage.opcode)
+        switch (minor_opcode)
+        {
+        case 0: req = "DamageQueryVersion"; break;
+        case 1: req = "DamageCreate";       break;
+        case 2: req = "DamageDestroy";      break;
+        case 3: req = "DamageSubtract";     break;
+        default: break;
+        }
+    else if (major_opcode == dpy->render.opcode)
+        switch (minor_opcode)
+        {
+        case 0:  req = "RenderQueryVersion";             break;
+        case 1:  req = "RenderQueryPictFormats";         break;
+        case 2:  req = "RenderQueryPictIndexValues";     break;
+        case 4:  req = "RenderCreatePicture";            break;
+        case 5:  req = "RenderChangePicture";            break;
+        case 6:  req = "RenderSetPictureClipRectangles"; break;
+        case 7:  req = "RenderFreePicture";              break;
+        case 8:  req = "RenderComposite";                break;
+        case 10: req = "RenderCompositeTrapezoids";      break;
+        case 11: req = "RenderCompositeTriangles";       break;
+        case 12: req = "RenderCompositeTriStrip";        break;
+        case 13: req = "RenderCompositeTriFan";          break;
+        case 17: req = "RenderCreateGlyphSet";           break;
+        case 18: req = "RenderReferenceGlyphSet";        break;
+        case 19: req = "RenderFreeGlyphSet";             break;
+        case 20: req = "RenderAddGlyphs";                break;
+        case 22: req = "RenderFreeGlyphs";               break;
+        case 23: req = "RenderCompositeGlyphs8";         break;
+        case 24: req = "RenderCompositeGlyphs16";        break;
+        case 25: req = "RenderCompositeGlyphs32";        break;
+        case 26: req = "RenderFillRectangles";           break;
+        case 27: req = "RenderCreateCursor";             break;
+        case 28: req = "RenderSetPictureTransform";      break;
+        case 29: req = "RenderQueryFilters";             break;
+        case 30: req = "RenderSetPictureFilter";         break;
+        case 31: req = "RenderCreateAnimCursor";         break;
+        case 32: req = "RenderAddTraps";                 break;
+        case 33: req = "RenderCreateSolidFill";          break;
+        case 34: req = "RenderLinearGradient";           break;
+        case 35: req = "RenderRadialGradient";           break;
+        case 36: req = "RenderConicalGradient";          break;
+        default: break;
+        }
+    else if (major_opcode == dpy->composite.opcode)
+        switch (minor_opcode)
+        {
+        case 0: req = "CompositeQueryVersion";               break;
+        case 1: req = "CompositeRedirectWindow";             break;
+        case 2: req = "CompositeRedirectSubwindows";         break;
+        case 3: req = "CompositeUnredirectWindow";           break;
+        case 4: req = "CompositeUnredirectSubwindows";       break;
+        case 5: req = "CompositeCreateRegionFromBorderClip"; break;
+        case 6: req = "CompositeNameWindowPixmap";           break;
+        case 7: req = "CompositeGetOverlayWindow";           break;
+        case 8: req = "CompositeReleaseOverlayWindow";       break;
+        default: break;
+        }
 
     if (name && req)
         printf("XError: %s %s!\n",
@@ -239,5 +336,42 @@ display_error(d_display_t *dpy, xcb_generic_error_t *ev)
         printf("XError: code %d major opcode %d minor opcode %d!\n",
                ev->error_code, major_opcode, minor_opcode);
 
-    abort();
+    //abort();
+}
+
+int
+display_claim_screens(d_display_t *dpy)
+{
+    static const xcb_setup_t *setup;
+    xcb_screen_iterator_t it;
+    int i;
+    d_screen_t *sc;
+
+    setup = xcb_get_setup(dpy->conn);
+
+    i = 0;
+    for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
+        sc = screen_new(dpy, i++, it.data);
+        if (screen_register(sc)) {
+            list_append(dpy->screens, sc);
+            printf(_("managing screen %d\n"), sc->num);
+        }
+        else
+            screen_unref(sc);
+    }
+    return list_length(dpy->screens);
+}
+
+d_screen_t*
+display_screen_from_root(d_display_t *dpy, xcb_window_t root)
+{
+    d_list_it_t *it;
+
+    for (it = list_top(dpy->screens); it; it = it->next) {
+        d_screen_t *sc = it->data;
+        if (sc->super.root == root)
+            return sc;
+    }
+    assert(0);
+    return NULL;
 }