]> Pileus Git - wmpus/commitdiff
Add XCB window mapping
authorAndy Spencer <andy753421@gmail.com>
Wed, 8 Apr 2015 20:43:52 +0000 (20:43 +0000)
committerAndy Spencer <andy753421@gmail.com>
Wed, 15 Apr 2015 19:54:07 +0000 (19:54 +0000)
sys-xcb.c

index 87dcb01da592a66e0ad3d1a78e3b807782cb5ae0..a9e780d0e1f621f1f65016f86eb2a652f3b349ab 100644 (file)
--- a/sys-xcb.c
+++ b/sys-xcb.c
@@ -16,6 +16,7 @@
 #define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
+#include <search.h>
 
 #include <xcb/xcb.h>
 
@@ -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;
 }