From c2ddb6eca6edbfc114c1ced0427a6297614a3453 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 18 Jul 2025 14:38:05 -0700 Subject: [PATCH] apprt/gtk-ng: scroll --- src/apprt/gtk-ng/class/surface.zig | 80 ++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index d690cab66..54fcd0515 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -88,6 +88,9 @@ pub const Surface = extern struct { im_buf: [128]u8 = undefined, im_len: u7 = 0, + /// True when we have a precision scroll in progress + precision_scroll: bool = false, + pub var offset: c_int = 0; }; @@ -290,6 +293,7 @@ pub const Surface = extern struct { // Initialize some private fields so they aren't undefined priv.rt_surface = .{ .surface = self }; + priv.precision_scroll = false; priv.cursor_pos = .{ .x = 0, .y = 0 }; priv.size = .{ // Funky numbers on purpose so they stand out if for some reason @@ -388,6 +392,33 @@ pub const Surface = extern struct { .{}, ); + // Scroll + const ec_scroll = gtk.EventControllerScroll.new(.flags_both_axes); + errdefer ec_scroll.unref(); + self_widget.addController(ec_scroll.as(gtk.EventController)); + errdefer self_widget.removeController(ec_scroll.as(gtk.EventController)); + _ = gtk.EventControllerScroll.signals.scroll.connect( + ec_scroll, + *Self, + ecMouseScroll, + self, + .{}, + ); + _ = gtk.EventControllerScroll.signals.scroll_begin.connect( + ec_scroll, + *Self, + ecMouseScrollPrecisionBegin, + self, + .{}, + ); + _ = gtk.EventControllerScroll.signals.scroll_end.connect( + ec_scroll, + *Self, + ecMouseScrollPrecisionEnd, + self, + .{}, + ); + // Setup our input method state const im_context = gtk.IMMulticontext.new(); priv.im_context = im_context; @@ -708,6 +739,55 @@ pub const Surface = extern struct { } } + fn ecMouseScrollPrecisionBegin( + _: *gtk.EventControllerScroll, + self: *Self, + ) callconv(.c) void { + self.private().precision_scroll = true; + } + + fn ecMouseScrollPrecisionEnd( + _: *gtk.EventControllerScroll, + self: *Self, + ) callconv(.c) void { + self.private().precision_scroll = false; + } + + fn ecMouseScroll( + _: *gtk.EventControllerScroll, + x: f64, + y: f64, + self: *Self, + ) callconv(.c) c_int { + const priv = self.private(); + if (priv.core_surface) |surface| { + // Multiply precision scrolls by 10 to get a better response from + // touchpad scrolling + const multiplier: f64 = if (priv.precision_scroll) 10.0 else 1.0; + const scroll_mods: input.ScrollMods = .{ + .precision = priv.precision_scroll, + }; + + const scaled = self.scaledCoordinates(x, y); + surface.scrollCallback( + // We invert because we apply natural scrolling to the values. + // This behavior has existed for years without Linux users complaining + // but I suspect we'll have to make this configurable in the future + // or read a system setting. + scaled.x * -1 * multiplier, + scaled.y * -1 * multiplier, + scroll_mods, + ) catch |err| { + log.warn("error in scroll callback err={}", .{err}); + return 0; + }; + + return 1; + } + + return 0; + } + fn imPreeditStart( _: *gtk.IMMulticontext, self: *Self,