git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitfbee5816426328da6a8b7407c1e4e9d4b65bf8b4
parent91f9feed91
authorIsaac Freund <[email protected]>
date2026-04-13 14:18
Seat: support hold pointer gestures

 river/Cursor.zig | 24 ++++++++++++++++++++++++
 river/Seat.zig   | 16 ++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/river/Cursor.zig b/river/Cursor.zig
index 46aad3d..00f3cde 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -126,6 +126,9 @@ pinch_begin: wl.Listener(*wlr.Pointer.event.PinchBegin) = .init(queuePinchBegin)
 pinch_update: wl.Listener(*wlr.Pointer.event.PinchUpdate) = .init(queuePinchUpdate),
 pinch_end: wl.Listener(*wlr.Pointer.event.PinchEnd) = .init(queuePinchEnd),
 
+hold_begin: wl.Listener(*wlr.Pointer.event.HoldBegin) = .init(queueHoldBegin),
+hold_end: wl.Listener(*wlr.Pointer.event.HoldEnd) = .init(queueHoldEnd),
+
 touch_down: wl.Listener(*wlr.Touch.event.Down) = .init(handleTouchDown),
 touch_motion: wl.Listener(*wlr.Touch.event.Motion) = .init(handleTouchMotion),
 touch_up: wl.Listener(*wlr.Touch.event.Up) = .init(handleTouchUp),
@@ -171,6 +174,9 @@ pub fn init(cursor: *Cursor, seat: *Seat) !void {
     wlr_cursor.events.pinch_update.add(&cursor.pinch_update);
     wlr_cursor.events.pinch_end.add(&cursor.pinch_end);
 
+    wlr_cursor.events.hold_begin.add(&cursor.hold_begin);
+    wlr_cursor.events.hold_end.add(&cursor.hold_end);
+
     wlr_cursor.events.touch_down.add(&cursor.touch_down);
     wlr_cursor.events.touch_motion.add(&cursor.touch_motion);
     wlr_cursor.events.touch_up.add(&cursor.touch_up);
@@ -195,6 +201,8 @@ pub fn deinit(cursor: *Cursor) void {
     cursor.pinch_begin.link.remove();
     cursor.pinch_update.link.remove();
     cursor.pinch_end.link.remove();
+    cursor.hold_begin.link.remove();
+    cursor.hold_end.link.remove();
     cursor.request_set_cursor.link.remove();
 
     cursor.touch_down.link.remove();
@@ -925,3 +933,19 @@ fn queueSwipeEnd(listener: *wl.Listener(*wlr.Pointer.event.SwipeEnd), event: *wl
         .cancelled = event.cancelled,
     } }) catch {};
 }
+
+fn queueHoldBegin(listener: *wl.Listener(*wlr.Pointer.event.HoldBegin), event: *wlr.Pointer.event.HoldBegin) void {
+    const cursor: *Cursor = @fieldParentPtr("hold_begin", listener);
+    cursor.seat.queueEvent(.{ .pointer_hold_begin = .{
+        .time_msec = event.time_msec,
+        .fingers = event.fingers,
+    } }) catch {};
+}
+
+fn queueHoldEnd(listener: *wl.Listener(*wlr.Pointer.event.HoldEnd), event: *wlr.Pointer.event.HoldEnd) void {
+    const cursor: *Cursor = @fieldParentPtr("hold_end", listener);
+    cursor.seat.queueEvent(.{ .pointer_hold_end = .{
+        .time_msec = event.time_msec,
+        .cancelled = event.cancelled,
+    } }) catch {};
+}
diff --git a/river/Seat.zig b/river/Seat.zig
index 799a73e..49dcb00 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -68,6 +68,9 @@ pub const Event = union(enum) {
     pointer_pinch_update: PointerPinchUpdate,
     pointer_pinch_end: PointerPinchEnd,
 
+    pointer_hold_begin: PointerHoldBegin,
+    pointer_hold_end: PointerHoldEnd,
+
     pub const PointerMotionRelative = struct {
         mapping: wlr.Box,
         time_msec: u32,
@@ -127,6 +130,14 @@ pub const Event = union(enum) {
         time_msec: u32,
         cancelled: bool,
     };
+    pub const PointerHoldBegin = struct {
+        time_msec: u32,
+        fingers: u32,
+    };
+    pub const PointerHoldEnd = struct {
+        time_msec: u32,
+        cancelled: bool,
+    };
 };
 
 pub const Focus = union(enum) {
@@ -298,6 +309,8 @@ pub fn destroy(seat: *Seat) void {
             .pointer_pinch_begin,
             .pointer_pinch_update,
             .pointer_pinch_end,
+            .pointer_hold_begin,
+            .pointer_hold_end,
             => {},
         }
     }
@@ -374,6 +387,9 @@ pub fn processEvents(seat: *Seat) void {
             .pointer_pinch_begin => |ev| pg.sendPinchBegin(seat.wlr_seat, ev.time_msec, ev.fingers),
             .pointer_pinch_update => |ev| pg.sendPinchUpdate(seat.wlr_seat, ev.time_msec, ev.dx, ev.dy, ev.scale, ev.rotation),
             .pointer_pinch_end => |ev| pg.sendPinchEnd(seat.wlr_seat, ev.time_msec, ev.cancelled),
+
+            .pointer_hold_begin => |ev| pg.sendHoldBegin(seat.wlr_seat, ev.time_msec, ev.fingers),
+            .pointer_hold_end => |ev| pg.sendHoldEnd(seat.wlr_seat, ev.time_msec, ev.cancelled),
         }
     }
     assert(server.wm.state == .idle);