config: add gtk-horizontal-tab-scroll option (#12659)

I've implemented a GTK toggle (gtk-horizontal-tab-scroll) for the
2-finger tab swiping introduced in #10575.

This resolves the issue presented in #11566. Simply put, this allows
users to decide whether or not they want to use horizontal tab scrolling
or just have the events passed through. Passing through the horizontal
scroll events allows programs like Neovim to use them for horizontal
scrolling.

This PR was largely generated by Claude Code and fully reviewed/refined
by me.
This commit is contained in:
Jeffrey C. Ollie
2026-06-27 01:58:13 -05:00
committed by GitHub
2 changed files with 49 additions and 22 deletions

View File

@@ -3030,37 +3030,56 @@ pub const Surface = extern struct {
) callconv(.c) c_int {
const priv: *Private = self.private();
switch (ec.getUnit()) {
.surface => {},
.wheel => return @intFromBool(false),
else => return @intFromBool(false),
}
// Check if horizontal tab scrolling is enabled and this is a
// touchpad surface scroll. If not, forward to the terminal.
const tab_scroll_enabled = if (priv.config) |config|
config.get().@"gtk-horizontal-tab-scroll"
else
true;
priv.pending_horizontal_scroll += x;
const is_surface_scroll = ec.getUnit() == .surface;
if (tab_scroll_enabled and is_surface_scroll) {
priv.pending_horizontal_scroll += x;
if (@abs(priv.pending_horizontal_scroll) < 120) {
if (priv.pending_horizontal_scroll_reset) |v| {
_ = glib.Source.remove(v);
priv.pending_horizontal_scroll_reset = null;
}
priv.pending_horizontal_scroll_reset = glib.timeoutAdd(500, ecMouseScrollHorizontalReset, self);
return @intFromBool(true);
}
_ = self.as(gtk.Widget).activateAction(
if (priv.pending_horizontal_scroll < 0.0)
"tab.next-page"
else
"tab.previous-page",
null,
);
if (@abs(priv.pending_horizontal_scroll) < 120) {
if (priv.pending_horizontal_scroll_reset) |v| {
_ = glib.Source.remove(v);
priv.pending_horizontal_scroll_reset = null;
}
priv.pending_horizontal_scroll_reset = glib.timeoutAdd(500, ecMouseScrollHorizontalReset, self);
priv.pending_horizontal_scroll = 0.0;
return @intFromBool(true);
}
_ = self.as(gtk.Widget).activateAction(
if (priv.pending_horizontal_scroll < 0.0)
"tab.next-page"
else
"tab.previous-page",
null,
);
if (priv.pending_horizontal_scroll_reset) |v| {
_ = glib.Source.remove(v);
priv.pending_horizontal_scroll_reset = null;
}
priv.pending_horizontal_scroll = 0.0;
// Forward horizontal scroll to the terminal (e.g. for neovim).
const surface = priv.core_surface orelse return @intFromBool(false);
const scaled = self.scaledCoordinates(x, 0);
surface.scrollCallback(
scaled.x * -1,
0,
.{},
) catch |err| {
log.warn("error in scroll callback err={}", .{err});
return @intFromBool(false);
};
return @intFromBool(true);
}

View File

@@ -3657,6 +3657,14 @@ else
/// which is the old style.
@"gtk-wide-tabs": bool = true,
/// If `true` (default), then two-finger horizontal scrolling on a touchpad
/// will switch between tabs. Scrolling left goes to the next tab and
/// scrolling right goes to the previous tab. Set this to `false` to
/// disable this behavior.
///
/// Available since 1.4.0.
@"gtk-horizontal-tab-scroll": bool = true,
/// Custom CSS files to be loaded.
///
/// GTK CSS documentation can be found at the following links: