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.
This commit is contained in:
lkn 2026-06-06 20:36:36 +02:00
parent 6a12e3ea5a
commit d17dc0d6ee
3 changed files with 37 additions and 2 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.