From 60d71f46b48915f732d0fa5510c5f3e96117853b Mon Sep 17 00:00:00 2001 From: Window Maker Date: Sun, 24 May 2026 08:46:03 +0200 Subject: [PATCH] arch: usermenu key send through vtable; drop dead misc.c code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * usermenu.c notifyClient: replace XSendEvent KeyPress/KeyRelease synthesis with two wm_backend->client_send_key calls. * New vtable slot client_send_key(win, keycode, modifier_mask, press). X11: synthesize XKeyEvent and XSendEvent. Wayland: same but on wl_state.x_display (XWayland clients). Native Wayland clients deferred (would need zwp_virtual_keyboard_v1). * misc.c: keysymToString was dead code inside #if 0 — removed. After this change misc.c and usermenu.c carry zero direct Xlib calls. --- src/backend/backend.h | 14 ++++++++++++++ src/backend/wayland/wl_backend.c | 22 ++++++++++++++++++++++ src/backend/x11/x11_backend.c | 19 +++++++++++++++++++ src/misc.c | 25 ------------------------- src/usermenu.c | 27 +++++---------------------- 5 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/backend/backend.h b/src/backend/backend.h index 56286b8..27549bf 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -1794,6 +1794,20 @@ typedef struct WMBackend { int (*event_check_window)(WNativeWindow win, int event_type); int (*event_check_type)(int event_type, WMEvent *event_out); void (*client_send_event)(WNativeWindow win, void *event_data); + + /* + * Deliver a synthetic key press/release to a client window. Used by + * usermenu.c to translate menu entries into keystrokes for the + * focused client. + * + * X11: synthesize XKeyEvent and XSendEvent it to the window. + * Wayland: deliver via XSendEvent for XWayland clients (the X + * server backed by wlroots' xwayland surfaces still + * accepts synthetic events). Native Wayland clients are + * not yet handled (would need zwp_virtual_keyboard_v1). + */ + void (*client_send_key)(WNativeWindow win, unsigned int keycode, + unsigned int modifier_mask, int press); int (*window_exists)(WNativeWindow win); void (*window_get_colormap)(WNativeWindow win, unsigned long *colormap_out); WNativeWindow (*pointer_query_window)(WNativeWindow root); diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 72508e7..10d3fdc 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -8863,6 +8863,27 @@ static void wl_noop_event_flush_type(int t) { (void)t; } static int wl_noop_event_check_window(WNativeWindow win, int t) { (void)win; (void)t; return 0; } static int wl_noop_event_check_type(int t, WMEvent *e) { (void)t; (void)e; return 0; } static void wl_noop_client_send_event(WNativeWindow win, void *d) { (void)win; (void)d; } +static void wl_client_send_key(WNativeWindow win, unsigned int keycode, + unsigned int modifier_mask, int press) +{ + /* For XWayland clients, deliver via the X server (wl_state.x_display) + * the same way the X11 backend does. Native Wayland clients are not + * yet supported (would require zwp_virtual_keyboard_v1). */ + if (!wl_state.x_display) return; + XEvent ev; + memset(&ev, 0, sizeof(ev)); + ev.xkey.type = press ? KeyPress : KeyRelease; + ev.xkey.display = wl_state.x_display; + ev.xkey.window = (Window)win; + ev.xkey.root = DefaultRootWindow(wl_state.x_display); + ev.xkey.subwindow = None; + ev.xkey.same_screen = True; + ev.xkey.time = CurrentTime; + ev.xkey.keycode = keycode; + ev.xkey.state = modifier_mask; + XSendEvent(wl_state.x_display, (Window)win, press ? False : True, + press ? KeyPressMask : KeyReleaseMask, &ev); +} static int wl_noop_window_exists(WNativeWindow win) { (void)win; return 1; } static void wl_noop_window_get_colormap(WNativeWindow win, unsigned long *c) { (void)win; (void)c; } static WNativeWindow wl_noop_pointer_query_window(WNativeWindow root) { (void)root; return WNATIVE_NONE; } @@ -9144,6 +9165,7 @@ const WMBackend wl_backend = { .event_check_window = wl_noop_event_check_window, .event_check_type = wl_noop_event_check_type, .client_send_event = wl_noop_client_send_event, + .client_send_key = wl_client_send_key, .window_exists = wl_noop_window_exists, .window_get_colormap = wl_noop_window_get_colormap, .pointer_query_window = wl_noop_pointer_query_window, diff --git a/src/backend/x11/x11_backend.c b/src/backend/x11/x11_backend.c index 76688d3..e729b26 100644 --- a/src/backend/x11/x11_backend.c +++ b/src/backend/x11/x11_backend.c @@ -3540,6 +3540,24 @@ static void x11_client_send_event(WNativeWindow win, void *event_data) { XSendEvent(dpy, (Window)win, False, 0L, (XEvent *)event_data); } + +static void x11_client_send_key(WNativeWindow win, unsigned int keycode, + unsigned int modifier_mask, int press) +{ + XEvent ev; + memset(&ev, 0, sizeof(ev)); + ev.xkey.type = press ? KeyPress : KeyRelease; + ev.xkey.display = dpy; + ev.xkey.window = (Window)win; + ev.xkey.root = DefaultRootWindow(dpy); + ev.xkey.subwindow = None; + ev.xkey.same_screen = True; + ev.xkey.time = CurrentTime; + ev.xkey.keycode = keycode; + ev.xkey.state = modifier_mask; + XSendEvent(dpy, (Window)win, press ? False : True, + press ? KeyPressMask : KeyReleaseMask, &ev); +} static int x11_window_exists(WNativeWindow win) { Window jr; int ji; unsigned int ju; @@ -4645,6 +4663,7 @@ const WMBackend x11_backend = { .event_check_window = x11_event_check_window, .event_check_type = x11_event_check_type, .client_send_event = x11_client_send_event, + .client_send_key = x11_client_send_key, .window_exists = x11_window_exists, .window_get_colormap = x11_window_get_colormap, .pointer_query_window = x11_pointer_query_window, diff --git a/src/misc.c b/src/misc.c index 0fab561..f693aad 100644 --- a/src/misc.c +++ b/src/misc.c @@ -617,31 +617,6 @@ void ParseWindowName(WMPropList *value, char **winstance, char **wclass, const c UnescapeWM_CLASS(name, winstance, wclass); } -#if 0 -static char *keysymToString(KeySym keysym, unsigned int state) -{ - XKeyEvent kev; - char *buf = wmalloc(20); - int count; - - kev.display = dpy; - kev.type = KeyPress; - kev.send_event = False; - kev.window = DefaultRootWindow(dpy); - kev.root = DefaultRootWindow(dpy); - kev.same_screen = True; - kev.subwindow = kev.root; - kev.serial = 0x12344321; - kev.time = CurrentTime; - kev.state = state; - kev.keycode = XKeysymToKeycode(dpy, keysym); - count = XLookupString(&kev, buf, 19, NULL, NULL); - buf[count] = 0; - - return buf; -} -#endif - char *GetShortcutString(const char *shortcut) { char *buffer = NULL; diff --git a/src/usermenu.c b/src/usermenu.c index 8723b63..37b95ec 100644 --- a/src/usermenu.c +++ b/src/usermenu.c @@ -86,10 +86,9 @@ typedef struct { static void notifyClient(WMenu *menu, WMenuEntry *entry) { - XEvent event; WUserMenuData *data = entry->clientdata; WScreen *scr = data->screen; - Window window; + WNativeWindow window; int i; (void) menu; @@ -97,26 +96,10 @@ static void notifyClient(WMenu *menu, WMenuEntry *entry) window = scr->focused_window->client_win; for (i = 0; i < data->key_no; i++) { - event.xkey.type = KeyPress; - event.xkey.display = dpy; - event.xkey.window = window; - event.xkey.root = DefaultRootWindow(dpy); - event.xkey.subwindow = (Window) None; - event.xkey.x = 0x0; - event.xkey.y = 0x0; - event.xkey.x_root = 0x0; - event.xkey.y_root = 0x0; - event.xkey.keycode = data->key[i].keycode; - event.xkey.state = data->key[i].modifier; - event.xkey.same_screen = True; - event.xkey.time = CurrentTime; - if (dpy) { - if (XSendEvent(dpy, window, False, KeyPressMask, &event)) { - event.xkey.type = KeyRelease; - event.xkey.time = CurrentTime; - XSendEvent(dpy, window, True, KeyReleaseMask, &event); - } - } + wm_backend->client_send_key(window, data->key[i].keycode, + data->key[i].modifier, 1 /*press*/); + wm_backend->client_send_key(window, data->key[i].keycode, + data->key[i].modifier, 0 /*release*/); } }