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.
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,
}
.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});
};

View File

@ -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,