diff --git a/include/key-state.h b/include/key-state.h index 1e7e5410..cfe9df9c 100644 --- a/include/key-state.h +++ b/include/key-state.h @@ -6,5 +6,6 @@ void key_state_set_pressed(uint32_t keycode, bool ispressed); void key_state_store_pressed_keys_as_bound(void); bool key_state_corresponding_press_event_was_bound(uint32_t keycode); void key_state_bound_key_remove(uint32_t keycode); +int key_state_nr_keys(void); #endif /* __LABWC_KEY_STATE_H */ diff --git a/src/key-state.c b/src/key-state.c index bc4844f6..0c53cf9f 100644 --- a/src/key-state.c +++ b/src/key-state.c @@ -68,3 +68,9 @@ key_state_bound_key_remove(uint32_t keycode) { remove_key(&bound, keycode); } + +int +key_state_nr_keys(void) +{ + return bound.nr_keys; +} diff --git a/src/keyboard.c b/src/keyboard.c index bdcb6c31..ae68b8f5 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7,6 +7,8 @@ #include "labwc.h" #include "workspaces.h" +static bool should_cancel_cycling_on_next_key_release; + static void change_vt(struct server *server, unsigned int vt) { @@ -33,6 +35,17 @@ keyboard_any_modifiers_pressed(struct wlr_keyboard *keyboard) return false; } +static void +end_cycling(struct server *server) +{ + desktop_focus_and_activate_view(&server->seat, server->osd_state.cycle_view); + desktop_move_to_front(server->osd_state.cycle_view); + + /* osd_finish() additionally resets cycle_view to NULL */ + osd_finish(server); + should_cancel_cycling_on_next_key_release = false; +} + static void keyboard_modifiers_notify(struct wl_listener *listener, void *data) { @@ -46,12 +59,11 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data) if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED && !keyboard_any_modifiers_pressed(keyboard)) { if (server->osd_state.cycle_view) { - /* end cycle */ - desktop_focus_and_activate_view(&server->seat, - server->osd_state.cycle_view); - desktop_move_to_front(server->osd_state.cycle_view); - /* osd_finish() additionally resets cycle_view to NULL */ - osd_finish(server); + if (key_state_nr_keys()) { + should_cancel_cycling_on_next_key_release = true; + } else { + end_cycling(server); + } } if (seat->workspace_osd_shown_by_modifier) { workspaces_osd_hide(seat); @@ -112,6 +124,21 @@ handle_compositor_keybindings(struct wl_listener *listener, key_state_set_pressed(keycode, event->state == WL_KEYBOARD_KEY_STATE_PRESSED); + /* + * If a user lets go of the modifier (e.g. alt) before the 'normal' key + * (e.g. tab) when window-cycling, we do not end the cycling until both + * keys have been released. If we end the window-cycling on release of + * the modifier only, some XWayland clients such as hexchat realise that + * tab is pressed (even though we did not forward the event) and because + * we absorb the equivalent release event it gets stuck on repeat. + */ + if (should_cancel_cycling_on_next_key_release + && event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { + end_cycling(server); + handled = true; + goto out; + } + /* * If a press event was handled by a compositor binding, then do not * forward the corresponding release event to clients