From 1b55a72ed37fcf2e73e21ff5a22ba86d0ac1525a Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Wed, 8 Apr 2015 20:43:52 +0000 Subject: [PATCH] Add XCB window mapping --- sys-xcb.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/sys-xcb.c b/sys-xcb.c index 87dcb01..a9e780d 100644 --- a/sys-xcb.c +++ b/sys-xcb.c @@ -16,6 +16,7 @@ #define _GNU_SOURCE #include #include +#include #include @@ -32,19 +33,194 @@ static int no_capture = 0; /* Internal structures */ struct win_sys { + xcb_window_t xcb; + int override; // normal vs override redirect + int managed; // window is currently managed by wm }; /* Global data */ static xcb_connection_t *conn; +static xcb_window_t root; static list_t *screens; +static void *cache; + +/***************** + * Constant data * + *****************/ + +const char *event_names[] = { + [XCB_KEY_PRESS ] "key_press", [XCB_KEY_RELEASE ] "key_release", + [XCB_BUTTON_PRESS ] "button_press", [XCB_BUTTON_RELEASE ] "button_release", + [XCB_MOTION_NOTIFY ] "motion_notify", [XCB_ENTER_NOTIFY ] "enter_notify", + [XCB_LEAVE_NOTIFY ] "leave_notify", [XCB_FOCUS_IN ] "focus_in", + [XCB_FOCUS_OUT ] "focus_out", [XCB_KEYMAP_NOTIFY ] "keymap_notify", + [XCB_EXPOSE ] "expose", [XCB_GRAPHICS_EXPOSURE] "graphics_exposure", + [XCB_NO_EXPOSURE ] "no_exposure", [XCB_VISIBILITY_NOTIFY] "visibility_notify", + [XCB_CREATE_NOTIFY ] "create_notify", [XCB_DESTROY_NOTIFY ] "destroy_notify", + [XCB_UNMAP_NOTIFY ] "unmap_notify", [XCB_MAP_NOTIFY ] "map_notify", + [XCB_MAP_REQUEST ] "map_request", [XCB_REPARENT_NOTIFY ] "reparent_notify", + [XCB_CONFIGURE_NOTIFY ] "configure_notify", [XCB_CONFIGURE_REQUEST] "configure_request", + [XCB_GRAVITY_NOTIFY ] "gravity_notify", [XCB_RESIZE_REQUEST ] "resize_request", + [XCB_CIRCULATE_NOTIFY ] "circulate_notify", [XCB_CIRCULATE_REQUEST] "circulate_request", + [XCB_PROPERTY_NOTIFY ] "property_notify", [XCB_SELECTION_CLEAR ] "selection_clear", + [XCB_SELECTION_REQUEST] "selection_request", [XCB_SELECTION_NOTIFY ] "selection_notify", + [XCB_COLORMAP_NOTIFY ] "colormap_notify", [XCB_CLIENT_MESSAGE ] "client_message", + [XCB_MAPPING_NOTIFY ] "mapping_notify", [XCB_GE_GENERIC ] "ge_generic", +}; + +/******************** + * Window functions * + ********************/ + +static int win_cmp(const void *_a, const void *_b) +{ + const win_t *a = _a; + const win_t *b = _b; + if (a->sys->xcb < b->sys->xcb) return -1; + if (a->sys->xcb > b->sys->xcb) return 1; + return 0; +} + +static win_t *win_get(xcb_window_t xcb) +{ + win_sys_t sys = { .xcb = xcb }; + win_t key = { .sys = &sys }; + + win_t **win = tfind(&key, &cache, win_cmp); + + if (!win) { + printf("Warning: no window for %u\n", xcb); + return NULL; + } + + return *win; +} + +/********************** + * X11 Event Handlers * + **********************/ + +/* Specific events */ +static void on_create_notify(xcb_create_notify_event_t *event) +{ + win_t *win = new0(win_t); + win_sys_t *sys = new0(win_sys_t); + + printf("on_create_notify: xcb=%u -> win=%p\n", + event->window, win); + + win->x = event->x; + win->y = event->y; + win->w = event->width; + win->h = event->height; + win->sys = sys; + + sys->xcb = event->window; + sys->override = event->override_redirect; + + tsearch(win, &cache, win_cmp); +} + +static void on_destroy_notify(win_t *win, xcb_destroy_notify_event_t *event) +{ + printf("on_destroy_notify: xcb=%u -> win=%p\n", + event->window, win); + + tdelete(win, &cache, win_cmp); + + free(win->sys); + free(win); +} + +static void on_map_request(win_t *win, xcb_map_request_event_t *event) +{ + printf("on_map_request: xcb=%u -> win=%p\n", + event->window, win); + + if (!win->sys->managed) { + wm_insert(win); + win->sys->managed = 1; + } + + xcb_map_window(conn, win->sys->xcb); + sys_move(win, win->x, win->y, win->w, win->h); +} + +static void on_configure_request(win_t *win, xcb_configure_request_event_t *event) +{ + printf("on_configure_request: xcb=%u -> win=%p -- %dx%d @ %d,%d\n", + event->window, win, + event->width, event->height, + event->x, event->y); + + win->x = event->x; + win->y = event->y; + win->w = event->width; + win->h = event->height; + + xcb_configure_notify_event_t resp = { + .response_type = XCB_CONFIGURE_NOTIFY, + .event = win->sys->xcb, + .window = win->sys->xcb, + .x = win->x, + .y = win->y, + .width = win->w, + .height = win->h, + .border_width = border, + }; + + xcb_send_event(conn, 0, win->sys->xcb, + XCB_EVENT_MASK_STRUCTURE_NOTIFY, + (const char *)&resp); +} + +/* Generic Event */ +static void on_event(xcb_generic_event_t *event) +{ + win_t *win = NULL; + switch (event->response_type) { + case XCB_CREATE_NOTIFY: + on_create_notify((xcb_create_notify_event_t *)event); + break; + case XCB_DESTROY_NOTIFY: + if ((win = win_get(((xcb_destroy_notify_event_t *)event)->window))) + on_destroy_notify(win, (xcb_destroy_notify_event_t *)event); + break; + case XCB_MAP_REQUEST: + if ((win = win_get(((xcb_map_request_event_t *)event)->window))) + on_map_request(win, (xcb_map_request_event_t *)event); + break; + case XCB_CONFIGURE_REQUEST: + if ((win = win_get(((xcb_configure_request_event_t *)event)->window))) + on_configure_request(win, (xcb_configure_request_event_t *)event); + break; + default: + printf("on_%s\n", event_names[event->response_type] ?: "unknown_event"); + break; + } +} /******************** * System functions * ********************/ + void sys_move(win_t *win, int x, int y, int w, int h) { printf("sys_move: %p - %dx%d @ %d,%d\n", win, w, h, x, y); + + win->x = x; + win->y = y; + win->w = w; + win->h = h; + + uint16_t mask = XCB_CONFIG_WINDOW_X + | XCB_CONFIG_WINDOW_Y + | XCB_CONFIG_WINDOW_WIDTH + | XCB_CONFIG_WINDOW_HEIGHT; + uint32_t list[] = {x, y, w, h}; + + xcb_configure_window(conn, win->sys->xcb, mask, list); } void sys_raise(win_t *win) @@ -75,10 +251,16 @@ void sys_unwatch(win_t *win, event_t ev, mod_t mod) list_t *sys_info(void) { printf("sys_info\n"); + if (screens == NULL) { win_t *screen = new0(win_t); + screen->x = 0; + screen->y = 0; + screen->w = 800; + screen->h = 600; screens = list_insert(NULL, screen); } + return screens; } @@ -96,19 +278,52 @@ void sys_init(void) error("xcb connect failed"); if (xcb_connection_has_error(conn)) error("xcb connection has errors"); + + /* Get root window */ + const xcb_setup_t *setup = xcb_get_setup(conn); + xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); + root = iter.data->root; + + /* Request substructure redirect */ + xcb_event_mask_t mask; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; + mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; + cookie = xcb_change_window_attributes_checked(conn, root, + XCB_CW_EVENT_MASK, &mask); + if ((err = xcb_request_check(conn, cookie))) + error("Another window manager is already running"); } void sys_run(void) { printf("sys_run\n"); + while (1) + { + int status; + xcb_generic_event_t *event; + if (!(event = xcb_wait_for_event(conn))) + break; + on_event(event); + free(event); + if (!(status = xcb_flush(conn))) + break; + } } void sys_exit(void) { printf("sys_exit\n"); + if (conn) + xcb_disconnect(conn); + conn = NULL; } void sys_free(void) { printf("sys_free\n"); + if (conn) + xcb_disconnect(conn); + conn = NULL; } -- 2.43.2