From a5188142ba5508e3e07a89116b6f3b17cec02814 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 29 Jul 2025 14:52:31 -0700 Subject: [PATCH] apprt/gtk-ng: move tab --- src/apprt/gtk-ng/class/application.zig | 27 ++++++++++++++++- src/apprt/gtk-ng/class/window.zig | 41 ++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/apprt/gtk-ng/class/application.zig b/src/apprt/gtk-ng/class/application.zig index 2efd6e211..138d2b56e 100644 --- a/src/apprt/gtk-ng/class/application.zig +++ b/src/apprt/gtk-ng/class/application.zig @@ -503,6 +503,8 @@ pub const Application = extern struct { .mouse_shape => Action.mouseShape(target, value), .mouse_visibility => Action.mouseVisibility(target, value), + .move_tab => return Action.moveTab(target, value), + .new_tab => return Action.newTab(target), .new_window => try Action.newWindow( @@ -537,7 +539,6 @@ pub const Application = extern struct { .toggle_fullscreen => Action.toggleFullscreen(target), // Unimplemented but todo on gtk-ng branch - .move_tab, .new_split, .resize_split, .equalize_splits, @@ -1301,6 +1302,30 @@ const Action = struct { } } + pub fn moveTab( + target: apprt.Target, + value: apprt.action.MoveTab, + ) bool { + switch (target) { + .app => return false, + .surface => |core| { + const surface = core.rt_surface.surface; + const window = ext.getAncestor( + Window, + surface.as(gtk.Widget), + ) orelse { + log.warn("surface is not in a window, ignoring new_tab", .{}); + return false; + }; + + return window.moveTab( + surface, + @intCast(value.amount), + ); + }, + } + } + pub fn newTab(target: apprt.Target) bool { switch (target) { .app => { diff --git a/src/apprt/gtk-ng/class/window.zig b/src/apprt/gtk-ng/class/window.zig index 8b5074968..8a1045fe7 100644 --- a/src/apprt/gtk-ng/class/window.zig +++ b/src/apprt/gtk-ng/class/window.zig @@ -407,6 +407,47 @@ pub const Window = extern struct { return true; } + /// Move the tab containing the given surface by the given amount. + /// Returns if this affected any tab positioning. + pub fn moveTab( + self: *Self, + surface: *Surface, + amount: isize, + ) bool { + const priv = self.private(); + const tab_view = priv.tab_view; + + // If we have one tab we never move. + const total = tab_view.getNPages(); + if (total == 1) return false; + + // Get the tab that contains the given surface. + const tab = ext.getAncestor( + Tab, + surface.as(gtk.Widget), + ) orelse return false; + + // Get the page position that contains the tab. + const page = tab_view.getPage(tab.as(gtk.Widget)); + const pos = tab_view.getPagePosition(page); + + // Move it + const desired_pos: c_int = desired: { + const initial: c_int = @intCast(pos + amount); + const max = total - 1; + break :desired if (initial < 0) + max + initial + 1 + else if (initial > max) + initial - max - 1 + else + initial; + }; + assert(desired_pos >= 0); + assert(desired_pos < total); + + return tab_view.reorderPage(page, desired_pos) != 0; + } + /// Updates various appearance properties. This should always be safe /// to call multiple times. This should be called whenever a change /// happens that might affect how the window appears (config change,