refine the pointer motion function, this is now closer to what other

compositors do
This commit is contained in:
Squibid 2026-03-07 14:49:27 -05:00
parent 94e8388e7c
commit 790fad4074
Signed by: squibid
GPG key ID: BECE5684D3C4005D

View file

@ -32,10 +32,11 @@ mode: enum { normal, drag } = .normal,
drag: ?struct { drag: ?struct {
event_code: u32, event_code: u32,
start: struct { x: c_int, y: c_int }, start: struct { x: c_int, y: c_int },
view: ?struct { view: *View, dims: struct { width: c_int, height: c_int }, offset: struct { view: ?struct {
x: c_int, view: *View,
y: c_int, dims: struct { width: c_int, height: c_int },
} }, offset: struct { x: c_int, y: c_int },
},
}, },
pub fn init(self: *Cursor) void { pub fn init(self: *Cursor) void {
@ -73,8 +74,21 @@ pub fn deinit(self: *Cursor) void {
self.x_cursor_manager.destroy(); self.x_cursor_manager.destroy();
} }
pub fn processCursorMotion(self: *Cursor, time_msec: u32) void { pub fn processCursorMotion(
var passthrough = true; 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) { if (self.mode == .drag) {
const modifiers = server.seat.keyboard_group.wlr_group.keyboard.getModifiers(); 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 // 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 (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(self.drag.?.event_code)))) |map| {
if (map.options.lua_drag_ref_idx > 0) { 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;
const output = server.seat.focused_output; // Exit the switch if no focused output exists
// Exit the switch if no focused output exists std.debug.assert(output != null);
std.debug.assert(output != null);
const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y); const surfaceAtResult = output.?.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y);
if (surfaceAtResult) |surface| { if (surfaceAtResult) |surface| {
if (surface.scene_node_data.* == .view) { 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.events.exec("ViewPointerMotion", .{
} surface.scene_node_data.view.id,
@as(c_int, @intFromFloat(self.wlr_cursor.x)),
server.seat.wlr_seat.pointerNotifyEnter(surfaceAtResult.?.surface, surfaceAtResult.?.sx, surfaceAtResult.?.sy); @as(c_int, @intFromFloat(self.wlr_cursor.y)),
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");
} }
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), _: *wl.Listener(*wlr.Pointer.event.Motion),
event: *wlr.Pointer.event.Motion, event: *wlr.Pointer.event.Motion,
) void { ) void {
server.cursor.wlr_cursor.move(event.device, event.delta_x, event.delta_y); server.cursor.processCursorMotion(
server.cursor.processCursorMotion(event.time_msec); event.time_msec,
event.device,
event.delta_x,
event.delta_y,
event.unaccel_dx,
event.unaccel_dy,
);
} }
fn handleMotionAbsolute( fn handleMotionAbsolute(
_: *wl.Listener(*wlr.Pointer.event.MotionAbsolute), listener: *wl.Listener(*wlr.Pointer.event.MotionAbsolute),
event: *wlr.Pointer.event.MotionAbsolute, event: *wlr.Pointer.event.MotionAbsolute,
) void { ) void {
server.cursor.wlr_cursor.warpAbsolute(event.device, event.x, event.y); const self: *Cursor = @fieldParentPtr("motion_absolute", listener);
server.cursor.processCursorMotion(event.time_msec); // 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 { 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 => { .pressed => {
cursor.mode = .drag; 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 // Keep track of where the drag started
if (server.seat.focused_surface) |fs| { if (server.seat.focused_surface) |fs| {
if (fs == .view) { if (fs == .view) {
cursor.drag.?.view = .{ cursor.drag.?.view = .{
.view = fs.view, .view = fs.view,
.dims = .{ .width = fs.view.xdg_toplevel.base.geometry.width, .height = fs.view.xdg_toplevel.base.geometry.height }, .dims = .{
.offset = .{ .x = cursor.drag.?.start.x - fs.view.scene_tree.node.x, .y = cursor.drag.?.start.y - fs.view.scene_tree.node.y }, .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 // Only make callback if a callback function exists
if (map.options.lua_press_ref_idx > 0) { if (map.options.lua_press_ref_idx > 0) {
passthrough = map.callback(.press, .{ 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 => { .released => {
if (map.options.lua_press_ref_idx > 0) { if (map.options.lua_press_ref_idx > 0) {
passthrough = map.callback(.release, .{ 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)),
},
}); });
} }
}, },