+static int do_get_input_focus(void)
+{
+ xcb_get_input_focus_cookie_t cookie =
+ xcb_get_input_focus(conn);
+ if (!cookie.sequence)
+ return warn("do_get_input_focus: bad cookie");
+
+ xcb_get_input_focus_reply_t *reply =
+ xcb_get_input_focus_reply(conn, cookie, NULL);
+ if (!reply)
+ return warn("do_get_input_focus: no reply");
+
+ return reply->focus;
+}
+
+static int do_ewmh_init_atoms(void)
+{
+ xcb_intern_atom_cookie_t *cookies =
+ xcb_ewmh_init_atoms(conn, &ewmh);
+ if (!cookies)
+ return warn("do_ewmh_init_atoms: no cookies");
+
+ int status =
+ xcb_ewmh_init_atoms_replies(&ewmh, cookies, NULL);
+ if (!status)
+ return warn("do_ewmh_init_atoms: no status");
+ return status;
+}
+
+static int do_get_strut(xcb_window_t win, strut_t *strut)
+{
+ xcb_get_property_cookie_t cookie =
+ xcb_ewmh_get_wm_strut(&ewmh, win);
+ if (!cookie.sequence)
+ return warn("do_get_strut: bad cookie");
+
+ xcb_ewmh_get_extents_reply_t ext = {};
+ int status =
+ xcb_ewmh_get_wm_strut_reply(&ewmh, cookie, &ext, NULL);
+ if (!status)
+ return warn("do_get_strut: no status");
+
+ strut->left = ext.left;
+ strut->right = ext.right;
+ strut->top = ext.top;
+ strut->bottom = ext.bottom;
+
+ return ext.left || ext.right || ext.top || ext.bottom;
+}
+
+static xcb_pixmap_t do_alloc_color(uint32_t rgb)
+{
+ uint16_t r = (rgb & 0xFF0000) >> 8;
+ uint16_t g = (rgb & 0x00FF00);
+ uint16_t b = (rgb & 0x0000FF) << 8;
+ xcb_alloc_color_cookie_t cookie =
+ xcb_alloc_color(conn, colormap, r, g, b);
+ if (!cookie.sequence)
+ return warn("do_alloc_color: bad cookie");
+
+ xcb_alloc_color_reply_t *reply =
+ xcb_alloc_color_reply(conn, cookie, NULL);
+ if (!reply)
+ return warn("do_alloc_color: no reply");
+
+ printf("do_alloc_color: %06x -> %06x\n", rgb, reply->pixel);
+ return reply->pixel;
+}
+
+static void do_grab_pointer(xcb_event_mask_t mask)
+{
+ if (!grabbed)
+ xcb_grab_pointer(conn, 0, root, mask,
+ XCB_GRAB_MODE_ASYNC,
+ XCB_GRAB_MODE_ASYNC,
+ 0, 0, XCB_CURRENT_TIME);
+ grabbed++;
+}
+
+static void do_ungrab_pointer(void)
+{
+ grabbed--;
+ if (!grabbed)
+ xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
+}
+
+static void do_configure_window(xcb_window_t win,
+ int x, int y, int w, int h,
+ int b, int s, int r)
+{
+ int table[][2] = {
+ { x, XCB_CONFIG_WINDOW_X },
+ { y, XCB_CONFIG_WINDOW_Y },
+ { w, XCB_CONFIG_WINDOW_WIDTH },
+ { h, XCB_CONFIG_WINDOW_HEIGHT },
+ { b, XCB_CONFIG_WINDOW_BORDER_WIDTH },
+ { s, XCB_CONFIG_WINDOW_SIBLING },
+ { r, XCB_CONFIG_WINDOW_STACK_MODE },
+ };
+
+ uint16_t mask = 0;
+ uint32_t list[7] = {};
+ for (int i = 0; i < 7; i++) {
+ if (table[i][0] >= 0) {
+ list[i] = table[i][0];
+ mask |= table[i][1];
+ }
+ }
+
+ xcb_configure_window(conn, win, mask, list);
+}
+
+/**************************
+ * Window Manager Helpers *
+ **************************/
+
+/* Send event info */
+static int send_event(event_t ev, xcb_window_t ewin)
+{
+ win_t *win = win_get(ewin);
+ do_grab_pointer(0);
+ int status = wm_handle_event(win, ev, MOD(), PTR());
+ do_ungrab_pointer();
+ return status;
+}
+
+/* Send event info */
+static int send_event_info(event_t ev, xcb_mod_mask_t mask, int up, int16_t *pos,
+ xcb_window_t rwin, xcb_window_t ewin, xcb_window_t cwin)
+{
+ xcb_window_t xcb = ewin == rwin ? cwin : ewin;
+ win_t *win = win_get(xcb);
+ mod_t mod = mask_to_mod(mask, up);
+ ptr_t ptr = list_to_ptr(pos);
+ do_grab_pointer(0);
+ int status = wm_handle_event(win, ev, mod, ptr);
+ do_ungrab_pointer();
+ return status;
+}
+
+/* Send pointer motion info */
+static int send_pointer(int16_t *pos,
+ xcb_window_t rwin, xcb_window_t ewin, xcb_window_t cwin)
+{
+ xcb_window_t xcb = ewin == rwin ? cwin : ewin;
+ win_t *win = win_get(xcb);
+ ptr_t ptr = list_to_ptr(pos);
+ do_grab_pointer(0);
+ int status = wm_handle_ptr(win, ptr);
+ do_ungrab_pointer();
+ return status;
+}
+
+/* Send window state info */
+static void send_manage(win_t *win, int managed)
+{
+ if (win->sys->managed == managed)
+ return;
+ if (managed)
+ wm_insert(win);
+ else
+ wm_remove(win);
+ win->sys->managed = managed;
+}
+
+/* Send window state info */
+static void send_state(win_t *win, state_t next)
+{
+ if (!win->sys->managed)
+ return;
+ if (win->state == next)
+ return;
+ state_t prev = win->state;
+ win->state = next;
+ wm_handle_state(win, prev, next);
+}
+