Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
fix(scenefx): hit-test a dest-scaled surface in surface coordinates
scene_node_at_iterator handed point_accepts_input the raw node-local
LAYOUT offset. The system-wlroots surface callback checks the input
region at whatever coordinates it is given and does not transform them,
so for a buffer displayed at dst_size != natural size both the region
gate and the coordinates delivered to the client were off by exactly
the display ratio.
Windows re-render at the camera scale and rest at ratio 1, so nothing
visible ever came of it there. The desktop grid is the one surface that
RESTS scaled: its patch resolution quantizes to pow2 steps, so any
camera zoom off a step leaves it displaying at 0.5-1.42x. There a click
on a desktop item hit-tested displaced (reading as a background press —
which in overview exits it), and the press position the client received
disagreed with the correctly-scaled drag deltas by the ratio times the
surface position — thousands of px on a patch-sized surface, which is
the delta that kept flinging the user's desktop image off the canvas
(to y=-5161 on a live session displaying at 0.5).
Map the point into surface-local logical coordinates before the region
check, using the scene surface's current logical size against dst — a
no-op (factor 1) for every buffer displayed at its natural size.
Verified in a shadow session at display ratio 1.026: the region now
sits exactly under the drawn item, a press on it grabs (previously
exited overview), the delivered press position matches the drag-delta
space to the decimal, and drags track 1:1 at rest, across a camera
flight mid-grab, and at zoom 1.
Co-Authored-By: Claude Fable 5 <[email protected]>
scenefx/types/scene/wlr_scene.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/scenefx/types/scene/wlr_scene.c b/scenefx/types/scene/wlr_scene.c
index 15523cc..91b5259 100644
--- a/scenefx/types/scene/wlr_scene.c
+++ b/scenefx/types/scene/wlr_scene.c
@@ -2328,6 +2328,32 @@ static bool scene_node_at_iterator(struct wlr_scene_node *node,
if (node->type == WLR_SCENE_NODE_BUFFER) {
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
+ // A dest-scaled surface buffer occupies dst_width x dst_height in
+ // layout space while its input region (and the coordinates its
+ // client expects) live in SURFACE-LOCAL logical space. Map the
+ // node-local point between the two before the region check, or a
+ // buffer resting at a display ratio != 1 (the desktop grid's
+ // patch, whenever the camera zoom sits off the pow2 quantization)
+ // hit-tests and reports coordinates displaced by exactly that
+ // ratio — which is how a click on a desktop item read as
+ // background, and how the press position disagreed with the drag
+ // deltas hard enough to fling the item across the canvas.
+ // Buffers displayed at their natural size (every window at rest)
+ // scale by exactly 1 here and are untouched.
+ if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) {
+ struct wlr_scene_surface *scene_surface =
+ wlr_scene_surface_try_from_buffer(scene_buffer);
+ if (scene_surface != NULL && scene_surface->surface != NULL) {
+ int sw = scene_surface->surface->current.width;
+ int sh = scene_surface->surface->current.height;
+ if (sw > 0 && sh > 0 && (sw != scene_buffer->dst_width ||
+ sh != scene_buffer->dst_height)) {
+ rx = rx * sw / scene_buffer->dst_width;
+ ry = ry * sh / scene_buffer->dst_height;
+ }
+ }
+ }
+
if (scene_buffer->point_accepts_input &&
!scene_buffer->point_accepts_input(scene_buffer, &rx, &ry)) {
return false;