aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/apprt/gtk/class/window.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-10 21:51:57 +0300
committerGitHub <noreply@github.com>2026-09-10 21:51:57 +0300
commit425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch)
treee52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/src/apprt/gtk/class/window.zig
parent90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff)
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/src/apprt/gtk/class/window.zig')
-rw-r--r--vendor/libghostty-vt/src/apprt/gtk/class/window.zig147
1 files changed, 144 insertions, 3 deletions
diff --git a/vendor/libghostty-vt/src/apprt/gtk/class/window.zig b/vendor/libghostty-vt/src/apprt/gtk/class/window.zig
index c34f2cb4..e2fe6403 100644
--- a/vendor/libghostty-vt/src/apprt/gtk/class/window.zig
+++ b/vendor/libghostty-vt/src/apprt/gtk/class/window.zig
@@ -29,6 +29,7 @@ const Tab = @import("tab.zig").Tab;
const DebugWarning = @import("debug_warning.zig").DebugWarning;
const CommandPalette = @import("command_palette.zig").CommandPalette;
const WeakRef = @import("../weak_ref.zig").WeakRef;
+const TitleDialog = @import("title_dialog.zig").TitleDialog;
const log = std.log.scoped(.gtk_ghostty_window);
@@ -213,6 +214,19 @@ pub const Window = extern struct {
},
);
};
+
+ pub const @"title-override" = struct {
+ pub const name = "title-override";
+ const impl = gobject.ext.defineProperty(
+ name,
+ Self,
+ ?[:0]const u8,
+ .{
+ .default = null,
+ .accessor = C.privateStringFieldAccessor("title_override"),
+ },
+ );
+ };
};
const Private = struct {
@@ -259,6 +273,9 @@ pub const Window = extern struct {
/// setup by `setup-menu`.
context_menu_page: ?*adw.TabPage = null,
+ /// The manually overridden title.
+ title_override: ?[:0]const u8 = null,
+
// Template bindings
tab_overview: *adw.TabOverview,
tab_bar: *adw.TabBar,
@@ -365,6 +382,7 @@ pub const Window = extern struct {
.init("prompt-surface-title", actionPromptSurfaceTitle, null),
.init("prompt-tab-title", actionPromptTabTitle, null),
.init("prompt-context-tab-title", actionPromptContextTabTitle, null),
+ .init("prompt-window-title", actionPromptWindowTitle, null),
.init("ring-bell", actionRingBell, null),
.init("split-right", actionSplitRight, null),
.init("split-left", actionSplitLeft, null),
@@ -390,8 +408,20 @@ pub const Window = extern struct {
/// Create a new tab with the given parent. The tab will be inserted
/// at the position dictated by the `window-new-tab-position` config.
/// The new tab will be selected.
- pub fn newTab(self: *Self, parent_: ?*CoreSurface) void {
- _ = self.newTabPage(parent_, .tab, .none);
+ pub fn newTab(self: *Self, parent_: ?*CoreSurface, overrides: struct {
+ command: ?configpkg.Command = null,
+ shell_integration: ?configpkg.Config.ShellIntegration = null,
+ working_directory: ?[:0]const u8 = null,
+ title: ?[:0]const u8 = null,
+
+ pub const none: @This() = .{};
+ }) void {
+ _ = self.newTabPage(parent_, .tab, .{
+ .command = overrides.command,
+ .shell_integration = overrides.shell_integration,
+ .working_directory = overrides.working_directory,
+ .title = overrides.title,
+ });
}
pub fn newTabForWindow(
@@ -399,6 +429,7 @@ pub const Window = extern struct {
parent_: ?*CoreSurface,
overrides: struct {
command: ?configpkg.Command = null,
+ shell_integration: ?configpkg.Config.ShellIntegration = null,
working_directory: ?[:0]const u8 = null,
title: ?[:0]const u8 = null,
@@ -410,6 +441,7 @@ pub const Window = extern struct {
.window,
.{
.command = overrides.command,
+ .shell_integration = overrides.shell_integration,
.working_directory = overrides.working_directory,
.title = overrides.title,
},
@@ -422,6 +454,7 @@ pub const Window = extern struct {
context: apprt.surface.NewSurfaceContext,
overrides: struct {
command: ?configpkg.Command = null,
+ shell_integration: ?configpkg.Config.ShellIntegration = null,
working_directory: ?[:0]const u8 = null,
title: ?[:0]const u8 = null,
@@ -436,6 +469,7 @@ pub const Window = extern struct {
priv.config,
.{
.command = overrides.command,
+ .shell_integration = overrides.shell_integration,
.working_directory = overrides.working_directory,
.title = overrides.title,
},
@@ -604,6 +638,29 @@ pub const Window = extern struct {
return tab_view.reorderPage(page, desired_pos) != 0;
}
+ pub fn moveTabToNewWindow(self: *Self, surface: *Surface) bool {
+ const tab_view = self.private().tab_view;
+ const tab = ext.getAncestor(
+ Tab,
+ surface.as(gtk.Widget),
+ ) orelse return false;
+ const page = tab_view.getPage(tab.as(gtk.Widget));
+
+ // Skip if this is the only tab in the existing window
+ if (tab_view.getNPages() <= 1) return false;
+
+ const app = Application.default();
+ const window = Window.new(app, .none);
+
+ tab_view.transferPage(
+ page,
+ window.private().tab_view,
+ 0,
+ );
+ window.as(gtk.Window).present();
+ return true;
+ }
+
pub fn toggleTabOverview(self: *Self) void {
const priv = self.private();
const tab_overview = priv.tab_overview;
@@ -1268,6 +1325,57 @@ pub const Window = extern struct {
});
}
+ pub fn setTitleOverride(self: *Self, title: ?[]const u8) void {
+ const priv: *Private = self.private();
+
+ if (priv.title_override) |v| glib.free(@ptrCast(@constCast(v)));
+ priv.title_override = null;
+
+ if (title) |v| priv.title_override = glib.ext.dupeZ(u8, v);
+
+ self.as(gobject.Object).notifyByPspec(properties.@"title-override".impl.param_spec);
+ }
+
+ fn titleDialogSet(_: *TitleDialog, title_: [*:0]const u8, self: *Self) callconv(.c) void {
+ const title = std.mem.span(title_);
+ self.setTitleOverride(if (title.len == 0) null else title);
+ }
+
+ pub fn promptWindowTitle(self: *Self) void {
+ const priv: *Private = self.private();
+
+ var value = std.mem.zeroes(gobject.Value);
+ _ = value.init(gobject.ext.types.string);
+ defer value.unset();
+
+ self.as(gobject.Object).getProperty("title", &value);
+
+ const title_: ?[*:0]const u8 = value.getString();
+ const title: ?[:0]const u8 = if (title_) |v| std.mem.span(v) else null;
+
+ const dialog = TitleDialog.new(.window, priv.title_override orelse title);
+ _ = TitleDialog.signals.set.connect(
+ dialog,
+ *Self,
+ titleDialogSet,
+ self,
+ .{},
+ );
+
+ dialog.present(self.as(gtk.Widget));
+ }
+
+ fn closureTitle(
+ _: *Self,
+ _: ?*Config,
+ title_: ?[*:0]const u8,
+ title_override_: ?[*:0]const u8,
+ ) callconv(.c) ?[*:0]const u8 {
+ if (title_override_) |v| return glib.ext.dupeZ(u8, std.mem.span(v));
+ if (title_) |v| return glib.ext.dupeZ(u8, std.mem.span(v));
+ return glib.ext.dupeZ(u8, "Ghostty");
+ }
+
fn closureSubtitle(
_: *Self,
config_: ?*Config,
@@ -1296,7 +1404,7 @@ pub const Window = extern struct {
priv.handle_active_state_source = null;
}
- priv.command_palette.set(null);
+ priv.command_palette.deinit();
if (priv.config) |v| {
v.unref();
@@ -1320,6 +1428,7 @@ pub const Window = extern struct {
const priv = self.private();
priv.tab_bindings.unref();
priv.winproto.deinit();
+ if (priv.title_override) |v| glib.free(@ptrCast(@constCast(v)));
gobject.Object.virtual_methods.finalize.call(
Class.parent,
@@ -1374,11 +1483,33 @@ pub const Window = extern struct {
}
}
+ // Notify every displayed surface when the compositor changes the
+ // Wayland xdg_toplevel suspended state.
+ _ = gobject.Object.signals.notify.connect(
+ self.as(gtk.Window),
+ *Self,
+ propSuspended,
+ self,
+ .{ .detail = "suspended" },
+ );
+
// When we are realized we always setup our appearance since this
// calls some winproto functions.
self.syncAppearance();
}
+ fn propSuspended(
+ _: *gtk.Window,
+ _: *gobject.ParamSpec,
+ self: *Self,
+ ) callconv(.c) void {
+ const tab = self.getSelectedTab() orelse return;
+ const tree = tab.getSurfaceTree() orelse return;
+
+ var it = tree.iterator();
+ while (it.next()) |entry| entry.view.updateOcclusion();
+ }
+
fn btnNewTab(_: *adw.SplitButton, self: *Self) callconv(.c) void {
self.performBindingAction(.new_tab);
}
@@ -1954,6 +2085,14 @@ pub const Window = extern struct {
self.performBindingAction(.prompt_tab_title);
}
+ fn actionPromptWindowTitle(
+ _: *gio.SimpleAction,
+ _: ?*glib.Variant,
+ self: *Window,
+ ) callconv(.c) void {
+ self.performBindingAction(.prompt_window_title);
+ }
+
fn actionSplitRight(
_: *gio.SimpleAction,
_: ?*glib.Variant,
@@ -2161,6 +2300,7 @@ pub const Window = extern struct {
properties.@"tabs-wide".impl,
properties.@"toolbar-style".impl,
properties.@"titlebar-style".impl,
+ properties.@"title-override".impl,
});
// Bindings
@@ -2191,6 +2331,7 @@ pub const Window = extern struct {
class.bindTemplateCallback("notify_quick_terminal", &propQuickTerminal);
class.bindTemplateCallback("notify_scale_factor", &propScaleFactor);
class.bindTemplateCallback("titlebar_style_is_tabs", &closureTitlebarStyleIsTab);
+ class.bindTemplateCallback("computed_title", &closureTitle);
class.bindTemplateCallback("computed_subtitle", &closureSubtitle);
// Virtual methods