From 790fad4074d98a734caf1c60b0aeef8ac2cb9bdd Mon Sep 17 00:00:00 2001 From: Squibid Date: Sat, 7 Mar 2026 14:49:27 -0500 Subject: [PATCH] refine the pointer motion function, this is now closer to what other compositors do --- src/Cursor.zig | 145 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 112 insertions(+), 33 deletions(-) diff --git a/src/Cursor.zig b/src/Cursor.zig index 38a5843..f231777 100644 --- a/src/Cursor.zig +++ b/src/Cursor.zig @@ -32,10 +32,11 @@ mode: enum { normal, drag } = .normal, drag: ?struct { event_code: u32, start: struct { x: c_int, y: c_int }, - view: ?struct { view: *View, dims: struct { width: c_int, height: c_int }, offset: struct { - x: c_int, - y: c_int, - } }, + view: ?struct { + view: *View, + dims: struct { width: c_int, height: c_int }, + offset: struct { x: c_int, y: c_int }, + }, }, pub fn init(self: *Cursor) void { @@ -73,8 +74,21 @@ pub fn deinit(self: *Cursor) void { self.x_cursor_manager.destroy(); } -pub fn processCursorMotion(self: *Cursor, time_msec: u32) void { - var passthrough = true; +pub fn processCursorMotion( + self: *Cursor, + time_msec: u32, + device: *wlr.InputDevice, + delta_x: f64, + delta_y: f64, + unaccel_dx: f64, + unaccel_dy: f64, +) void { + // these will be used later when the relative pointer manager is setup + _ = unaccel_dx; + _ = unaccel_dy; + + // process the cursor motion + self.wlr_cursor.move(device, delta_x, delta_y); if (self.mode == .drag) { const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers(); @@ -84,29 +98,44 @@ pub fn processCursorMotion(self: *Cursor, time_msec: u32) void { // Proceed if mousemap for current mouse and modifier state's exist if (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(self.drag.?.event_code)))) |map| { if (map.options.lua_drag_ref_idx > 0) { - passthrough = map.callback(.drag, .{ .{ .x = @as(c_int, @intFromFloat(self.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(self.wlr_cursor.y)) }, .{ .start = self.drag.?.start, .view = if (self.drag.?.view != null) .{ .id = self.drag.?.view.?.view.id, .dims = self.drag.?.view.?.dims, .offset = self.drag.?.view.?.offset } else null } }); + const passthrough = map.callback(.drag, .{ + .{ + .x = @as(c_int, @intFromFloat(self.wlr_cursor.x)), + .y = @as(c_int, @intFromFloat(self.wlr_cursor.y)), + }, + .{ + .start = self.drag.?.start, + .view = if (self.drag.?.view != null) .{ + .id = self.drag.?.view.?.view.id, + .dims = self.drag.?.view.?.dims, + .offset = self.drag.?.view.?.offset, + } else null, + } + }); + if (!passthrough) return; } } } - if (passthrough) { - const output = server.seat.focused_output; - // Exit the switch if no focused output exists - std.debug.assert(output != null); + const output = server.seat.focused_output; + // Exit the switch if no focused output exists + std.debug.assert(output != null); - const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y); - if (surfaceAtResult) |surface| { - if (surface.scene_node_data.* == .view) { - server.events.exec("ViewPointerMotion", .{ surface.scene_node_data.view.id, @as(c_int, @intFromFloat(self.wlr_cursor.x)), @as(c_int, @intFromFloat(self.wlr_cursor.y)) }); - } - - server.seat.wlr_seat.pointerNotifyEnter(surfaceAtResult.?.surface, surfaceAtResult.?.sx, surfaceAtResult.?.sy); - server.seat.wlr_seat.pointerNotifyMotion(time_msec, surfaceAtResult.?.sx, surfaceAtResult.?.sy); - } else { - // This may not be necessary, remove if no bugs - server.seat.wlr_seat.pointerClearFocus(); - self.wlr_cursor.setXcursor(self.x_cursor_manager, "default"); + const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y); + if (surfaceAtResult) |surface| { + if (surface.scene_node_data.* == .view) { + server.events.exec("ViewPointerMotion", .{ + surface.scene_node_data.view.id, + @as(c_int, @intFromFloat(self.wlr_cursor.x)), + @as(c_int, @intFromFloat(self.wlr_cursor.y)), + }); } + + server.seat.wlr_seat.pointerNotifyEnter(surfaceAtResult.?.surface, surfaceAtResult.?.sx, surfaceAtResult.?.sy); + server.seat.wlr_seat.pointerNotifyMotion(time_msec, surfaceAtResult.?.sx, surfaceAtResult.?.sy); + } else { + server.seat.wlr_seat.pointerClearFocus(); + self.wlr_cursor.setXcursor(self.x_cursor_manager, "default"); } } @@ -115,16 +144,47 @@ fn handleMotion( _: *wl.Listener(*wlr.Pointer.event.Motion), event: *wlr.Pointer.event.Motion, ) void { - server.cursor.wlr_cursor.move(event.device, event.delta_x, event.delta_y); - server.cursor.processCursorMotion(event.time_msec); + server.cursor.processCursorMotion( + event.time_msec, + event.device, + event.delta_x, + event.delta_y, + event.unaccel_dx, + event.unaccel_dy, + ); } fn handleMotionAbsolute( - _: *wl.Listener(*wlr.Pointer.event.MotionAbsolute), + listener: *wl.Listener(*wlr.Pointer.event.MotionAbsolute), event: *wlr.Pointer.event.MotionAbsolute, ) void { - server.cursor.wlr_cursor.warpAbsolute(event.device, event.x, event.y); - server.cursor.processCursorMotion(event.time_msec); + const self: *Cursor = @fieldParentPtr("motion_absolute", listener); + // comment from dwl: + // This event is forwarded by the cursor when a pointer emits an _absolute_ + // motion event, from 0..1 on each axis. This happens, for example, when + // wlroots is running under a Wayland window rather than KMS+DRM, and you + // move the mouse over the window. You could enter the window from any edge, + // so we have to warp the mouse there. Also, some hardware emits these events. + + // move the cursor when it doesn't order its events + if (event.time_msec == 0) { + self.wlr_cursor.warpAbsolute(event.device, event.x, event.y); + } + + var layout_x: f64 = 0; + var layout_y: f64 = 0; + self.wlr_cursor.absoluteToLayoutCoords(event.device, event.x, event.y, &layout_x, &layout_y); + + const delta_x = layout_x - self.wlr_cursor.x; + const delta_y = layout_y - self.wlr_cursor.y; + server.cursor.processCursorMotion( + event.time_msec, + event.device, + delta_x, + delta_y, + delta_x, // absolute motions do not decelerate + delta_y, + ); } fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.Pointer.event.Button) void { @@ -134,15 +194,28 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P .pressed => { cursor.mode = .drag; - cursor.drag = .{ .event_code = event.button, .start = .{ .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)) }, .view = null }; + cursor.drag = .{ + .event_code = event.button, + .start = .{ + .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), + .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)), + }, + .view = null, + }; // Keep track of where the drag started if (server.seat.focused_surface) |fs| { if (fs == .view) { cursor.drag.?.view = .{ .view = fs.view, - .dims = .{ .width = fs.view.xdg_toplevel.base.geometry.width, .height = fs.view.xdg_toplevel.base.geometry.height }, - .offset = .{ .x = cursor.drag.?.start.x - fs.view.scene_tree.node.x, .y = cursor.drag.?.start.y - fs.view.scene_tree.node.y }, + .dims = .{ + .width = fs.view.xdg_toplevel.base.geometry.width, + .height = fs.view.xdg_toplevel.base.geometry.height, + }, + .offset = .{ + .x = cursor.drag.?.start.x - fs.view.scene_tree.node.x, + .y = cursor.drag.?.start.y - fs.view.scene_tree.node.y, + }, }; } } @@ -172,14 +245,20 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P // Only make callback if a callback function exists if (map.options.lua_press_ref_idx > 0) { passthrough = map.callback(.press, .{ - .{ .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)) }, + .{ + .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), + .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)), + }, }); } }, .released => { if (map.options.lua_press_ref_idx > 0) { passthrough = map.callback(.release, .{ - .{ .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)) }, + .{ + .x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)), + .y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)), + }, }); } },