From bf1f461eba320cdeded1d5d8ae80caaa9d4cef98 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 15 Nov 2017 22:35:16 +0100 Subject: [PATCH 1/9] Call wl_output_send_done when current mode is updated --- types/wlr_output.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/types/wlr_output.c b/types/wlr_output.c index df02afec..411dd404 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -29,8 +29,7 @@ static void wl_output_send_to_resource(struct wl_resource *resource) { if (version >= WL_OUTPUT_MODE_SINCE_VERSION) { struct wlr_output_mode *mode; wl_list_for_each(mode, &output->modes, link) { - // TODO: mode->flags should just be preferred - uint32_t flags = mode->flags; + uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED; if (output->current_mode == mode) { flags |= WL_OUTPUT_MODE_CURRENT; } @@ -62,13 +61,17 @@ static void wlr_output_send_current_mode_to_resource( } if (output->current_mode != NULL) { struct wlr_output_mode *mode = output->current_mode; - wl_output_send_mode(resource, mode->flags | WL_OUTPUT_MODE_CURRENT, + uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED; + wl_output_send_mode(resource, flags | WL_OUTPUT_MODE_CURRENT, mode->width, mode->height, mode->refresh); } else { // Output has no mode, send the current width/height wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, output->width, output->height, 0); } + if (version >= WL_OUTPUT_DONE_SINCE_VERSION) { + wl_output_send_done(resource); + } } static void wl_output_destroy(struct wl_resource *resource) { @@ -163,6 +166,9 @@ bool wlr_output_set_mode(struct wlr_output *output, void wlr_output_update_size(struct wlr_output *output, int32_t width, int32_t height) { + if (output->width == width && output->height == height) { + return; + } output->width = width; output->height = height; wlr_output_update_matrix(output); From 73c48f2f35ffea2f4fb03f54e652559be4bfe658 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 16 Nov 2017 09:33:47 +0100 Subject: [PATCH 2/9] Terminate local display on remote Wayland display error --- backend/wayland/backend.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 532935b8..bfc73e05 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -12,10 +12,15 @@ #include "backend/wayland.h" #include "xdg-shell-unstable-v6-client-protocol.h" - static int dispatch_events(int fd, uint32_t mask, void *data) { struct wlr_wl_backend *backend = data; int count = 0; + + if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) { + wl_display_terminate(backend->local_display); + return 0; + } + if (mask & WL_EVENT_READABLE) { count = wl_display_dispatch(backend->remote_display); } From 7d847efe403c01a842a3e237b49249c95372d9de Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 16 Nov 2017 09:38:24 +0100 Subject: [PATCH 3/9] Terminate local display on remote X11 server error --- backend/wayland/backend.c | 7 +++---- backend/x11/backend.c | 10 ++++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index bfc73e05..1801f3e0 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -41,7 +41,7 @@ static bool wlr_wl_backend_start(struct wlr_backend *_backend) { wlr_log(L_INFO, "Initializating wayland backend"); wlr_wl_registry_poll(backend); - if (!(backend->compositor) || (!(backend->shell))) { + if (!backend->compositor || !backend->shell) { wlr_log_errno(L_ERROR, "Could not obtain retrieve required globals"); return false; } @@ -54,10 +54,9 @@ static bool wlr_wl_backend_start(struct wlr_backend *_backend) { struct wl_event_loop *loop = wl_display_get_event_loop(backend->local_display); int fd = wl_display_get_fd(backend->remote_display); - int events = WL_EVENT_READABLE | WL_EVENT_ERROR | - WL_EVENT_HANGUP; + int events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP; backend->remote_display_src = wl_event_loop_add_fd(loop, fd, events, - dispatch_events, backend); + dispatch_events, backend); wl_event_source_check(backend->remote_display_src); return true; diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 97b0dd8c..b798daf6 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -155,9 +155,14 @@ static bool handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *e static int x11_event(int fd, uint32_t mask, void *data) { struct wlr_x11_backend *x11 = data; + + if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) { + wl_display_terminate(x11->wl_display); + return 0; + } + xcb_generic_event_t *e; bool quit = false; - while (!quit && (e = xcb_poll_for_event(x11->xcb_conn))) { quit = handle_x11_event(x11, e); free(e); @@ -205,7 +210,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, int fd = xcb_get_file_descriptor(x11->xcb_conn); struct wl_event_loop *ev = wl_display_get_event_loop(display); - x11->event_source = wl_event_loop_add_fd(ev, fd, WL_EVENT_READABLE, x11_event, x11); + int events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP; + x11->event_source = wl_event_loop_add_fd(ev, fd, events, x11_event, x11); if (!x11->event_source) { wlr_log(L_ERROR, "Could not create event source"); goto error_x11; From bb79ada49f43be5417bdd55fda3a7cf07c2a69df Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 16 Nov 2017 10:30:54 +0100 Subject: [PATCH 4/9] Fix a bunch of mistakes detected with scan-build --- backend/libinput/events.c | 5 +++-- backend/session/session.c | 2 +- rootston/config.c | 2 +- rootston/cursor.c | 2 +- rootston/keyboard.c | 1 + rootston/seat.c | 1 - types/wlr_data_device.c | 5 ++++- types/wlr_keyboard.c | 5 ++++- types/wlr_screenshooter.c | 3 +++ types/wlr_wl_shell.c | 2 +- 10 files changed, 19 insertions(+), 9 deletions(-) diff --git a/backend/libinput/events.c b/backend/libinput/events.c index 5da45c67..3ca41124 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -66,10 +66,11 @@ static void handle_device_added(struct wlr_libinput_backend *backend, int product = libinput_device_get_id_product(libinput_dev); const char *name = libinput_device_get_name(libinput_dev); struct wl_list *wlr_devices = calloc(1, sizeof(struct wl_list)); - wl_list_init(wlr_devices); if (!wlr_devices) { - goto fail; + wlr_log(L_ERROR, "Allocation failed"); + return; } + wl_list_init(wlr_devices); wlr_log(L_DEBUG, "Added %s [%d:%d]", name, vendor, product); if (libinput_device_has_capability(libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) { diff --git a/backend/session/session.c b/backend/session/session.c index 760830c3..657558fd 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -249,7 +249,7 @@ static size_t explicit_find_gpus(struct wlr_session *session, } } while ((ptr = strtok_r(NULL, ":", &save))); - free(ptr); + free(gpus); return i; } diff --git a/rootston/config.c b/rootston/config.c index 7ffbb786..727b52d0 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -405,7 +405,7 @@ void roots_config_destroy(struct roots_config *config) { } struct roots_keyboard_config *kc, *ktmp = NULL; - wl_list_for_each_safe(kc, ktmp, &config->bindings, link) { + wl_list_for_each_safe(kc, ktmp, &config->keyboards, link) { free(kc->name); free(kc->rules); free(kc->model); diff --git a/rootston/cursor.c b/rootston/cursor.c index ecd5e9a0..5949a364 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -18,9 +18,9 @@ struct roots_cursor *roots_cursor_create(struct roots_seat *seat) { } cursor->cursor = wlr_cursor_create(); if (!cursor->cursor) { + free(cursor); return NULL; } - return cursor; } diff --git a/rootston/keyboard.c b/rootston/keyboard.c index c118e55c..fb648ae5 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -141,6 +141,7 @@ static bool keyboard_keysyms_xkb(struct roots_keyboard *keyboard, uint32_t consumed = xkb_state_key_get_consumed_mods2( keyboard->device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB); + // TODO: actually use this value modifiers = modifiers & ~consumed; bool handled = false; diff --git a/rootston/seat.c b/rootston/seat.c index 6d8dc749..1fa37c44 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -252,7 +252,6 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { seat->seat = wlr_seat_create(input->server->wl_display, name); if (!seat->seat) { free(seat); - roots_cursor_destroy(seat->cursor); return NULL; } diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index df18317b..4d926236 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -636,7 +636,10 @@ static void data_device_start_drag(struct wl_client *client, if (!seat_client_start_drag(seat_client, source, icon)) { wl_resource_post_no_memory(device_resource); - } else { + return; + } + + if (source) { source->seat_client = seat_client; } } diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index 98ebeed5..c4f2ed52 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -105,7 +105,10 @@ void wlr_keyboard_init(struct wlr_keyboard *kb, } void wlr_keyboard_destroy(struct wlr_keyboard *kb) { - if (kb && kb->impl && kb->impl->destroy) { + if (kb == NULL) { + return; + } + if (kb->impl && kb->impl->destroy) { kb->impl->destroy(kb); } else { wl_list_remove(&kb->events.key.listener_list); diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index a78c7ad7..94b45384 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -85,6 +85,7 @@ static void screenshooter_shoot(struct wl_client *client, struct wlr_screenshot *screenshot = calloc(1, sizeof(struct wlr_screenshot)); if (!screenshot) { + free(pixels); wl_resource_post_no_memory(screenshooter_resource); return; } @@ -96,6 +97,7 @@ static void screenshooter_shoot(struct wl_client *client, wl_resource_get_version(screenshooter_resource), id); if (screenshot->resource == NULL) { free(screenshot); + free(pixels); wl_resource_post_no_memory(screenshooter_resource); return; } @@ -109,6 +111,7 @@ static void screenshooter_shoot(struct wl_client *client, if (!state) { wl_resource_destroy(screenshot->resource); free(screenshot); + free(pixels); wl_resource_post_no_memory(screenshooter_resource); return; } diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 31032fef..abe967d7 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -347,7 +347,7 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, transient_state->flags = flags; struct wlr_wl_shell_surface_popup_state *popup_state = - calloc(1, sizeof(struct wlr_wl_shell_surface_transient_state)); + calloc(1, sizeof(struct wlr_wl_shell_surface_popup_state)); if (popup_state == NULL) { free(transient_state); wl_client_post_no_memory(client); From 53d4cb47ffae0f8632ba7aea1687fdf75dd7deb8 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 16 Nov 2017 16:13:23 +0100 Subject: [PATCH 5/9] Refactor rootston keyboard --- include/rootston/keyboard.h | 3 +- rootston/keyboard.c | 159 ++++++++++++++++++++---------------- 2 files changed, 90 insertions(+), 72 deletions(-) diff --git a/include/rootston/keyboard.h b/include/rootston/keyboard.h index 15e7c9c4..39650d7c 100644 --- a/include/rootston/keyboard.h +++ b/include/rootston/keyboard.h @@ -16,7 +16,8 @@ struct roots_keyboard { struct wl_listener keyboard_key; struct wl_listener keyboard_modifiers; - xkb_keysym_t pressed_keysyms[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; + xkb_keysym_t pressed_keysyms_translated[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; + xkb_keysym_t pressed_keysyms_raw[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; }; struct roots_keyboard *roots_keyboard_create(struct wlr_input_device *device, diff --git a/rootston/keyboard.c b/rootston/keyboard.c index fb648ae5..566a1d7e 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -13,16 +13,35 @@ #include "rootston/seat.h" #include "rootston/keyboard.h" -static ssize_t keyboard_pressed_keysym_index(struct roots_keyboard *keyboard, +static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms, xkb_keysym_t keysym) { - for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; i++) { - if (keyboard->pressed_keysyms[i] == keysym) { + for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { + if (pressed_keysyms[i] == keysym) { return i; } } return -1; } +static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms, + xkb_keysym_t keysym) { + ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); + if (i < 0) { + i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol); + if (i >= 0) { + pressed_keysyms[i] = keysym; + } + } +} + +static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms, + xkb_keysym_t keysym) { + ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); + if (i >= 0) { + pressed_keysyms[i] = XKB_KEY_NoSymbol; + } +} + static const char *exec_prefix = "exec "; static void keyboard_binding_execute(struct roots_keyboard *keyboard, @@ -56,21 +75,13 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } /** - * Process a keypress from the keyboard. + * Execute a built-in, hardcoded compositor action when a keysym is pressed. * * Returns true if the keysym was handled by a binding and false if the event * should be propagated to clients. */ -static bool keyboard_keysym_press(struct roots_keyboard *keyboard, +static bool keyboard_press_keysym(struct roots_keyboard *keyboard, xkb_keysym_t keysym) { - ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym); - if (i < 0) { - i = keyboard_pressed_keysym_index(keyboard, XKB_KEY_NoSymbol); - if (i >= 0) { - keyboard->pressed_keysyms[i] = keysym; - } - } - if (keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12) { struct roots_server *server = keyboard->input->server; @@ -90,7 +101,35 @@ static bool keyboard_keysym_press(struct roots_keyboard *keyboard, wlr_seat_keyboard_end_grab(keyboard->seat->seat); } - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + return false; +} + +/** + * Press or release keysyms. + * + * Returns true if the keysym was handled by a binding and false if the event + * should be propagated to clients. + */ +static bool keyboard_handle_keysyms(struct roots_keyboard *keyboard, + xkb_keysym_t *pressed_keysyms, uint32_t modifiers, + const xkb_keysym_t *keysyms, size_t keysyms_len, + enum wlr_key_state state) { + bool handled = false; + for (size_t i = 0; i < keysyms_len; ++i) { + if (state == WLR_KEY_PRESSED) { + pressed_keysyms_add(pressed_keysyms, keysyms[i]); + handled |= keyboard_press_keysym(keyboard, keysyms[i]); + } else { // WLR_KEY_RELEASED + pressed_keysyms_remove(pressed_keysyms, keysyms[i]); + } + } + if (handled) { + return true; + } + if (state != WLR_KEY_PRESSED) { + return false; + } + struct wl_list *bindings = &keyboard->input->server->config->bindings; struct roots_binding_config *bc; wl_list_for_each(bc, bindings, link) { @@ -100,7 +139,7 @@ static bool keyboard_keysym_press(struct roots_keyboard *keyboard, bool ok = true; for (size_t i = 0; i < bc->keysyms_len; i++) { - ssize_t j = keyboard_pressed_keysym_index(keyboard, bc->keysyms[i]); + ssize_t j = pressed_keysyms_index(pressed_keysyms, bc->keysyms[i]); if (j < 0) { ok = false; break; @@ -116,86 +155,64 @@ static bool keyboard_keysym_press(struct roots_keyboard *keyboard, return false; } -static void keyboard_keysym_release(struct roots_keyboard *keyboard, - xkb_keysym_t keysym) { - ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym); - if (i >= 0) { - keyboard->pressed_keysyms[i] = XKB_KEY_NoSymbol; - } -} /* - * Process keypresses from the keyboard as xkb sees them. + * Get keysyms and modifiers from the keyboard as xkb sees them. * * This uses the xkb keysyms translation based on pressed modifiers and clears * the consumed modifiers from the list of modifiers passed to keybind * detection. * - * (On US layout) this will trigger: [Alt]+[at] + * On US layout, this will trigger: Alt + @ */ -static bool keyboard_keysyms_xkb(struct roots_keyboard *keyboard, - uint32_t keycode, enum wlr_key_state state) { - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - const xkb_keysym_t *syms; - int syms_len = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, - keycode, &syms); - uint32_t consumed = xkb_state_key_get_consumed_mods2( +static size_t keyboard_keysyms_translated(struct roots_keyboard *keyboard, + xkb_keycode_t keycode, const xkb_keysym_t **keysyms, + uint32_t *modifiers) { + *modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2( keyboard->device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB); + *modifiers = *modifiers & ~consumed; - // TODO: actually use this value - modifiers = modifiers & ~consumed; - - bool handled = false; - for (int i = 0; i < syms_len; i++) { - if (state) { - bool keysym_handled = - keyboard_keysym_press(keyboard, syms[i]); - handled = handled || keysym_handled; - } else { // WLR_KEY_RELEASED - keyboard_keysym_release(keyboard, syms[i]); - } - } - - return handled; + return xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, keysyms); } + /* - * Process keypresses from the keyboard as if modifiers didn't change keysyms. + * Get keysyms and modifiers from the keyboard as if modifiers didn't change + * keysyms. * * This avoids the xkb keysym translation based on modifiers considered pressed - * in the state and uses the list of modifiers saved on the rootston side. + * in the state. * - * This will trigger the keybind: [Alt]+[Shift]+2 + * This will trigger the keybind: Alt + Shift + 2 */ -static bool keyboard_keysyms_simple(struct roots_keyboard *keyboard, - uint32_t keycode, enum wlr_key_state state) { - const xkb_keysym_t *syms; +static size_t keyboard_keysyms_raw(struct roots_keyboard *keyboard, + xkb_keycode_t keycode, const xkb_keysym_t **keysyms, + uint32_t *modifiers) { + *modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + xkb_layout_index_t layout_index = xkb_state_key_get_layout( keyboard->device->keyboard->xkb_state, keycode); - int syms_len = xkb_keymap_key_get_syms_by_level( - keyboard->device->keyboard->keymap, keycode, layout_index, 0, &syms); - - bool handled = false; - for (int i = 0; i < syms_len; i++) { - if (state) { - bool keysym_handled = keyboard_keysym_press(keyboard, syms[i]); - handled = handled || keysym_handled; - } else { // WLR_KEY_RELEASED - keyboard_keysym_release(keyboard, syms[i]); - } - } - - return handled; + return xkb_keymap_key_get_syms_by_level(keyboard->device->keyboard->keymap, + keycode, layout_index, 0, keysyms); } void roots_keyboard_handle_key(struct roots_keyboard *keyboard, struct wlr_event_keyboard_key *event) { - uint32_t keycode = event->keycode + 8; - - bool handled = keyboard_keysyms_xkb(keyboard, keycode, event->state); + xkb_keycode_t keycode = event->keycode + 8; + uint32_t modifiers; + const xkb_keysym_t *keysyms; + size_t keysyms_len = keyboard_keysyms_translated(keyboard, keycode, + &keysyms, &modifiers); + bool handled = keyboard_handle_keysyms(keyboard, + keyboard->pressed_keysyms_translated, modifiers, keysyms, keysyms_len, + event->state); if (!handled) { - bool key_handled = keyboard_keysyms_simple(keyboard, keycode, + keysyms_len = keyboard_keysyms_raw(keyboard, keycode, &keysyms, + &modifiers); + handled = keyboard_handle_keysyms(keyboard, + keyboard->pressed_keysyms_raw, modifiers, keysyms, keysyms_len, event->state); - handled = handled || key_handled; } if (!handled) { From e674266b44a5a8991e697ea43d5a0c8b461f76bf Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 16 Nov 2017 16:34:39 +0100 Subject: [PATCH 6/9] Fix example config file --- rootston/rootston.ini.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootston/rootston.ini.example b/rootston/rootston.ini.example index 433dc78f..c33b0f04 100644 --- a/rootston/rootston.ini.example +++ b/rootston/rootston.ini.example @@ -40,6 +40,6 @@ meta-key = Logo # - "close" to close the current view # - "next_window" to cycle through windows [bindings] -Logo+Shift+E = exit +Logo+Shift+e = exit Logo+q = close Alt+Tab = next_window From a52ca9482a7583bee22c8435b96a6141d44939f4 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 16 Nov 2017 18:58:33 +0100 Subject: [PATCH 7/9] Various keyboard fixes * Ensure keysyms state is always updated * Check if pressed keysyms are exactly the binding keysyms * Do not include modifiers in list of keysyms, these are special cases --- rootston/keyboard.c | 107 +++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 31 deletions(-) diff --git a/rootston/keyboard.c b/rootston/keyboard.c index 566a1d7e..39f46a32 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -23,6 +23,16 @@ static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms, return -1; } +static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) { + size_t n = 0; + for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { + if (pressed_keysyms[i] != XKB_KEY_NoSymbol) { + ++n; + } + } + return n; +} + static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms, xkb_keysym_t keysym) { ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); @@ -42,6 +52,37 @@ static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms, } } +static bool keysym_is_modifier(xkb_keysym_t keysym) { + switch (keysym) { + case XKB_KEY_Shift_L: case XKB_KEY_Shift_R: + case XKB_KEY_Control_L: case XKB_KEY_Control_R: + case XKB_KEY_Caps_Lock: + case XKB_KEY_Shift_Lock: + case XKB_KEY_Meta_L: case XKB_KEY_Meta_R: + case XKB_KEY_Alt_L: case XKB_KEY_Alt_R: + case XKB_KEY_Super_L: case XKB_KEY_Super_R: + case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R: + return true; + default: + return false; + } +} + +static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms, + const xkb_keysym_t *keysyms, size_t keysyms_len, + enum wlr_key_state state) { + for (size_t i = 0; i < keysyms_len; ++i) { + if (keysym_is_modifier(keysyms[i])) { + continue; + } + if (state == WLR_KEY_PRESSED) { + pressed_keysyms_add(pressed_keysyms, keysyms[i]); + } else { // WLR_KEY_RELEASED + pressed_keysyms_remove(pressed_keysyms, keysyms[i]); + } + } +} + static const char *exec_prefix = "exec "; static void keyboard_binding_execute(struct roots_keyboard *keyboard, @@ -75,12 +116,13 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } /** - * Execute a built-in, hardcoded compositor action when a keysym is pressed. + * Execute a built-in, hardcoded compositor binding. These are triggered from a + * single keysym. * * Returns true if the keysym was handled by a binding and false if the event * should be propagated to clients. */ -static bool keyboard_press_keysym(struct roots_keyboard *keyboard, +static bool keyboard_execute_compositor_binding(struct roots_keyboard *keyboard, xkb_keysym_t keysym) { if (keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12) { @@ -105,35 +147,27 @@ static bool keyboard_press_keysym(struct roots_keyboard *keyboard, } /** - * Press or release keysyms. + * Execute keyboard bindings. These include compositor bindings and user-defined + * bindings. * * Returns true if the keysym was handled by a binding and false if the event * should be propagated to clients. */ -static bool keyboard_handle_keysyms(struct roots_keyboard *keyboard, +static bool keyboard_execute_binding(struct roots_keyboard *keyboard, xkb_keysym_t *pressed_keysyms, uint32_t modifiers, - const xkb_keysym_t *keysyms, size_t keysyms_len, - enum wlr_key_state state) { - bool handled = false; + const xkb_keysym_t *keysyms, size_t keysyms_len) { for (size_t i = 0; i < keysyms_len; ++i) { - if (state == WLR_KEY_PRESSED) { - pressed_keysyms_add(pressed_keysyms, keysyms[i]); - handled |= keyboard_press_keysym(keyboard, keysyms[i]); - } else { // WLR_KEY_RELEASED - pressed_keysyms_remove(pressed_keysyms, keysyms[i]); + if (keyboard_execute_compositor_binding(keyboard, keysyms[i])) { + return true; } } - if (handled) { - return true; - } - if (state != WLR_KEY_PRESSED) { - return false; - } + // User-defined bindings + size_t n = pressed_keysyms_length(pressed_keysyms); struct wl_list *bindings = &keyboard->input->server->config->bindings; struct roots_binding_config *bc; wl_list_for_each(bc, bindings, link) { - if (modifiers ^ bc->modifiers) { + if (modifiers ^ bc->modifiers || n != bc->keysyms_len) { continue; } @@ -162,7 +196,7 @@ static bool keyboard_handle_keysyms(struct roots_keyboard *keyboard, * the consumed modifiers from the list of modifiers passed to keybind * detection. * - * On US layout, this will trigger: Alt + @ + * On US layout, pressing Alt+Shift+2 will trigger Alt+@. */ static size_t keyboard_keysyms_translated(struct roots_keyboard *keyboard, xkb_keycode_t keycode, const xkb_keysym_t **keysyms, @@ -183,7 +217,7 @@ static size_t keyboard_keysyms_translated(struct roots_keyboard *keyboard, * This avoids the xkb keysym translation based on modifiers considered pressed * in the state. * - * This will trigger the keybind: Alt + Shift + 2 + * This will trigger keybinds such as Alt+Shift+2. */ static size_t keyboard_keysyms_raw(struct roots_keyboard *keyboard, xkb_keycode_t keycode, const xkb_keysym_t **keysyms, @@ -200,19 +234,30 @@ void roots_keyboard_handle_key(struct roots_keyboard *keyboard, struct wlr_event_keyboard_key *event) { xkb_keycode_t keycode = event->keycode + 8; + bool handled = false; uint32_t modifiers; const xkb_keysym_t *keysyms; - size_t keysyms_len = keyboard_keysyms_translated(keyboard, keycode, - &keysyms, &modifiers); - bool handled = keyboard_handle_keysyms(keyboard, - keyboard->pressed_keysyms_translated, modifiers, keysyms, keysyms_len, + size_t keysyms_len; + + // Handle translated keysyms + + keysyms_len = keyboard_keysyms_translated(keyboard, keycode, &keysyms, + &modifiers); + pressed_keysyms_update(keyboard->pressed_keysyms_translated, keysyms, + keysyms_len, event->state); + if (event->state == WLR_KEY_PRESSED) { + handled = keyboard_execute_binding(keyboard, + keyboard->pressed_keysyms_translated, modifiers, keysyms, + keysyms_len); + } + + // Handle raw keysyms + keysyms_len = keyboard_keysyms_raw(keyboard, keycode, &keysyms, &modifiers); + pressed_keysyms_update(keyboard->pressed_keysyms_raw, keysyms, keysyms_len, event->state); - if (!handled) { - keysyms_len = keyboard_keysyms_raw(keyboard, keycode, &keysyms, - &modifiers); - handled = keyboard_handle_keysyms(keyboard, - keyboard->pressed_keysyms_raw, modifiers, keysyms, keysyms_len, - event->state); + if (event->state == WLR_KEY_PRESSED && !handled) { + handled = keyboard_execute_binding(keyboard, + keyboard->pressed_keysyms_raw, modifiers, keysyms, keysyms_len); } if (!handled) { From a446f735aea6f294bc75a1675f191521d45ed2d0 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 16 Nov 2017 15:39:48 -0500 Subject: [PATCH 8/9] readme: add basic running doc --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 0f221e3c..721265ae 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,25 @@ Run these commands: ninja -C build (On FreeBSD, you need to pass an extra flag to prevent a linking error: `meson build -D b_lundef=false`) + +## Running the Reference Compositor + +wlroots comes with a reference compositor called rootston that demonstrates the +features of the library. + +After building, run rootston from a terminal or VT with: + + ./build/rootston/rootston + +Run windows on the compositor with the display variable set: + +```bash +# run gtk apps like this +gnome-calculator --display=wayland-0 + +# run QT apps like this +qgit -platform wayland + +# run X11 apps like this +DISPLAY=:1 firefox +``` From 2bbea060937dd8ab99be2a4878c837298343f02a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 16 Nov 2017 15:59:12 -0500 Subject: [PATCH 9/9] readme: change running instructions --- README.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 721265ae..06ef8dcb 100644 --- a/README.md +++ b/README.md @@ -43,15 +43,7 @@ After building, run rootston from a terminal or VT with: ./build/rootston/rootston -Run windows on the compositor with the display variable set: - -```bash -# run gtk apps like this -gnome-calculator --display=wayland-0 - -# run QT apps like this -qgit -platform wayland - -# run X11 apps like this -DISPLAY=:1 firefox -``` +Now you can run windows in the compositor from the command line or by +configuring bindings in your +[`rootston.ini`](https://github.com/swaywm/wlroots/blob/master/rootston/rootston.ini.example) +file.