gtk: add option to always display the tab bar

Also fixes crashes in both vanilla GTK and Adwaita implementations of
`closeTab`, which erroneously close windows twice when there are no
more tabs left (we probably already handle it somewhere else).
pull/5590/head
Leah Amelia Chen 2025-02-05 13:58:01 +01:00
parent a090e8eeed
commit d6dea79bde
No known key found for this signature in database
2 changed files with 59 additions and 26 deletions

View File

@ -54,6 +54,9 @@ window: *adw.ApplicationWindow,
/// The header bar for the window. /// The header bar for the window.
headerbar: HeaderBar, 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 /// The tab overview for the window. This is possibly null since there is no
/// taboverview without a AdwApplicationWindow (libadwaita >= 1.4.0). /// taboverview without a AdwApplicationWindow (libadwaita >= 1.4.0).
tab_overview: ?*adw.TabOverview, tab_overview: ?*adw.TabOverview,
@ -82,6 +85,7 @@ pub const DerivedConfig = struct {
gtk_tabs_location: configpkg.Config.GtkTabsLocation, gtk_tabs_location: configpkg.Config.GtkTabsLocation,
gtk_wide_tabs: bool, gtk_wide_tabs: bool,
gtk_toolbar_style: configpkg.Config.GtkToolbarStyle, gtk_toolbar_style: configpkg.Config.GtkToolbarStyle,
window_show_tab_bar: configpkg.Config.WindowShowTabBar,
quick_terminal_position: configpkg.Config.QuickTerminalPosition, quick_terminal_position: configpkg.Config.QuickTerminalPosition,
quick_terminal_size: configpkg.Config.QuickTerminalSize, quick_terminal_size: configpkg.Config.QuickTerminalSize,
@ -101,6 +105,7 @@ pub const DerivedConfig = struct {
.gtk_tabs_location = config.@"gtk-tabs-location", .gtk_tabs_location = config.@"gtk-tabs-location",
.gtk_wide_tabs = config.@"gtk-wide-tabs", .gtk_wide_tabs = config.@"gtk-wide-tabs",
.gtk_toolbar_style = config.@"gtk-toolbar-style", .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_position = config.@"quick-terminal-position",
.quick_terminal_size = config.@"quick-terminal-size", .quick_terminal_size = config.@"quick-terminal-size",
@ -135,6 +140,7 @@ pub fn init(self: *Window, app: *App) !void {
.config = DerivedConfig.init(&app.config), .config = DerivedConfig.init(&app.config),
.window = undefined, .window = undefined,
.headerbar = undefined, .headerbar = undefined,
.tab_bar = undefined,
.tab_overview = null, .tab_overview = null,
.notebook = undefined, .notebook = undefined,
.titlebar_menu = 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 we're using an AdwWindow then we can support the tab overview.
if (self.tab_overview) |tab_overview| { if (self.tab_overview) |tab_overview| {
if (!adw_version.supportsTabOverview()) unreachable; 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(); const btn = gtk.ToggleButton.new();
btn.as(gtk.Widget).setTooltipText(i18n._("View Open Tabs")); btn.as(gtk.Widget).setTooltipText(i18n._("View Open Tabs"));
btn.as(gtk.Button).setIconName("view-grid-symbolic"); 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); break :btn btn.as(gtk.Widget);
}, },
.never => btn: {
.hidden => btn: {
const btn = adw.TabButton.new(); const btn = adw.TabButton.new();
btn.setView(self.notebook.tab_view); btn.setView(self.notebook.tab_view);
btn.as(gtk.Actionable).setActionName("overview.open"); btn.as(gtk.Actionable).setActionName("overview.open");
@ -376,21 +382,16 @@ pub fn init(self: *Window, app: *App) !void {
// Our actions for the menu // Our actions for the menu
initActions(self); initActions(self);
self.tab_bar = adw.TabBar.new();
self.tab_bar.setView(self.notebook.tab_view);
if (adw_version.supportsToolbarView()) { if (adw_version.supportsToolbarView()) {
const toolbar_view = adw.ToolbarView.new(); const toolbar_view = adw.ToolbarView.new();
toolbar_view.addTopBar(self.headerbar.asWidget()); 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) { switch (self.config.gtk_tabs_location) {
.top => toolbar_view.addTopBar(tab_bar.as(gtk.Widget)), .top => toolbar_view.addTopBar(self.tab_bar.as(gtk.Widget)),
.bottom => toolbar_view.addBottomBar(tab_bar.as(gtk.Widget)), .bottom => toolbar_view.addBottomBar(self.tab_bar.as(gtk.Widget)),
.hidden => unreachable,
}
} }
toolbar_view.setContent(box.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. // Set our application window content.
self.tab_overview.?.setChild(toolbar_view.as(gtk.Widget)); self.tab_overview.?.setChild(toolbar_view.as(gtk.Widget));
self.window.setContent(self.tab_overview.?.as(gtk.Widget)); self.window.setContent(self.tab_overview.?.as(gtk.Widget));
} else tab_bar: { } else {
if (self.config.gtk_tabs_location == .hidden) break :tab_bar;
// In earlier adwaita versions, we need to add the tabbar manually since we do not use // In earlier adwaita versions, we need to add the tabbar manually since we do not use
// an AdwToolbarView. // an AdwToolbarView.
const tab_bar = adw.TabBar.new(); self.tab_bar.as(gtk.Widget).addCssClass("inline");
tab_bar.as(gtk.Widget).addCssClass("inline");
switch (self.config.gtk_tabs_location) { switch (self.config.gtk_tabs_location) {
.top => box.insertChildAfter( .top => box.insertChildAfter(
tab_bar.as(gtk.Widget), self.tab_bar.as(gtk.Widget),
self.headerbar.asWidget(), self.headerbar.asWidget(),
), ),
.bottom => box.append(tab_bar.as(gtk.Widget)), .bottom => box.append(self.tab_bar.as(gtk.Widget)),
.hidden => unreachable,
} }
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. // 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| { self.winproto.syncAppearance() catch |err| {
log.warn("failed to sync winproto appearance error={}", .{err}); log.warn("failed to sync winproto appearance error={}", .{err});
}; };

View File

@ -1410,6 +1410,27 @@ keybind: Keybinds = .{},
/// * `end` - Insert the new tab at the end of the tab list. /// * `end` - Insert the new tab at the end of the tab list.
@"window-new-tab-position": WindowNewTabPosition = .current, @"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 /// Background color for the window titlebar. This only takes effect if
/// window-theme is set to ghostty. Currently only supported in the GTK app /// window-theme is set to ghostty. Currently only supported in the GTK app
/// runtime. /// runtime.
@ -5747,7 +5768,6 @@ pub const GtkSingleInstance = enum {
pub const GtkTabsLocation = enum { pub const GtkTabsLocation = enum {
top, top,
bottom, bottom,
hidden,
}; };
/// See gtk-toolbar-style /// See gtk-toolbar-style
@ -5795,6 +5815,13 @@ pub const WindowNewTabPosition = enum {
end, end,
}; };
/// See window-show-tab-bar
pub const WindowShowTabBar = enum {
always,
auto,
never,
};
/// See resize-overlay /// See resize-overlay
pub const ResizeOverlay = enum { pub const ResizeOverlay = enum {
always, always,