redirect rendering and get the composite overlay window
[dana/dcompmgr.git] / display.c
index ffca5e6..be05baf 100644 (file)
--- a/display.c
+++ b/display.c
 #include "display.h"
+#include "screen.h"
+#include "gettext.h"
 #include <stdlib.h>
+#include <string.h>
 #include <stdio.h>
 
+#include <xcb/damage.h>
 #include <xcb/render.h>
 #include <xcb/xfixes.h>
-#include <xcb/damage.h>
+#include <xcb/composite.h>
+
+typedef struct {
+    xcb_atom_t               *atom;
+    const char               *name;
+    xcb_intern_atom_cookie_t  ck;
+} d_atom_query_t;
+
+#define setup_extension(name) \
+    xcb_##name##_query_version_cookie_t ck_##name;
+
+#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;
+
+#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;   \
+    ext->event   = rep && rep->first_event;   \
+    ext->opcode  = rep && rep->major_opcode;  \
+\
+    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
+query_atom(d_display_t *dpy, d_atom_query_t *q)
+{
+    q->ck = xcb_intern_atom(dpy->conn, FALSE, strlen(q->name), q->name);
+}
+
+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_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,
+          .name = "_NET_WM_WINDOW_TYPE_DESKTOP" },
+        { .atom = &dpy->a.net_wm_window_type_dock,
+          .name = "_NET_WM_WINDOW_TYPE_DOCK" },
+        { .atom = &dpy->a.net_wm_window_type_normal,
+          .name = "_NET_WM_WINDOW_TYPE_NORMAL" },
+        { .atom = &dpy->a.net_wm_window_type_dialog,
+          .name = "_NET_WM_WINDOW_TYPE_DIALOG" },
+        { .atom = &dpy->a.net_wm_window_type_toolbar,
+          .name = "_NET_WM_WINDOW_TYPE_TOOLBAR" },
+        { .atom = &dpy->a.net_wm_window_type_menu,
+          .name = "_NET_WM_WINDOW_TYPE_MENU" },
+        { .atom = &dpy->a.net_wm_window_type_utility,
+          .name = "_NET_WM_WINDOW_TYPE_UTILITY" },
+        { .atom = &dpy->a.net_wm_window_type_splash,
+          .name = "_NET_WM_WINDOW_TYPE_SPLAH" },
+        { .atom = &dpy->a.net_wm_window_type_tooltip,
+          .name = "_NET_WM_WINDOW_TYPE_TOOLTIP" },
+        { .atom = &dpy->a.net_wm_window_type_combo,
+          .name = "_NET_WM_WINDOW_TYPE_COMBO" },
+        { .atom = &dpy->a.net_wm_window_type_dropdown_menu,
+          .name = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU" },
+        { .atom = &dpy->a.net_wm_window_type_popup_menu,
+          .name = "_NET_WM_WINDOW_TYPE_POPUP_MENU" },
+        { .atom = &dpy->a.net_wm_window_type_notification,
+          .name = "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
+        { .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; 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]);
+}
 
 d_display_t*
 display_open(const char *name)
@@ -13,10 +169,14 @@ 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->screens = NULL;
+        dpy->nscreens = 0;
+
+        query_statics(dpy);
     }
     return dpy;
 }
@@ -32,6 +192,7 @@ display_unref(d_display_t *dpy)
 {
     if (dpy && --dpy->ref == 0) {
         xcb_disconnect(dpy->conn);
+        free(dpy->screens);
         free(dpy);
     }
 }
@@ -59,17 +220,17 @@ display_error(d_display_t *dpy, xcb_generic_error_t *ev)
     default: break;
     }
     if (!name)
-        switch (ev->error_code - dpy->fixes_error) {
+        switch (ev->error_code - dpy->xfixes.error) {
         case XCB_XFIXES_BAD_REGION: name = "BadRegion"; break;
         default: break;
         }
     if (!name)
-        switch (ev->error_code - dpy->damage_error) {
+        switch (ev->error_code - dpy->damage.error) {
         case XCB_DAMAGE_BAD_DAMAGE: name = "BadDamage"; break;
         default: break;
         }
     if (!name)
-        switch (ev->error_code - dpy->render_error) {
+        switch (ev->error_code - dpy->render.error) {
         case XCB_RENDER_PICT_FORMAT: name = "BadPictFormat"; break;
         case XCB_RENDER_PICT_OP:     name = "BadPictOp"; break;
         case XCB_RENDER_PICTURE:     name = "BadPicture"; break;
@@ -110,3 +271,40 @@ display_error(d_display_t *dpy, xcb_generic_error_t *ev)
 
     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.super = *it.data;
+        sc.dpy = dpy;
+        sc.num = i++;
+        if (screen_register(dpy, i, &sc)) {
+            ++dpy->nscreens;
+            dpy->screens = realloc(dpy->screens,
+                                   sizeof(d_screen_t)*dpy->nscreens);
+            dpy->screens[dpy->nscreens-1] = sc;
+            printf(_("managing screen %d\n"), sc.num);
+        }
+    }
+    return dpy->nscreens;
+}
+
+d_screen_t*
+display_screen_from_root(d_display_t *dpy, xcb_window_t root)
+{
+    int i;
+    for (i = 0; i < dpy->nscreens; ++i)
+        if (dpy->screens[i].super.root == root) return &dpy->screens[i];
+    g_assert_not_reached();
+    return NULL;
+}
+