From ac34b4b0fe4321dc8dd744601408fe7d1224ee7b Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Mon, 3 Mar 2008 00:09:38 -0500 Subject: [PATCH] lots more structure, for windws and such. starting to get event. --- Makefile | 2 +- dcompmgr.c | 54 +++++++++++++++++--- screen.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++---------- screen.h | 27 +++++++--- window.c | 28 +++++++++++ window.h | 19 +++++++ 6 files changed, 254 insertions(+), 40 deletions(-) create mode 100644 window.c create mode 100644 window.h diff --git a/Makefile b/Makefile index 2be3a3a..f32f5d3 100644 --- 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) diff --git a/dcompmgr.c b/dcompmgr.c index 38f96e7..db14b2d 100644 --- a/dcompmgr.c +++ b/dcompmgr.c @@ -1,4 +1,5 @@ #include "screen.h" +#include "window.h" #include "gettext.h" #include @@ -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; diff --git a/screen.c b/screen.c index f268ede..684d6c5 100644 --- a/screen.c +++ b/screen.c @@ -1,59 +1,173 @@ #include "screen.h" +#include "window.h" #include "gettext.h" #include +#include #include +#include -#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; } diff --git a/screen.h b/screen.h index 5aed2af..20daed3 100644 --- a/screen.h +++ b/screen.h @@ -4,18 +4,31 @@ #include #include +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 index 0000000..3e83634 --- /dev/null +++ b/window.c @@ -0,0 +1,28 @@ +#include "window.h" +#include + +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 index 0000000..5b0d9ae --- /dev/null +++ b/window.h @@ -0,0 +1,19 @@ +#ifndef dc__window_h +#define dc__window_h + +#include + +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 -- 1.9.1