diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index d82087ff0..6bed56ec0 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -54,6 +54,9 @@ window: *adw.ApplicationWindow, /// The header bar for the window. headerbar: HeaderBar, +/// The tab bar for the window. +tab_bar: *adw.TabBar, + /// The tab overview for the window. This is possibly null since there is no /// taboverview without a AdwApplicationWindow (libadwaita >= 1.4.0). tab_overview: ?*adw.TabOverview, @@ -82,6 +85,7 @@ pub const DerivedConfig = struct { gtk_tabs_location: configpkg.Config.GtkTabsLocation, gtk_wide_tabs: bool, gtk_toolbar_style: configpkg.Config.GtkToolbarStyle, + window_show_tab_bar: configpkg.Config.WindowShowTabBar, quick_terminal_position: configpkg.Config.QuickTerminalPosition, quick_terminal_size: configpkg.Config.QuickTerminalSize, @@ -101,6 +105,7 @@ pub const DerivedConfig = struct { .gtk_tabs_location = config.@"gtk-tabs-location", .gtk_wide_tabs = config.@"gtk-wide-tabs", .gtk_toolbar_style = config.@"gtk-toolbar-style", + .window_show_tab_bar = config.@"window-show-tab-bar", .quick_terminal_position = config.@"quick-terminal-position", .quick_terminal_size = config.@"quick-terminal-size", @@ -135,6 +140,7 @@ pub fn init(self: *Window, app: *App) !void { .config = DerivedConfig.init(&app.config), .window = undefined, .headerbar = undefined, + .tab_bar = undefined, .tab_overview = null, .notebook = undefined, .titlebar_menu = undefined, @@ -216,8 +222,9 @@ pub fn init(self: *Window, app: *App) !void { // If we're using an AdwWindow then we can support the tab overview. if (self.tab_overview) |tab_overview| { if (!adw_version.supportsTabOverview()) unreachable; - const btn = switch (self.config.gtk_tabs_location) { - .top, .bottom => btn: { + + const btn = switch (self.config.window_show_tab_bar) { + .always, .auto => btn: { const btn = gtk.ToggleButton.new(); btn.as(gtk.Widget).setTooltipText(i18n._("View Open Tabs")); btn.as(gtk.Button).setIconName("view-grid-symbolic"); @@ -229,8 +236,7 @@ pub fn init(self: *Window, app: *App) !void { ); break :btn btn.as(gtk.Widget); }, - - .hidden => btn: { + .never => btn: { const btn = adw.TabButton.new(); btn.setView(self.notebook.tab_view); btn.as(gtk.Actionable).setActionName("overview.open"); @@ -376,21 +382,16 @@ pub fn init(self: *Window, app: *App) !void { // Our actions for the menu initActions(self); + self.tab_bar = adw.TabBar.new(); + self.tab_bar.setView(self.notebook.tab_view); + if (adw_version.supportsToolbarView()) { const toolbar_view = adw.ToolbarView.new(); toolbar_view.addTopBar(self.headerbar.asWidget()); - if (self.config.gtk_tabs_location != .hidden) { - const tab_bar = adw.TabBar.new(); - tab_bar.setView(self.notebook.tab_view); - - if (!self.config.gtk_wide_tabs) tab_bar.setExpandTabs(0); - - switch (self.config.gtk_tabs_location) { - .top => toolbar_view.addTopBar(tab_bar.as(gtk.Widget)), - .bottom => toolbar_view.addBottomBar(tab_bar.as(gtk.Widget)), - .hidden => unreachable, - } + switch (self.config.gtk_tabs_location) { + .top => toolbar_view.addTopBar(self.tab_bar.as(gtk.Widget)), + .bottom => toolbar_view.addBottomBar(self.tab_bar.as(gtk.Widget)), } toolbar_view.setContent(box.as(gtk.Widget)); @@ -405,23 +406,18 @@ pub fn init(self: *Window, app: *App) !void { // Set our application window content. self.tab_overview.?.setChild(toolbar_view.as(gtk.Widget)); self.window.setContent(self.tab_overview.?.as(gtk.Widget)); - } else tab_bar: { - if (self.config.gtk_tabs_location == .hidden) break :tab_bar; + } else { // In earlier adwaita versions, we need to add the tabbar manually since we do not use // an AdwToolbarView. - const tab_bar = adw.TabBar.new(); - tab_bar.as(gtk.Widget).addCssClass("inline"); + self.tab_bar.as(gtk.Widget).addCssClass("inline"); + switch (self.config.gtk_tabs_location) { .top => box.insertChildAfter( - tab_bar.as(gtk.Widget), + self.tab_bar.as(gtk.Widget), self.headerbar.asWidget(), ), - .bottom => box.append(tab_bar.as(gtk.Widget)), - .hidden => unreachable, + .bottom => box.append(self.tab_bar.as(gtk.Widget)), } - tab_bar.setView(self.notebook.tab_view); - - if (!self.config.gtk_wide_tabs) tab_bar.setExpandTabs(0); } // If we want the window to be maximized, we do that here. @@ -543,6 +539,16 @@ pub fn syncAppearance(self: *Window) !void { } } + self.tab_bar.setExpandTabs(@intFromBool(self.config.gtk_wide_tabs)); + self.tab_bar.setAutohide(switch (self.config.window_show_tab_bar) { + .auto, .never => @intFromBool(true), + .always => @intFromBool(false), + }); + self.tab_bar.as(gtk.Widget).setVisible(switch (self.config.window_show_tab_bar) { + .always, .auto => @intFromBool(true), + .never => @intFromBool(false), + }); + self.winproto.syncAppearance() catch |err| { log.warn("failed to sync winproto appearance error={}", .{err}); }; diff --git a/src/config/Config.zig b/src/config/Config.zig index ca330f8f6..fd6ae798e 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -1410,6 +1410,27 @@ keybind: Keybinds = .{}, /// * `end` - Insert the new tab at the end of the tab list. @"window-new-tab-position": WindowNewTabPosition = .current, +/// Whether to show the tab bar. +/// +/// Valid values: +/// +/// - `always` +/// +/// Always display the tab bar, even when there's only one tab. +/// +/// - `auto` *(default)* +/// +/// Automatically show and hide the tab bar. The tab bar is only +/// shown when there are two or more tabs present. +/// +/// - `never` +/// +/// Never show the tab bar. Tabs are only accessible via the tab +/// overview or by keybind actions. +/// +/// Currently only supported on Linux (GTK). +@"window-show-tab-bar": WindowShowTabBar = .auto, + /// Background color for the window titlebar. This only takes effect if /// window-theme is set to ghostty. Currently only supported in the GTK app /// runtime. @@ -5747,7 +5768,6 @@ pub const GtkSingleInstance = enum { pub const GtkTabsLocation = enum { top, bottom, - hidden, }; /// See gtk-toolbar-style @@ -5795,6 +5815,13 @@ pub const WindowNewTabPosition = enum { end, }; +/// See window-show-tab-bar +pub const WindowShowTabBar = enum { + always, + auto, + never, +}; + /// See resize-overlay pub const ResizeOverlay = enum { always,