lots more structure, for windws and such. starting to get event.
authorDana Jansens <danakj@orodu.net>
Mon, 3 Mar 2008 05:09:38 +0000 (00:09 -0500)
committerDana Jansens <danakj@orodu.net>
Mon, 3 Mar 2008 05:10:15 +0000 (00:10 -0500)
Makefile
dcompmgr.c
screen.c
screen.h
window.c [new file with mode: 0644]
window.h [new file with mode: 0644]

index 2be3a3a..f32f5d3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ sources = $(wildcard *.c)
 objs = $(sources:.c=.o)
 headers = $(wildcard *.h)
 
-CFLAGS=$(shell pkg-config --cflags xcb-composite glib-2.0) -ggdb
+CFLAGS=$(shell pkg-config --cflags xcb-composite glib-2.0) -ggdb -W -Wall
 LIBS=$(shell pkg-config --libs xcb-composite glib-2.0)
 
 dcompmgr: $(objs)
index 38f96e7..db14b2d 100644 (file)
@@ -1,4 +1,5 @@
 #include "screen.h"
+#include "window.h"
 #include "gettext.h"
 
 #include <glib.h>
@@ -19,24 +20,35 @@ all_screens(xcb_connection_t *conn, d_screen_t **list)
     count = i = 0;
     for (it = xcb_setup_roots_iterator(setup); it.rem; xcb_screen_next(&it)) {
         sc.super = *it.data;
+        sc.conn = conn;
         sc.num = i++;
-        if (screen_register(conn, &sc)) {
+        if (screen_register(&sc)) {
             ++count;
             *list = g_renew(d_screen_t, *list, count);
             (*list)[count-1] = sc;
             printf(_("managing screen %d\n"), sc.num);
-
-            screen_listen(conn, &sc);
         }
     }
     return count;
 }
 
+d_screen_t*
+screen_from_root(d_screen_t *list, int n, xcb_window_t root)
+{
+    int i;
+    for (i = 0; i < n; ++i)
+        if (list->super.root == root) return &list[i];
+    g_assert_not_reached();
+    return NULL;
+}
+
 int
 main(int argc, char **argv)
 {
-    xcb_connection_t  *conn;
-    d_screen_t        *screens = NULL;
+    xcb_connection_t    *conn;
+    d_screen_t          *screens = NULL;
+    int                  nscreens;
+    xcb_generic_event_t *ev;
 
     conn = xcb_connect(NULL, NULL);
     if (!conn) {
@@ -44,8 +56,36 @@ main(int argc, char **argv)
         return 1;
     }
 
-    all_screens(conn, &screens);
-    
+    nscreens = all_screens(conn, &screens);
+    if (nscreens < 1) {
+        printf(_("found no screens to run on\n"));
+        xcb_disconnect(conn);
+        return 0;
+    }
+
+    while (ev = xcb_wait_for_event(conn)) {
+        printf("event\n");
+        switch (ev->response_type & ~0x80) {
+        case XCB_CREATE_WINDOW:
+        {
+            xcb_create_notify_event_t *cev = (xcb_create_notify_event_t*)ev;
+            d_screen_t *sc = screen_from_root(screens, nscreens, cev->parent);
+            screen_add_window(sc, cev);
+        }
+        case XCB_DESTROY_WINDOW:
+        {
+            xcb_destroy_notify_event_t *dev = (xcb_destroy_notify_event_t*)ev;
+            d_screen_t *sc = screen_from_root(screens, nscreens, dev->event);
+            d_window_t *w = screen_find_window(sc, dev->window);
+            screen_hide_window(sc, w);
+            screen_remove_window(sc, w);
+        }
+        case XCB_REPARENT_WINDOW:
+        default:
+            break;
+        }
+        free(ev);
+    }
 
     xcb_disconnect(conn);
     return 0;
index f268ede..684d6c5 100644 (file)
--- a/screen.c
+++ b/screen.c
 #include "screen.h"
+#include "window.h"
 #include "gettext.h"
 #include <string.h>
+#include <stdlib.h>
 #include <stdio.h>
+#include <xcb/composite.h>
 
-#define ROOT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY)
+#define ROOT_MASK      (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | \
+                        XCB_EVENT_MASK_STRUCTURE_NOTIFY)
+
+#define SELECTION_MASK (XCB_EVENT_MASK_STRUCTURE_NOTIFY | \
+                        XCB_EVENT_MASK_PROPERTY_CHANGE)
+
+static void screen_init(d_screen_t *sc);
+static xcb_timestamp_t screen_timestamp(d_screen_t *sc);
 
 gboolean
-screen_register(xcb_connection_t *conn, d_screen_t *sc)
+screen_register(d_screen_t *sc)
 {
     char *name;
-    int len, s;
     xcb_window_t w;
     xcb_intern_atom_cookie_t ack;
     xcb_intern_atom_reply_t *arep;
     xcb_get_selection_owner_cookie_t sck;
     xcb_get_selection_owner_reply_t *srep;
-    gboolean taken;
+    uint32_t event_mask;
+    gboolean taken, ret;
 
-    w = xcb_generate_id(conn);
-    xcb_create_window(conn, XCB_COPY_FROM_PARENT, w, sc->super.root,
+    w = xcb_generate_id(sc->conn);
+    event_mask = SELECTION_MASK;
+    xcb_create_window(sc->conn, XCB_COPY_FROM_PARENT, w, sc->super.root,
                       0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
-                      sc->super.root_visual, 0, NULL);
+                      sc->super.root_visual, XCB_CW_EVENT_MASK, &event_mask);
 
     name = g_strdup_printf("_NET_WM_CM_S%d", sc->num);
-    ack = xcb_intern_atom(conn, FALSE, strlen(name), name);
-    arep = xcb_intern_atom_reply(conn, ack, NULL);
+    ack = xcb_intern_atom(sc->conn, FALSE, strlen(name), name);
+    arep = xcb_intern_atom_reply(sc->conn, ack, NULL);
     g_free(name);
 
-    sck = xcb_get_selection_owner(conn, arep->atom);
-    srep = xcb_get_selection_owner_reply(conn, sck, NULL);
+    sck = xcb_get_selection_owner(sc->conn, arep->atom);
+    srep = xcb_get_selection_owner_reply(sc->conn, sck, NULL);
     taken = !!srep->owner;
     free(srep);
     if (taken) {
         printf(_("screen %d already has a composite manager, skipping\n"),
                sc->num);
-        return FALSE;
+        ret = FALSE;
     }
+    else {
+        xcb_timestamp_t time;
 
-    xcb_set_selection_owner(conn, w, arep->atom, XCB_CURRENT_TIME);
-    sck = xcb_get_selection_owner(conn, arep->atom);
-    srep = xcb_get_selection_owner_reply(conn, sck, NULL);
-    taken = srep->owner == w;
-    if (taken) {
         sc->selwin = w;
-        return TRUE;
-    }
-    else {
-        xcb_destroy_window(conn, w);
-        return FALSE;
+        sc->selatom = arep->atom;
+
+        time = screen_timestamp(sc);
+
+        xcb_grab_server(sc->conn);
+        xcb_set_selection_owner(sc->conn, w, arep->atom, time);
+        sck = xcb_get_selection_owner(sc->conn, arep->atom);
+        srep = xcb_get_selection_owner_reply(sc->conn, sck, NULL);
+        taken = srep->owner == w;
+        if (taken) {
+            screen_init(sc);
+            ret = TRUE;
+        }
+        else {
+            xcb_destroy_window(sc->conn, w);
+            ret = FALSE;
+        }
+        xcb_ungrab_server(sc->conn);
+        xcb_flush(sc->conn);
     }
+    return ret;
 }
 
-void screen_listen(xcb_connection_t *conn, d_screen_t *sc)
+static guint
+window_hash(xcb_window_t *w) { return *w; }
+
+static gboolean
+window_compare(xcb_window_t *w1, xcb_window_t *w2) { return *w1 == *w2; }
+
+static void
+screen_init(d_screen_t *sc)
 {
-    const uint32_t mask = ROOT_MASK;
-    xcb_change_window_attributes(conn, sc->super.root,
+    uint32_t mask;
+
+    sc->winhash = g_hash_table_new((GHashFunc)window_hash,
+                                   (GCompareFunc)window_compare);
+
+//    xcb_composite_redirect_subwindows(sc->conn, sc->super.root,
+//                                      XCB_COMPOSITE_REDIRECT_MANUAL);
+
+    mask = SELECTION_MASK;
+    xcb_change_window_attributes(sc->conn, sc->selwin,
                                  XCB_CW_EVENT_MASK, &mask);
+    mask = ROOT_MASK;
+    xcb_change_window_attributes(sc->conn, sc->super.root,
+                                 XCB_CW_EVENT_MASK, &mask);
+}
+
+void
+screen_add_window(d_screen_t *sc, xcb_create_notify_event_t *cev)
+{
+    d_window_t *w;
+
+    w = window_new(cev->window, sc);
+    g_hash_table_insert(sc->winhash, &w->id, w);
+
+    printf("added window 0x%x\n", w->id);
+}
+
+void
+screen_remove_window(d_screen_t *sc, struct d_window *w)
+{
+    printf("removed window 0x%x\n", w->id);
+
+    g_hash_table_remove(sc->winhash, &w->id);
+    window_unref(w);
+}
+
+d_window_t*
+screen_find_window(d_screen_t *sc, xcb_window_t id)
+{
+    return g_hash_table_lookup(sc->winhash, &id);
+}
+
+void
+screen_show_window(d_screen_t *sc, struct d_window *w)
+{
+}
+
+void
+screen_hide_window(d_screen_t *sc, struct d_window *w)
+{
+}
+
+static xcb_timestamp_t
+screen_timestamp(d_screen_t *sc)
+{
+    xcb_void_cookie_t ck;
+    xcb_timestamp_t   time;
+
+    ck = xcb_change_property(sc->conn, XCB_PROP_MODE_REPLACE, sc->selwin,
+                             sc->selatom, sc->selatom, 32, 0, NULL);
+    xcb_flush(sc->conn);
+    while (1) {
+        xcb_generic_event_t *ev;
+
+        ev = xcb_wait_for_event(sc->conn);
+        if (!ev) {
+            printf(_("IO error\n"));
+            exit(0);
+        }
+
+        /* expect errors.. */
+        if (!ev->response_type) {
+            /* XXX handle error */
+            free(ev);
+            continue;
+        }
+
+        if (ev->response_type == XCB_PROPERTY_NOTIFY &&
+            ev->full_sequence == ck.sequence)
+        {
+            time = ((xcb_property_notify_event_t*)ev)->time;
+            free(ev);
+            break;
+        }
+    }
+    printf("created timestamp %lu\n", (unsigned long) time);
+    return time;
 }
index 5aed2af..20daed3 100644 (file)
--- a/screen.h
+++ b/screen.h
@@ -4,18 +4,31 @@
 #include <xcb/xcb.h>
 #include <glib.h>
 
+struct d_window;
+
 /* inherits from xcb_screen_t */
-typedef struct {
-    xcb_screen_t super;
-    int          num;
-    xcb_window_t selwin; /* for the selection */
+typedef struct d_screen {
+    xcb_screen_t      super;
+    xcb_connection_t *conn;
+    int               num;
+
+    xcb_window_t      selwin;  /* for the selection */
+    xcb_atom_t        selatom; /* ditto.. */
+
+    GHashTable       *winhash;
 } d_screen_t;
 
 /*! Tries to register on the screen given by @sc.  If it succeeds, it fills
-  out the selwin in @sc and returns TRUE, otherwise it returns FALSE.
+    in @sc and returns TRUE, otherwise it returns FALSE.
 */
-gboolean screen_register(xcb_connection_t *conn, d_screen_t *sc);
+gboolean screen_register(d_screen_t *sc);
+
+void screen_add_window(d_screen_t *sc, xcb_create_notify_event_t *cev);
+void screen_remove_window(d_screen_t *sc, struct d_window *w);
+
+struct d_window* screen_find_window(d_screen_t *sc, xcb_window_t id);
 
-void screen_listen(xcb_connection_t *conn, d_screen_t *sc);
+void screen_show_window(d_screen_t *sc, struct d_window *w);
+void screen_hide_window(d_screen_t *sc, struct d_window *w);
 
 #endif
diff --git a/window.c b/window.c
new file mode 100644 (file)
index 0000000..3e83634
--- /dev/null
+++ b/window.c
@@ -0,0 +1,28 @@
+#include "window.h"
+#include <glib.h>
+
+d_window_t*
+window_new(xcb_window_t id, struct d_screen *sc)
+{
+    d_window_t *w;
+
+    w = g_new(d_window_t, 1);
+    w->id = id;
+    w->ref = 1;
+    w->sc = sc;
+    return w;
+}
+
+void
+window_ref(d_window_t *w)
+{
+    ++w->ref;
+}
+
+void
+window_unref(d_window_t *w)
+{
+    if (w && --w->ref == 0) {
+        g_free(w);
+    }
+}
diff --git a/window.h b/window.h
new file mode 100644 (file)
index 0000000..5b0d9ae
--- /dev/null
+++ b/window.h
@@ -0,0 +1,19 @@
+#ifndef dc__window_h
+#define dc__window_h
+
+#include <xcb/xcb.h>
+
+struct d_screen;
+
+typedef struct d_window {
+    xcb_window_t     id;
+    int              ref;
+    struct d_screen *sc;
+} d_window_t;
+
+d_window_t* window_new(xcb_window_t id, struct d_screen *sc);
+
+void window_ref(d_window_t *w);
+void window_unref(d_window_t *w);
+
+#endif