From 0b12c7ad71f9a85d742777be976ee1dcef356da1 Mon Sep 17 00:00:00 2001 From: lkn Date: Sat, 6 Jun 2026 20:47:16 +0200 Subject: [PATCH] wayland: track real keyboard modifiers in wl_state.current_mods The seat keyboard may be the XWayland virtual keyboard when a client has focus, which carries no modifier state. Reading seat->keyboard_state.keyboard->modifiers.depressed for button events then yields 0 even when the user holds Alt, so frameMouseDown's MOD_MASK check always fails and Alt+drag never starts. Add current_mods to wl_compositor_state. Update it from the real keyboard in handle_keyboard_modifiers, which fires on every modifier change from the physical device regardless of seat focus. Use wl_state.current_mods in handle_pointer_button to populate u.button.state and to gate the client-forwarding suppression. --- src/backend/wayland/wl_handlers.c | 9 ++------- src/backend/wayland/wl_keyboard.c | 4 ++++ src/backend/wayland/wl_types.h | 4 ++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/backend/wayland/wl_handlers.c b/src/backend/wayland/wl_handlers.c index c95e088..d69d210 100644 --- a/src/backend/wayland/wl_handlers.c +++ b/src/backend/wayland/wl_handlers.c @@ -272,10 +272,7 @@ handle_pointer_button(struct wl_listener *listener, void *data) case 0x112: wev.u.button.button = 2; break; default: wev.u.button.button = (ev->button - 0x110) + 1; break; } - { - struct wlr_keyboard *kb = wl_state.seat ? wl_state.seat->keyboard_state.keyboard : NULL; - wev.u.button.state = kb ? kb->modifiers.depressed : 0; - } + wev.u.button.state = wl_state.current_mods; /* For WINGs views, resolve the child widget at click coordinates. * Two cases: * 1. fb->id >= 0x20000000 — fb IS a WINGs view frame_buf, use directly. @@ -334,9 +331,7 @@ handle_pointer_button(struct wl_listener *listener, void *data) * will handle the event (move or resize), and the app must not see it. */ Bool forward_to_client = True; if (ev->state == WLR_BUTTON_PRESSED && wl_state.seat) { - struct wlr_keyboard *_kb = wl_state.seat->keyboard_state.keyboard; - unsigned int _mods = _kb ? _kb->modifiers.depressed : 0; - if (_mods & wPreferences.modifier_mask) { + if (wl_state.current_mods & wPreferences.modifier_mask) { double _sx, _sy; struct wl_toplevel_view *_tv = NULL; struct wlr_surface *_surf = view_surface_at( diff --git a/src/backend/wayland/wl_keyboard.c b/src/backend/wayland/wl_keyboard.c index 6f2b056..aa882fb 100644 --- a/src/backend/wayland/wl_keyboard.c +++ b/src/backend/wayland/wl_keyboard.c @@ -105,4 +105,8 @@ handle_keyboard_modifiers(struct wl_listener *listener, void *data) struct wlr_keyboard *kb = wl_state.seat->keyboard_state.keyboard; if (!kb) return; wlr_seat_keyboard_notify_modifiers(wl_state.seat, &kb->modifiers); + /* Cache the real keyboard's depressed modifiers so pointer button + * handlers can read them regardless of which keyboard the seat + * currently has focused (e.g. XWayland virtual keyboard). */ + wl_state.current_mods = kb->modifiers.depressed; } diff --git a/src/backend/wayland/wl_types.h b/src/backend/wayland/wl_types.h index f8ea1ea..f670dd1 100644 --- a/src/backend/wayland/wl_types.h +++ b/src/backend/wayland/wl_types.h @@ -399,6 +399,10 @@ struct wl_compositor_state { /* Keyboard grab: when true, key events are queued for WMMaskEvent but not * forwarded to Wayland clients (used by Alt-Tab cycling). */ bool keyboard_grabbed; + /* Current depressed modifier mask from the real keyboard, updated by + * handle_keyboard_modifiers. Used by handle_pointer_button to populate + * u.button.state so frameMouseDown can detect Alt/Super+drag. */ + unsigned int current_mods; }; extern struct wl_compositor_state wl_state;