From 28cd50406730d9f50761c0898d3fcb90c6c11761 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Sun, 19 Oct 2025 22:15:37 -0400 Subject: [PATCH] desktop: work around client-side rounding issues at right/bottom pixel This also avoids a similar server-side rounding issue with some combinations of wlroots and libwayland versions. See: - https://gitlab.freedesktop.org/wayland/wayland/-/issues/555 - https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5159 Tested with qmpanel (similar to lxqt-panel) at 1x and 2x output scale. Does not help if scaling is done client-side, e.g. QT_SCALE_FACTOR=2. Fixes: #2379 Fixes: #3099 --- src/desktop.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/desktop.c b/src/desktop.c index bac6c065..2d883445 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -242,6 +242,39 @@ desktop_update_top_layer_visibility(struct server *server) } } +/* + * Work around rounding issues in some clients (notably Qt apps) where + * cursor coordinates in the rightmost or bottom pixel are incorrectly + * rounded up, putting them outside the surface bounds. The effect is + * especially noticeable in right/bottom desktop panels, since driving + * the cursor to the edge of the screen no longer works. + * + * Under X11, such rounding issues went unnoticed since cursor positions + * were always integers (i.e. whole pixel boundaries) anyway. Until more + * clients/toolkits are fractional-pixel clean, limit surface cursor + * coordinates to (w - 1, h - 1) as a workaround. + */ +static void +avoid_edge_rounding_issues(struct cursor_context *ctx) +{ + if (!ctx->surface) { + return; + } + + int w = ctx->surface->current.width; + int h = ctx->surface->current.height; + /* + * The cursor isn't expected to be outside the surface bounds + * here, but check (sx < w, sy < h) just in case. + */ + if (ctx->sx > w - 1 && ctx->sx < w) { + ctx->sx = w - 1; + } + if (ctx->sy > h - 1 && ctx->sy < h) { + ctx->sy = h - 1; + } +} + /* TODO: make this less big and scary */ struct cursor_context get_cursor_context(struct server *server) @@ -269,6 +302,8 @@ get_cursor_context(struct server *server) ret.node = node; ret.surface = lab_wlr_surface_from_node(node); + avoid_edge_rounding_issues(&ret); + #if HAVE_XWAYLAND /* TODO: attach LAB_NODE_UNMANAGED node-descriptor to unmanaged surfaces */ if (node->type == WLR_SCENE_NODE_BUFFER) {