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_CLOSE_ALL_WINDOWS,
GHOSTTY_ACTION_TOGGLE_FULLSCREEN,
GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW,
GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS,
GHOSTTY_ACTION_GOTO_TAB,
GHOSTTY_ACTION_GOTO_SPLIT,

View File

@ -484,6 +484,8 @@ extension Ghostty {
case GHOSTTY_ACTION_CLOSE_ALL_WINDOWS:
fallthrough
case GHOSTTY_ACTION_TOGGLE_TAB_OVERVIEW:
fallthrough
case GHOSTTY_ACTION_TOGGLE_WINDOW_DECORATIONS:
fallthrough
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(
.{ .surface = self },
.secure_input,

View File

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

View File

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

View File

@ -372,6 +372,7 @@ pub fn performAction(
.mouse_visibility => self.setMouseVisibility(target, value),
.mouse_shape => try self.setMouseShape(target, value),
.mouse_over_link => self.setMouseOverLink(target, value),
.toggle_tab_overview => self.toggleTabOverview(target),
.toggle_window_decorations => self.toggleWindowDecorations(target),
.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(
_: *App,
target: apprt.Target,

View File

@ -35,6 +35,10 @@ window: *c.GtkWindow,
/// GtkHeaderBar depending on if adw is enabled and linked.
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.
/// can be either c.GtkNotebook or c.AdwTabView.
notebook: Notebook,
@ -68,6 +72,7 @@ pub fn init(self: *Window, app: *App) !void {
.app = app,
.window = undefined,
.header = null,
.tab_overview = null,
.notebook = undefined,
.context_menu = 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);
// 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();
c.adw_tab_overview_set_enable_new_tab(@ptrCast(tab_overview), 1);
_ = 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_menu_button_set_icon_name(@ptrCast(btn), "open-menu-symbolic");
c.gtk_menu_button_set_menu_model(@ptrCast(btn), @ptrCast(@alignCast(app.menu)));
if (self.isAdwWindow())
c.adw_header_bar_pack_end(@ptrCast(header), btn)
else
c.gtk_header_bar_pack_end(@ptrCast(header), btn);
if (self.isAdwWindow()) {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
c.adw_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 (tab_overview_) |tab_overview| {
if (self.tab_overview) |tab_overview| {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
assert(self.isAdwWindow());
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 (tab_overview_) |tab_overview| {
if (self.tab_overview) |tab_overview| {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
assert(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
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 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
// we're using an AdwTabOverview or not.
if (tab_overview_) |tab_overview| {
if (self.tab_overview) |tab_overview| {
c.adw_tab_overview_set_child(
@ptrCast(tab_overview),
@ptrCast(@alignCast(toolbar_view)),
@ -391,18 +399,9 @@ pub fn deinit(self: *Window) void {
/// paths that are not enabled.
inline fn isAdwWindow(self: *Window) bool {
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.versionAtLeast(1, 4, 0) and
self.app.config.@"gtk-titlebar");
self.app.config.@"gtk-titlebar";
}
/// 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.
pub fn toggleFullscreen(self: *Window) void {
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.
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
/// the direction given.
new_split: SplitDirection,
@ -607,6 +611,7 @@ pub const Action = union(enum) {
.next_tab,
.last_tab,
.goto_tab,
.toggle_tab_overview,
.new_split,
.goto_split,
.toggle_split_zoom,