From f5cb5e5cf8a3b410a4afda52f925e84432ca2ac8 Mon Sep 17 00:00:00 2001 From: Samuel Fadel Date: Sun, 4 Dec 2022 12:32:13 +0100 Subject: Key grabbing, handling outputs, init clients. * main.scm: Added key press handler * wm.scm: Added key press handler * schewm.c: Added key grabbing, output management, client initialization (initial grab) --- main.scm | 7 +- schewm.c | 603 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ wm.scm | 14 +- 3 files changed, 563 insertions(+), 61 deletions(-) diff --git a/main.scm b/main.scm index f8ac169..e0647ab 100644 --- a/main.scm +++ b/main.scm @@ -11,11 +11,12 @@ (make-config 2 0)) (when (wm-init) - (wm-set-configure-notify-handler! - (lambda (x y w h) - (display (+ x y w h)) + (wm-set-key-press-handler! + (lambda (mod keysym) + (display (list mod keysym)) (display "\n"))) (display config) (display "\n") (wm-run) (wm-quit)) + diff --git a/schewm.c b/schewm.c index a515e1b..dd90982 100644 --- a/schewm.c +++ b/schewm.c @@ -20,8 +20,8 @@ const uint16_t MOVE_GLYPH = 52; const uint16_t RESIZE_GLYPH = 120; // Key modifiers -const uint16_t META = XCB_MOD_MASK_4; -const uint16_t SHIFT = XCB_MOD_MASK_SHIFT; +const uint16_t MOD_META = XCB_MOD_MASK_4; +const uint16_t MOD_SHIFT = XCB_MOD_MASK_SHIFT; struct Point { int16_t x, y; @@ -58,12 +58,12 @@ min(int16_t a, int16_t b) { return a < b ? a : b; } -uint16_t +uint32_t rect_intersect_area(const struct Rect *r1, const struct Rect *r2) { - int16_t x1 = max(r1->x, r2->x); - int16_t y1 = max(r1->y, r2->y); - int16_t x2 = min(r1->x + r1->width, r2->x + r2->width); - int16_t y2 = min(r1->y + r1->height, r2->y + r2->height); + int32_t x1 = max(r1->x, r2->x); + int32_t y1 = max(r1->y, r2->y); + int32_t x2 = min(r1->x + r1->width, r2->x + r2->width); + int32_t y2 = min(r1->y + r1->height, r2->y + r2->height); return (x1 > x2 || y1 > y2) ? 0 : (x2 - x1) * (y2 - y1); } @@ -112,17 +112,15 @@ client_new(xcb_window_t id) { return client; } -void -client_free(struct Client *client) { - // NOTE: We ignore monitor, next, and prev on purpose. The client - // does not own that memory. - free(client); -} - +/* + * Adds a new client to the ring, adjusting the necessary next/prev + * pointers. + */ struct Client * client_ring_add(struct Client *ring, struct Client *client) { if (ring == NULL || ring->next == NULL || ring->prev == NULL) { ring = client; + client->next = client; } client->prev = ring; @@ -132,13 +130,18 @@ client_ring_add(struct Client *ring, struct Client *client) { return client; } +/* + * Removes a client from the ring. We do not manage memory here, so + * the caller must free the memory of the client struct if that's + * needed. + */ struct Client * client_ring_erase(struct Client *ring, struct Client *client) { if (ring == NULL) { return NULL; } if (ring == client && client->next == client) { - client_free(ring); + // client_free(ring); return NULL; } @@ -146,7 +149,7 @@ client_ring_erase(struct Client *ring, struct Client *client) { client->prev->next = client->next; if (ring == client) { ring = client->next; - client_free(client); + // client_free(client); } return ring; } @@ -204,7 +207,7 @@ client_list_free(struct ClientList *list, bool deep) { while (list != NULL) { next = list->next; if (deep) { - client_free(list->client); + free(list->client); } free(list); list = next; @@ -326,6 +329,48 @@ struct Monitor { struct Monitor *prev, *next; }; +/* + * Add a new monitor to the ring, keeping it circular and adjusting + * the necessary next/prev pointers. + */ +struct Monitor * +monitor_ring_add(struct Monitor *ring, struct Monitor *monitor) { + if (ring == NULL || ring->next == NULL || ring->prev == NULL) { + ring = monitor; + monitor->next = monitor; + } + + monitor->prev = ring; + monitor->next = ring->next; + ring->next->prev = monitor; + ring->next = monitor; + return monitor; +} + +/* + * Same as for clients, we also don't manage memory here, just the + * structure of the ring. The caller should free the monitor struct if + * needed. + */ +struct Monitor * +monitor_ring_erase(struct Monitor *ring, struct Monitor *monitor) { + if (ring == NULL) { + return NULL; + } + if (ring == monitor && monitor->next == monitor) { + // free(ring); + return NULL; + } + + monitor->next->prev = monitor->prev; + monitor->prev->next = monitor->next; + if (ring == monitor) { + ring = monitor->next; + // free(monitor); + } + return ring; +} + void monitor_rect(const struct Monitor *monitor, struct Rect *rect) { rect->x = monitor->x; @@ -363,7 +408,7 @@ static struct { xcb_screen_t *screen; bool has_randr; int randr_base, screen_num; - struct Monitor monitors; + struct Monitor *monitors; } dpy; /* @@ -488,7 +533,7 @@ void wm_pack_right(); void wm_pack_top(); void wm_pack_bottom(); void wm_set_workspace(uint32_t workspace); -void wm_set_client_workspace(uint32_t workspace); +void wm_set_focused_client_workspace(uint32_t workspace); void wm_client_monitor_prev(); void wm_client_monitor_next(); @@ -550,6 +595,7 @@ wm_erase_client(xcb_window_t id) { // Workspace being NULL is a bug! workspace->ring = client_ring_erase(workspace->ring, client); clients_map_erase(wm.clients, client); + free(client); if (!wm.focus) { dpy_set_focus(XCB_NONE); } @@ -560,8 +606,151 @@ wm_has_error() { return dpy.has_error || xcb_connection_has_error(dpy.conn) > 0; } -static void +struct Monitor * +dpy_find_monitor(xcb_randr_output_t id) { + if (dpy.monitors == NULL) { + return NULL; + } + + struct Monitor *monitor = dpy.monitors; + for (;;) { + if (monitor->id == id) { + return monitor; + } + monitor = monitor->next; + if (monitor == dpy.monitors) { + break; + } + } + return NULL; +} + +static bool +dpy_update_output(xcb_randr_output_t output, + xcb_timestamp_t timestamp, + xcb_randr_get_output_info_reply_t *o_reply) { + xcb_randr_get_crtc_info_cookie_t c_cookie = + xcb_randr_get_crtc_info(dpy.conn, o_reply->crtc, timestamp); + xcb_randr_get_crtc_info_reply_t *c_reply = + xcb_randr_get_crtc_info_reply(dpy.conn, c_cookie, NULL); + if (!c_reply) { + return false; + } + + bool any_change = false; + struct Monitor *monitor = dpy_find_monitor(output); + if (monitor != NULL) { + // Monitor already known, update info + if (c_reply->x != monitor->x) { + monitor->x = c_reply->x; + any_change = true; + } + if (c_reply->y != monitor->y) { + monitor->y = c_reply->y; + any_change = true; + } + if (c_reply->width != monitor->width) { + monitor->width = c_reply->width; + any_change = true; + } + if (c_reply->height != monitor->height) { + monitor->height = c_reply->height; + any_change = true; + } + goto dpy_update_output_end; + } + + // Check if we have a clone of an existing monitor, since we did + // not find a monitor with same id + if (dpy.monitors != NULL) { + monitor = dpy.monitors; + for (;;) { + if (monitor->x == c_reply->x + && monitor->y == c_reply->y + && monitor->width == c_reply->width + && monitor->height == c_reply->height) { + // Found a clone, can be ignored + goto dpy_update_output_end; + } + monitor = monitor->next; + if (monitor == dpy.monitors) { + break; + } + } + } + + // It is a new monitor + // XXX: should we care about name length? + // int name_len = min(16, xcb_randr_get_output_info_name_length(output_info_reply.get())); + const char *name = (const char *) xcb_randr_get_output_info_name(o_reply); + monitor = calloc(1, sizeof(struct Monitor)); + if (monitor == NULL) { + goto dpy_update_output_end; + } + monitor->id = output; + monitor->name = name; + monitor->x = c_reply->x; + monitor->y = c_reply->y; + monitor->width = c_reply->width; + monitor->height = c_reply->height; + dpy.monitors = monitor_ring_add(dpy.monitors, monitor); + any_change = true; + +dpy_update_output_end: + free(c_reply); + return any_change; +} + +/* + * Attempts to update monitor info and returns whether there were any + * changes. + */ +static bool dpy_update_outputs() { + if (!dpy.has_randr) { + return false; + } + + xcb_randr_get_screen_resources_current_cookie_t s_cookie = + xcb_randr_get_screen_resources_current(dpy.conn, dpy.screen->root); + xcb_randr_get_screen_resources_current_reply_t *s_reply = + xcb_randr_get_screen_resources_current_reply(dpy.conn, s_cookie, NULL); + if (!s_reply) { + return false; + } + + bool any_change = false; + xcb_timestamp_t timestamp = s_reply->config_timestamp; + int length = xcb_randr_get_screen_resources_current_outputs_length(s_reply); + xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(s_reply); + for (int i = 0; i < length; i++) { + xcb_randr_get_output_info_cookie_t o_cookie = + xcb_randr_get_output_info(dpy.conn, outputs[i], timestamp); + xcb_randr_get_output_info_reply_t *o_reply = + xcb_randr_get_output_info_reply(dpy.conn, o_cookie, NULL); + if (!o_reply) { + continue; + } + + if (o_reply->crtc == XCB_NONE) { + // Output no longer active, delete if we had any info about it + struct Monitor *monitor = dpy_find_monitor(outputs[i]); + if (monitor == NULL) { + continue; + } + + dpy.monitors = monitor_ring_erase(dpy.monitors, monitor); + free(monitor); + any_change = true; + } else { + // New monitor or existing one changed its info + any_change = any_change || dpy_update_output(outputs[i], timestamp, o_reply); + } + + free(o_reply); + } + free(s_reply); + return any_change; } static void @@ -651,6 +840,7 @@ dpy_init(const char *wm_name) { dpy.has_error = false; dpy.has_randr = false; dpy.randr_base = -1; + dpy.monitors = NULL; dpy.conn = xcb_connect(NULL, &dpy.screen_num); if (wm_has_error()) { @@ -707,7 +897,8 @@ dpy_init(const char *wm_name) { net_atoms); // Setup RandR - const struct xcb_query_extension_reply_t *reply = xcb_get_extension_data(dpy.conn, &xcb_randr_id); + const struct xcb_query_extension_reply_t *reply = + xcb_get_extension_data(dpy.conn, &xcb_randr_id); if (!reply || !reply->present) { dpy.has_randr = false; } else { @@ -791,6 +982,81 @@ dpy_init(const char *wm_name) { return !dpy.has_error; } +static bool +dpy_grab_keycode(uint16_t mod, xcb_keycode_t keycode) { + xcb_void_cookie_t cookie = xcb_grab_key_checked( + dpy.conn, + true, + dpy.screen->root, + mod, + keycode, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC); + xcb_generic_error_t *error = xcb_request_check(dpy.conn, cookie); + return !error; +} + +static void +dpy_grab_keycode_with_lock_mods(uint16_t mod, xcb_keycode_t keycode) { + dpy_grab_keycode(mod, keycode); + if (mod == XCB_MOD_MASK_ANY) { + return; + } + + if (dpy.num_lock != 0) { + dpy_grab_keycode(mod | dpy.num_lock, keycode); + } + if (dpy.caps_lock != 0) { + dpy_grab_keycode(mod | dpy.caps_lock, keycode); + } + if (dpy.scroll_lock != 0) { + dpy_grab_keycode(mod | dpy.scroll_lock, keycode); + } + if (dpy.num_lock != 0 && dpy.caps_lock != 0) { + dpy_grab_keycode(mod | dpy.num_lock | dpy.caps_lock, keycode); + } + if (dpy.caps_lock != 0 && dpy.scroll_lock != 0) { + dpy_grab_keycode(mod | dpy.caps_lock | dpy.scroll_lock, keycode); + } + if (dpy.num_lock != 0 && dpy.scroll_lock != 0) { + dpy_grab_keycode(mod | dpy.num_lock | dpy.scroll_lock, keycode); + } + if (dpy.num_lock != 0 && dpy.caps_lock != 0 && dpy.scroll_lock != 0) { + dpy_grab_keycode(mod | dpy.num_lock | dpy.caps_lock | dpy.scroll_lock, keycode); + } +} + +static void +dpy_grab_key(uint16_t mod, xcb_keysym_t keysym) { + const xcb_setup_t *setup = xcb_get_setup(dpy.conn); + if (!setup) { + return; + } + + /* + * We go through every keycode in the setup, looking for the ones + * matching our keysym request. + */ + unsigned int kc; + for (kc = setup->min_keycode; kc <= setup->max_keycode; kc++) { + for (unsigned int col = 0; col < 4 /* KEYSYMS_PER_KEYCODE */; col++) { + xcb_keysym_t ks = xcb_key_symbols_get_keysym(dpy.keysyms, kc, col); + if (ks == keysym) { + dpy_grab_keycode_with_lock_mods(mod, kc); + } + } + } +} + +static void +dpy_set_workspace(uint32_t workspace) { + xcb_ewmh_set_current_desktop(dpy.ewmh, dpy.screen_num, workspace); +} + +static void +dpy_set_num_workspaces() { + xcb_ewmh_set_number_of_desktops(dpy.ewmh, dpy.screen_num, wm.num_workspaces); +} static void dpy_map_window(xcb_window_t window) { @@ -812,14 +1078,13 @@ dpy_raise_window(xcb_window_t window) { xcb_configure_window(dpy.conn, window, XCB_CONFIG_WINDOW_STACK_MODE, &mode); } -static void -dpy_set_workspace(uint32_t workspace) { - xcb_ewmh_set_current_desktop(dpy.ewmh, dpy.screen_num, workspace); -} - void dpy_set_window_border_width(xcb_window_t window) { - xcb_configure_window(dpy.conn, window, XCB_CONFIG_WINDOW_BORDER_WIDTH, &cfg.inner_border_width); + xcb_configure_window( + dpy.conn, + window, + XCB_CONFIG_WINDOW_BORDER_WIDTH, + &cfg.inner_border_width); } void @@ -827,6 +1092,66 @@ dpy_set_window_workspace(xcb_window_t window, uint32_t workspace) { xcb_ewmh_set_wm_desktop(dpy.ewmh, window, workspace); } +uint32_t +dpy_get_window_workspace(xcb_window_t window) { + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_desktop(dpy.ewmh, window); + uint32_t workspace = NULL_WORKSPACE; + // We don't check the return of the call below because, if anything goes + // wrong, we'd just assume o3::NULL_WORKSPACE anyway + xcb_ewmh_get_wm_desktop_reply(dpy.ewmh, cookie, &workspace, NULL); + return workspace; +} + +void +dpy_update_window_geometry(const struct Client *client) { + xcb_window_t window = client->id; + if (dpy.screen->root == window || window == XCB_NONE) { + return; + } + + uint32_t data[] = { + (uint32_t) client->x, + (uint32_t) client->y, + (uint32_t) client->width, + (uint32_t) client->height, + }; + uint16_t mask = XCB_CONFIG_WINDOW_X + | XCB_CONFIG_WINDOW_Y + | XCB_CONFIG_WINDOW_WIDTH + | XCB_CONFIG_WINDOW_HEIGHT; + xcb_configure_window(dpy.conn, window, mask, data); +} + +void +dpy_update_window_position(const struct Client *client) { + xcb_window_t window = client->id; + if (dpy.screen->root == window || window == XCB_NONE) { + return; + } + + uint32_t data[] = { + (uint32_t) client->x, + (uint32_t) client->y, + }; + uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y; + xcb_configure_window(dpy.conn, window, mask, data); +} + +void +dpy_update_window_size(const struct Client *client) { + xcb_window_t window = client->id; + if (dpy.screen->root == window || window == XCB_NONE) { + return; + } + + uint32_t data[] = { + (uint32_t) client->width, + (uint32_t) client->height, + }; + uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + xcb_configure_window(dpy.conn, window, mask, data); +} + #define RECT_INIT(x, y, w, h) { \ (int16_t) (x), \ (int16_t) (y), \ @@ -963,6 +1288,148 @@ void dpy_grab_buttons(struct Client *client) { } +bool +dpy_fetch_geometry(struct Client *client) { + xcb_get_geometry_cookie_t cookie = xcb_get_geometry(dpy.conn, client->id); + xcb_get_geometry_reply_t *reply = + xcb_get_geometry_reply(dpy.conn, cookie, NULL); + if (!reply) { + return false; + } + + client->x = reply->x; + client->y = reply->y; + client->width = reply->width; + client->height = reply->height; + free(reply); + return true; +} + +bool +dpy_fetch_hints(struct Client *client) { + xcb_size_hints_t hints; + xcb_get_property_cookie_t cookie = + xcb_icccm_get_wm_normal_hints_unchecked(dpy.conn, client->id); + uint8_t reply = xcb_icccm_get_wm_normal_hints_reply(dpy.conn, cookie, &hints, NULL); + if (!reply) { + return false; + } + + if (hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION) { + client->user_coord = true; + client->x = hints.x; + client->y = hints.y; + } + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { + client->min_width = hints.min_width; + client->min_height = hints.min_height; + } + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { + client->max_width = hints.max_width; + client->max_height = hints.max_height; + } + if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) { + client->base_width = hints.base_width; + client->base_height = hints.base_height; + } + return true; +} + +bool +dpy_fetch_cursor_position(struct Point *p) { + xcb_query_pointer_cookie_t cookie = + xcb_query_pointer(dpy.conn, dpy.screen->root); + xcb_query_pointer_reply_t *reply = + xcb_query_pointer_reply(dpy.conn, cookie, NULL); + if (!reply) { + return false; + } + + p->x = reply->win_x; + p->y = reply->win_y; + free(reply); + return true; +} + +struct Client * +dpy_make_client(xcb_window_t window) { + xcb_ewmh_get_atoms_reply_t window_type; + xcb_get_property_cookie_t cookie = + xcb_ewmh_get_wm_window_type(dpy.ewmh, window); + uint8_t reply = xcb_ewmh_get_wm_window_type_reply( + dpy.ewmh, + cookie, + &window_type, + NULL); + if (reply) { + for (uint32_t i = 0; i < window_type.atoms_len; i++) { + xcb_atom_t atom = window_type.atoms[i]; + if (atom == dpy.ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR + || atom == dpy.ewmh->_NET_WM_WINDOW_TYPE_DESKTOP + || atom == dpy.ewmh->_NET_WM_WINDOW_TYPE_DOCK) { + // Ignore those windows + xcb_ewmh_get_atoms_reply_wipe(&window_type); + return NULL; + } + } + xcb_ewmh_get_atoms_reply_wipe(&window_type); + } + + uint32_t event_mask[] = { XCB_EVENT_MASK_ENTER_WINDOW, XCB_NONE }; + xcb_change_window_attributes(dpy.conn, window, XCB_CW_EVENT_MASK, event_mask); + xcb_change_window_attributes(dpy.conn, window, XCB_CW_BACK_PIXEL, &cfg.colors.empty); + xcb_change_save_set(dpy.conn, XCB_SET_MODE_INSERT, window); + + struct Client *client = client_new(window); + if (client) { + dpy_fetch_geometry(client); + // Assume a reasonable max_width/max_height, then fetch hints + client->max_width = dpy.screen->width_in_pixels; + client->max_height = dpy.screen->height_in_pixels; + dpy_fetch_hints(client); + } + return client; +} + +/* + * Finds the monitor which contains most of the client's rect. + */ +struct Monitor * +find_monitor(const struct Client *client) { + if (dpy.monitors == NULL) { + return NULL; + } + if (dpy.monitors->next == dpy.monitors) { + // We only have one monitor + return dpy.monitors; + } + + struct Rect c_rect; + c_rect.x = client->x; + c_rect.y = client->y; + c_rect.width = client->width; + c_rect.height = client->height; + + uint32_t max_area = 0; + struct Monitor *iter = dpy.monitors; + struct Monitor *monitor = iter; + for (;;) { + struct Rect mon_rect; + monitor_rect(iter, &mon_rect); + uint32_t area = rect_intersect_area(&c_rect, &mon_rect); + if (area > max_area) { + max_area = area; + monitor = iter; + } + iter = iter->next; + if (iter == dpy.monitors) { + // We reached the first monitor in the ring again + break; + } + } + return monitor; +} + void wm_set_focus(struct Client *client) { if (wm.focus != NULL) { @@ -1030,8 +1497,12 @@ wm_set_workspace(uint32_t workspace) { } } +void +wm_set_client_workspace(struct Client *client, uint32_t workspace) { +} + /* - * Event handlers which take a generic event and know what to cast it into. + * event handlers which take a generic event and know what to cast it into. */ static void ev_configure_request(xcb_generic_event_t *); static void ev_destroy_notify(xcb_generic_event_t *); @@ -1045,9 +1516,44 @@ static void ev_circulate_request(xcb_generic_event_t *); static void ev_button_press(xcb_generic_event_t *); static void ev_client_message(xcb_generic_event_t *); -static bool -setup_client(xcb_window_t window) { - return false; +static struct Client * +manage_client_maybe_reposition(xcb_window_t window, bool set_position) { + struct Client *client = dpy_make_client(window); + if (!client) { + return NULL; + } + // TODO: check if unkillable + uint32_t workspace = dpy_get_window_workspace(client->id); + if (workspace == ALL_WORKSPACES) { + fprintf(stderr, "client was supposed to be sticky;" + " mapping to current workspace\n"); + workspace = wm.cur_workspace; + } else if (workspace == NULL_WORKSPACE || workspace >= wm.num_workspaces) { + workspace = wm.cur_workspace; + } + wm_set_client_workspace(client, workspace); + if (set_position && !client->user_coord) { + // No predefined position, map at cursor position if possible + struct Point p; + if (!dpy_fetch_cursor_position(&p)) { + p.x = p.y = 0; + } + client->x = p.x - client->width / 2; + client->y = p.y - client->height / 2; + dpy_update_window_position(client); + } + client->monitor = find_monitor(client); + wm_fit_client(client); + clients_map_add(wm.clients, client); + if (client->state == WS_NORMAL) { + dpy_draw_unfocused_borders(client); + } + return client; +} + +static struct Client * +manage_client(xcb_window_t window) { + return manage_client_maybe_reposition(window, false); } bool @@ -1057,24 +1563,22 @@ wm_init() { } wm.is_running = true; - wm.cur_workspace = 0; - wm.num_workspaces = 10; - wm.workspaces = calloc(wm.num_workspaces, sizeof(struct Workspace)); wm.focus = NULL; wm.clients = clients_map_new(128); - // TODO - // wm.workspaces = INIT; - // dpy_set_num_workspaces(); + wm.cur_workspace = 0; + wm.num_workspaces = 10; + wm.workspaces = calloc(wm.num_workspaces, sizeof(struct Workspace)); + dpy_set_num_workspaces(); // Look into all existing windows and set them up struct WindowsQueryReply reply; windows_query(dpy.screen->root, &reply); for (int i = 0; i < reply.length; i++) { xcb_window_t window = reply.data[i]; - if (!setup_client(window)) { + if (!manage_client(window)) { /* - * Could not be setup, just map it on screen because we + * Could not be managed, just map it on screen because we * probably should not own it. */ dpy_map_window(window); @@ -1093,6 +1597,7 @@ wm_init() { // update_client_list(); wm_set_workspace(wm.cur_workspace); // grab_keys(); + dpy_grab_key(XCB_MOD_MASK_ANY, XK_q); dpy_flush(); memset(wm.events, 0, sizeof(wm.events)); @@ -1148,15 +1653,16 @@ wm_destroy() { dpy_destroy(); } -static int +static uint8_t ev_type(const xcb_generic_event_t *ev) { - return ev->response_type & 0x80; + return ev->response_type & ~0x80; } void wm_run() { while (wm.is_running) { xcb_generic_event_t *ev = xcb_wait_for_event(dpy.conn); + fprintf(stderr, "ev: %u\n", ev_type(ev)); generic_event_handler_t handler = wm.events[ev_type(ev)]; if (handler) { handler(ev); @@ -1167,7 +1673,7 @@ wm_run() { wm_destroy(); } -static uint16_t mod_key = META; +static uint16_t mod_key = MOD_META; void wm_set_mod_key(uint16_t mod) { @@ -1177,7 +1683,7 @@ wm_set_mod_key(uint16_t mod) { uint16_t wm_get_mod_key(bool with_shift) { if (with_shift) { - return mod_key | SHIFT; + return mod_key | MOD_SHIFT; } return mod_key; } @@ -1204,7 +1710,6 @@ wm_set_configure_request_handler(configure_request_handler_t handler) { static void ev_configure_request(xcb_generic_event_t *generic_ev) { - fprintf(stderr, "configure_request\n"); if (configure_request_handler) { xcb_configure_request_event_t *ev = (xcb_configure_request_event_t *) generic_ev; configure_request_handler(); @@ -1222,7 +1727,6 @@ wm_set_destroy_notify_handler(destroy_notify_handler_t handler) { static void ev_destroy_notify(xcb_generic_event_t *generic_ev) { - fprintf(stderr, "destroy_notify\n"); if (destroy_notify_handler) { xcb_destroy_notify_event_t *ev = (xcb_destroy_notify_event_t *) generic_ev; destroy_notify_handler(); @@ -1240,7 +1744,6 @@ wm_set_enter_notify_handler(enter_notify_handler_t handler) { static void ev_enter_notify(xcb_generic_event_t *generic_ev) { - fprintf(stderr, "enter_notify\n"); if (enter_notify_handler) { xcb_enter_notify_event_t *ev = (xcb_enter_notify_event_t *) generic_ev; enter_notify_handler(); @@ -1248,7 +1751,7 @@ ev_enter_notify(xcb_generic_event_t *generic_ev) { } // XCB_KEY_PRESS -typedef void (*key_press_handler_t)(); +typedef void (*key_press_handler_t)(uint16_t, uint8_t); static key_press_handler_t key_press_handler = NULL; void @@ -1258,10 +1761,9 @@ wm_set_key_press_handler(key_press_handler_t handler) { static void ev_key_press(xcb_generic_event_t *generic_ev) { - fprintf(stderr, "key_press\n"); if (key_press_handler) { xcb_key_press_event_t *ev = (xcb_key_press_event_t *) generic_ev; - key_press_handler(); + key_press_handler(ev->state, ev->detail); } } @@ -1276,7 +1778,6 @@ wm_set_map_request_handler(map_request_handler_t handler) { static void ev_map_request(xcb_generic_event_t *generic_ev) { - fprintf(stderr, "map_resquest\n"); if (map_request_handler) { xcb_map_request_event_t *ev = (xcb_map_request_event_t *) generic_ev; map_request_handler(); @@ -1294,7 +1795,6 @@ wm_set_unmap_notify_handler(unmap_notify_handler_t handler) { static void ev_unmap_notify(xcb_generic_event_t *generic_ev) { - fprintf(stderr, "unmap_notify\n"); if (unmap_notify_handler) { xcb_unmap_notify_event_t *ev = (xcb_unmap_notify_event_t *) generic_ev; unmap_notify_handler(); @@ -1312,7 +1812,6 @@ wm_set_mapping_notify_handler(mapping_notify_handler_t handler) { static void ev_mapping_notify(xcb_generic_event_t *generic_ev) { - fprintf(stderr, "mapping_notify\n"); if (mapping_notify_handler) { xcb_mapping_notify_event_t *ev = (xcb_mapping_notify_event_t *) generic_ev; mapping_notify_handler(); diff --git a/wm.scm b/wm.scm index 06d1581..85a23f4 100644 --- a/wm.scm +++ b/wm.scm @@ -1,7 +1,7 @@ (define-module (wm) #:use-module (system foreign) #:export (wm-init - wm-set-configure-notify-handler! + wm-set-key-press-handler! wm-run wm-quit)) @@ -28,14 +28,16 @@ (define wm-run (schewm-func void "wm_run" '())) -(define c/wm-set-configure-notify-handler +(define c/wm-set-key-press-handler (schewm-func void - "wm_set_configure_notify_handler" + "wm_set_key_press_handler" (list '*))) -(define (wm-set-configure-notify-handler! handler) - (c/wm-set-configure-notify-handler +(define (wm-set-key-press-handler! handler) + ;; mod (state, uint16) + ;; keysym (detail, uint8) + (c/wm-set-key-press-handler (procedure->pointer void handler - (list int16 int16 uint32 uint32)))) + (list uint16 uint8)))) -- cgit v1.2.3