From d17dc0d6ee4d10317a0a3dc0efec93f2719a5cbf Mon Sep 17 00:00:00 2001 From: lkn Date: Sat, 6 Jun 2026 20:36:36 +0200 Subject: [PATCH] wayland: fix window resize and populate button modifier state Three related fixes for the Wayland backend: wl_handlers.c: populate u.button.state with keyboard modifiers Button events were built with state=0 after memset, so all modifier- dependent logic in window.c (resizebarMouseDown, frameMouseDown, titlebarMouseDown) received no modifier information. Read the current depressed modifier mask from the seat keyboard and copy it directly -- wlroots WLR_MODIFIER_* bits match the WM_MOD_* layout exactly. wl_framebuf.c: fix frame_buf_hit to resolve child sub-windows frame_buf_at() uses wlr_scene_node_at() which skips frame_buf children whose scene_buf has no committed buffer (resizebar, titlebar pixels are composited into the parent frame buffer). The hit always resolved to the top-level frame, so events were dispatched to frameMouseDown instead of resizebarMouseDown, and resize never started. After frame_buf_at returns a top-level frame, do a coordinate-based child search and return the smallest (most specific) child that contains the pointer -- the same strategy frame_buf_button_at uses for buttons. wl_events.c: fix wl_coords_translate to return frame-relative coords The stub was a pass-through returning root-relative coordinates unchanged. wMouseResizeWindow calls coords_translate(root, frame->core->window, ...) to get frame-relative click coordinates for getResizeDirection(). Look up the dst window in the frame_buf list and subtract its absolute position. --- src/backend/wayland/wl_events.c | 15 +++++++++++++-- src/backend/wayland/wl_framebuf.c | 20 ++++++++++++++++++++ src/backend/wayland/wl_handlers.c | 4 ++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/backend/wayland/wl_events.c b/src/backend/wayland/wl_events.c index 35beb37..ca755aa 100644 --- a/src/backend/wayland/wl_events.c +++ b/src/backend/wayland/wl_events.c @@ -31,7 +31,18 @@ int wl_coords_translate(WNativeWindow src, WNativeWindow dst, int src_x, int src_y, int *dst_x, int *dst_y) { - (void)src; (void)dst; - *dst_x = src_x; *dst_y = src_y; + (void)src; + /* Convert src-window-relative (or root-relative) coordinates into + * dst-window-relative coordinates by subtracting dst's absolute position. + * Used by wMouseResizeWindow to get frame-relative click coords for + * getResizeDirection(). */ + struct wl_frame_buf *fb = frame_buf_find(dst); + if (fb) { + *dst_x = src_x - fb->x; + *dst_y = src_y - fb->y; + } else { + *dst_x = src_x; + *dst_y = src_y; + } return 0; } diff --git a/src/backend/wayland/wl_framebuf.c b/src/backend/wayland/wl_framebuf.c index e97bf46..6ee1655 100644 --- a/src/backend/wayland/wl_framebuf.c +++ b/src/backend/wayland/wl_framebuf.c @@ -300,6 +300,26 @@ frame_buf_hit(int px, int py) struct wl_frame_buf *fb = frame_buf_at(px, py); if (!fb) fb = frame_buf_button_at(px, py); + + /* If we landed on a top-level frame (parent_id==0), check whether a + * child sub-window (resizebar, titlebar) actually contains (px,py). + * Child frame_bufs may not have a committed scene_buf buffer so + * wlr_scene_node_at skips them; we find them by coordinate instead. + * Return the smallest (most specific) child that encloses the point. */ + if (fb && fb->parent_id == 0) { + struct wl_frame_buf *child, *best_child = NULL; + wl_list_for_each(child, &wl_state.frame_list, link) { + if (child->parent_id != fb->id) continue; + if (px < child->x || px >= child->x + child->width) continue; + if (py < child->y || py >= child->y + child->height) continue; + if (!best_child || + (child->width * child->height) < (best_child->width * best_child->height)) + best_child = child; + } + if (best_child) + fb = best_child; + } + wl_dump_hit_debug(px, py, fb); return fb; } diff --git a/src/backend/wayland/wl_handlers.c b/src/backend/wayland/wl_handlers.c index 73156af..923d750 100644 --- a/src/backend/wayland/wl_handlers.c +++ b/src/backend/wayland/wl_handlers.c @@ -272,6 +272,10 @@ 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; + } /* 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.