mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Merge pull request #2298 from Pangoraw/toggle_tab_overview
add binding to toggle tab overview
This commit is contained in:
@ -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,
|
||||||
|
@ -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:
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
Reference in New Issue
Block a user