Merge pull request #2298 from Pangoraw/toggle_tab_overview

add binding to toggle tab overview
This commit is contained in:
Mitchell Hashimoto
2024-09-27 10:19:49 -07:00
committed by GitHub
8 changed files with 64 additions and 19 deletions

View File

@ -505,6 +505,7 @@ typedef enum {
GHOSTTY_ACTION_NEW_SPLIT, GHOSTTY_ACTION_NEW_SPLIT,
GHOSTTY_ACTION_CLOSE_ALL_WINDOWS, GHOSTTY_ACTION_CLOSE_ALL_WINDOWS,
GHOSTTY_ACTION_TOGGLE_FULLSCREEN, GHOSTTY_ACTION_TOGGLE_FULLSCREEN,
GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW,
GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS, GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS,
GHOSTTY_ACTION_GOTO_TAB, GHOSTTY_ACTION_GOTO_TAB,
GHOSTTY_ACTION_GOTO_SPLIT, GHOSTTY_ACTION_GOTO_SPLIT,

View File

@ -484,6 +484,8 @@ extension Ghostty {
case GHOSTTY_ACTION_CLOSE_ALL_WINDOWS: case GHOSTTY_ACTION_CLOSE_ALL_WINDOWS:
fallthrough fallthrough
case GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW:
fallthrough
case GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS: case GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS:
fallthrough fallthrough
case GHOSTTY_ACTION_PRESENT_TERMINAL: case GHOSTTY_ACTION_PRESENT_TERMINAL:

View File

@ -3830,6 +3830,12 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
{}, {},
), ),
.toggle_tab_overview => try self.rt_app.performAction(
.{ .surface = self },
.toggle_tab_overview,
{},
),
.toggle_secure_input => try self.rt_app.performAction( .toggle_secure_input => try self.rt_app.performAction(
.{ .surface = self }, .{ .surface = self },
.secure_input, .secure_input,

View File

@ -87,6 +87,9 @@ pub const Action = union(Key) {
/// Toggle fullscreen mode. /// Toggle fullscreen mode.
toggle_fullscreen: Fullscreen, toggle_fullscreen: Fullscreen,
/// Toggle tab overview.
toggle_tab_overview,
/// Toggle whether window directions are shown. /// Toggle whether window directions are shown.
toggle_window_decorations, toggle_window_decorations,
@ -171,6 +174,7 @@ pub const Action = union(Key) {
new_split, new_split,
close_all_windows, close_all_windows,
toggle_fullscreen, toggle_fullscreen,
toggle_tab_overview,
toggle_window_decorations, toggle_window_decorations,
goto_tab, goto_tab,
goto_split, goto_split,

View File

@ -194,6 +194,7 @@ pub const App = struct {
.toggle_split_zoom, .toggle_split_zoom,
.present_terminal, .present_terminal,
.close_all_windows, .close_all_windows,
.toggle_tab_overview,
.toggle_window_decorations, .toggle_window_decorations,
.goto_tab, .goto_tab,
.inspector, .inspector,

View File

@ -372,6 +372,7 @@ pub fn performAction(
.mouse_visibility => self.setMouseVisibility(target, value), .mouse_visibility => self.setMouseVisibility(target, value),
.mouse_shape => try self.setMouseShape(target, value), .mouse_shape => try self.setMouseShape(target, value),
.mouse_over_link => self.setMouseOverLink(target, value), .mouse_over_link => self.setMouseOverLink(target, value),
.toggle_tab_overview => self.toggleTabOverview(target),
.toggle_window_decorations => self.toggleWindowDecorations(target), .toggle_window_decorations => self.toggleWindowDecorations(target),
.quit_timer => self.quitTimer(value), .quit_timer => self.quitTimer(value),
@ -534,6 +535,23 @@ fn toggleFullscreen(
} }
} }
fn toggleTabOverview(_: *App, target: apprt.Target) void {
switch (target) {
.app => {},
.surface => |v| {
const window = v.rt_surface.container.window() orelse {
log.info(
"toggleTabOverview invalid for container={s}",
.{@tagName(v.rt_surface.container)},
);
return;
};
window.toggleTabOverview();
},
}
}
fn toggleWindowDecorations( fn toggleWindowDecorations(
_: *App, _: *App,
target: apprt.Target, target: apprt.Target,

View File

@ -35,6 +35,10 @@ window: *c.GtkWindow,
/// GtkHeaderBar depending on if adw is enabled and linked. /// GtkHeaderBar depending on if adw is enabled and linked.
header: ?*c.GtkWidget, header: ?*c.GtkWidget,
/// The tab overview for the window. This is possibly null since there is no
/// taboverview without a AdwApplicationWindow (libadwaita >= 1.4.0).
tab_overview: ?*c.GtkWidget,
/// The notebook (tab grouping) for this window. /// The notebook (tab grouping) for this window.
/// can be either c.GtkNotebook or c.AdwTabView. /// can be either c.GtkNotebook or c.AdwTabView.
notebook: Notebook, notebook: Notebook,
@ -68,6 +72,7 @@ pub fn init(self: *Window, app: *App) !void {
.app = app, .app = app,
.window = undefined, .window = undefined,
.header = null, .header = null,
.tab_overview = null,
.notebook = undefined, .notebook = undefined,
.context_menu = undefined, .context_menu = undefined,
.toast_overlay = undefined, .toast_overlay = undefined,
@ -114,7 +119,7 @@ pub fn init(self: *Window, app: *App) !void {
const box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0); const box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0);
// If we are using an AdwWindow then we can support the tab overview. // If we are using an AdwWindow then we can support the tab overview.
const tab_overview_: ?*c.GtkWidget = if (self.isAdwWindow()) overview: { self.tab_overview = if (self.isAdwWindow()) overview: {
const tab_overview = c.adw_tab_overview_new(); const tab_overview = c.adw_tab_overview_new();
c.adw_tab_overview_set_enable_new_tab(@ptrCast(tab_overview), 1); c.adw_tab_overview_set_enable_new_tab(@ptrCast(tab_overview), 1);
_ = c.g_signal_connect_data( _ = c.g_signal_connect_data(
@ -152,14 +157,15 @@ pub fn init(self: *Window, app: *App) !void {
c.gtk_widget_set_tooltip_text(btn, "Main Menu"); c.gtk_widget_set_tooltip_text(btn, "Main Menu");
c.gtk_menu_button_set_icon_name(@ptrCast(btn), "open-menu-symbolic"); c.gtk_menu_button_set_icon_name(@ptrCast(btn), "open-menu-symbolic");
c.gtk_menu_button_set_menu_model(@ptrCast(btn), @ptrCast(@alignCast(app.menu))); c.gtk_menu_button_set_menu_model(@ptrCast(btn), @ptrCast(@alignCast(app.menu)));
if (self.isAdwWindow()) if (self.isAdwWindow()) {
c.adw_header_bar_pack_end(@ptrCast(header), btn) if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
else c.adw_header_bar_pack_end(@ptrCast(header), btn);
c.gtk_header_bar_pack_end(@ptrCast(header), btn); } else c.gtk_header_bar_pack_end(@ptrCast(header), btn);
} }
// 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 (tab_overview_) |tab_overview| { if (self.tab_overview) |tab_overview| {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
assert(self.isAdwWindow()); assert(self.isAdwWindow());
const btn = c.gtk_toggle_button_new(); const btn = c.gtk_toggle_button_new();
@ -235,7 +241,8 @@ pub fn init(self: *Window, app: *App) !void {
}; };
// If we have a tab overview then we can set it on our notebook. // If we have a tab overview then we can set it on our notebook.
if (tab_overview_) |tab_overview| { if (self.tab_overview) |tab_overview| {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
assert(self.notebook == .adw_tab_view); assert(self.notebook == .adw_tab_view);
c.adw_tab_overview_set_view(@ptrCast(tab_overview), self.notebook.adw_tab_view); c.adw_tab_overview_set_view(@ptrCast(tab_overview), self.notebook.adw_tab_view);
} }
@ -256,7 +263,8 @@ pub fn init(self: *Window, app: *App) !void {
// Our actions for the menu // Our actions for the menu
initActions(self); initActions(self);
if (self.hasAdwToolbar()) { if (self.isAdwWindow()) {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
const toolbar_view: *c.AdwToolbarView = @ptrCast(c.adw_toolbar_view_new()); const toolbar_view: *c.AdwToolbarView = @ptrCast(c.adw_toolbar_view_new());
const header_widget: *c.GtkWidget = @ptrCast(@alignCast(self.header.?)); const header_widget: *c.GtkWidget = @ptrCast(@alignCast(self.header.?));
@ -289,7 +297,7 @@ pub fn init(self: *Window, app: *App) !void {
// Set our application window content. The content depends on if // Set our application window content. The content depends on if
// we're using an AdwTabOverview or not. // we're using an AdwTabOverview or not.
if (tab_overview_) |tab_overview| { if (self.tab_overview) |tab_overview| {
c.adw_tab_overview_set_child( c.adw_tab_overview_set_child(
@ptrCast(tab_overview), @ptrCast(tab_overview),
@ptrCast(@alignCast(toolbar_view)), @ptrCast(@alignCast(toolbar_view)),
@ -391,18 +399,9 @@ pub fn deinit(self: *Window) void {
/// paths that are not enabled. /// paths that are not enabled.
inline fn isAdwWindow(self: *Window) bool { inline fn isAdwWindow(self: *Window) bool {
return (comptime adwaita.versionAtLeast(1, 4, 0)) and return (comptime adwaita.versionAtLeast(1, 4, 0)) and
adwaita.enabled(&self.app.config) and
self.app.config.@"gtk-titlebar" and
adwaita.versionAtLeast(1, 4, 0);
}
/// This must be `inline` so that the comptime check noops conditional
/// paths that are not enabled.
inline fn hasAdwToolbar(self: *Window) bool {
return ((comptime adwaita.versionAtLeast(1, 4, 0)) and
adwaita.enabled(&self.app.config) and adwaita.enabled(&self.app.config) and
adwaita.versionAtLeast(1, 4, 0) and adwaita.versionAtLeast(1, 4, 0) and
self.app.config.@"gtk-titlebar"); self.app.config.@"gtk-titlebar";
} }
/// Add a new tab to this window. /// Add a new tab to this window.
@ -458,6 +457,15 @@ pub fn gotoTab(self: *Window, n: usize) void {
} }
} }
/// Toggle tab overview (if present)
pub fn toggleTabOverview(self: *Window) void {
if (self.tab_overview) |tab_overview_widget| {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
const tab_overview: *c.AdwTabOverview = @ptrCast(@alignCast(tab_overview_widget));
c.adw_tab_overview_set_open(tab_overview, 1 - c.adw_tab_overview_get_open(tab_overview));
}
}
/// Toggle fullscreen for this window. /// Toggle fullscreen for this window.
pub fn toggleFullscreen(self: *Window) void { pub fn toggleFullscreen(self: *Window) void {
const is_fullscreen = c.gtk_window_is_fullscreen(self.window); const is_fullscreen = c.gtk_window_is_fullscreen(self.window);

View File

@ -298,6 +298,10 @@ pub const Action = union(enum) {
/// Go to the tab with the specific number, 1-indexed. /// Go to the tab with the specific number, 1-indexed.
goto_tab: usize, goto_tab: usize,
/// Toggle the tab overview.
/// This only works with libadwaita enabled currently.
toggle_tab_overview: void,
/// Create a new split in the given direction. The new split will appear in /// Create a new split in the given direction. The new split will appear in
/// the direction given. /// the direction given.
new_split: SplitDirection, new_split: SplitDirection,
@ -607,6 +611,7 @@ pub const Action = union(enum) {
.next_tab, .next_tab,
.last_tab, .last_tab,
.goto_tab, .goto_tab,
.toggle_tab_overview,
.new_split, .new_split,
.goto_split, .goto_split,
.toggle_split_zoom, .toggle_split_zoom,