mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk: use a subtitle to mark the current working directory
If the title is already the current working directory, hide the subtitle. Otherwise show the current working directory, like if a command is running for instance. Signed-off-by: Tristan Partin <tristan@partin.io>
This commit is contained in:
@ -346,6 +346,11 @@ cursor: ?*c.GdkCursor = null,
|
||||
/// pass it to GTK.
|
||||
title_text: ?[:0]const u8 = null,
|
||||
|
||||
/// Our current working directory. We use this value for setting tooltips in
|
||||
/// the headerbar subtitle if we have focus. When set, the text in this buf
|
||||
/// will be null-terminated because we need to pass it to GTK.
|
||||
pwd: ?[:0]const u8 = null,
|
||||
|
||||
/// The core surface backing this surface
|
||||
core_surface: CoreSurface,
|
||||
|
||||
@ -624,6 +629,7 @@ fn realize(self: *Surface) !void {
|
||||
pub fn deinit(self: *Surface) void {
|
||||
self.init_config.deinit(self.app.core_app.alloc);
|
||||
if (self.title_text) |title| self.app.core_app.alloc.free(title);
|
||||
if (self.pwd) |pwd| self.app.core_app.alloc.free(pwd);
|
||||
|
||||
// We don't allocate anything if we aren't realized.
|
||||
if (!self.realized) return;
|
||||
@ -871,7 +877,7 @@ fn updateTitleLabels(self: *Surface) void {
|
||||
// I don't know a way around this yet. I've tried re-hiding the
|
||||
// cursor after setting the title but it doesn't work, I think
|
||||
// due to some gtk event loop things...
|
||||
c.gtk_window_set_title(window.window, title.ptr);
|
||||
window.setTitle(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -908,11 +914,33 @@ pub fn getTitle(self: *Surface) ?[:0]const u8 {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn setPwd(self: *Surface, pwd: [:0]const u8) !void {
|
||||
// If we have a tab and are the focused child, then we have to update the tab
|
||||
/// Update the subtitle of the surface's window if it has one.
|
||||
fn updateSubtitle(self: *Surface, subtitle: [:0]const u8) void {
|
||||
const window = self.container.window() orelse return;
|
||||
window.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
/// Set the current working directory of the surface.
|
||||
///
|
||||
/// In addition, update the tab's tooltip text, and if we are the focused child,
|
||||
/// update the subtitle of the containing window.
|
||||
pub fn setPwd(self: *Surface, slice: [:0]const u8) !void {
|
||||
if (self.container.tab()) |tab| {
|
||||
tab.setTooltipText(pwd);
|
||||
tab.setTooltipText(slice);
|
||||
|
||||
if (tab.focus_child == self) {
|
||||
if (self.container.window()) |window| {
|
||||
window.setSubtitle(slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const alloc = self.app.core_app.alloc;
|
||||
|
||||
// Failing to set the surface's current working directory is not a big
|
||||
// deal since we just used our slice parameter which is the same value.
|
||||
if (self.pwd) |old| alloc.free(old);
|
||||
self.pwd = alloc.dupeZ(u8, slice) catch null;
|
||||
}
|
||||
|
||||
pub fn setMouseShape(
|
||||
@ -1860,6 +1888,12 @@ fn gtkFocusEnter(_: *c.GtkEventControllerFocus, ud: ?*anyopaque) callconv(.C) vo
|
||||
self.unfocused_widget = null;
|
||||
}
|
||||
|
||||
if (self.pwd) |pwd| {
|
||||
if (self.container.window()) |window| {
|
||||
window.setSubtitle(pwd);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify our surface
|
||||
self.core_surface.focusCallback(true) catch |err| {
|
||||
log.err("error in focus callback err={}", .{err});
|
||||
|
@ -426,6 +426,22 @@ inline fn isAdwWindow(self: *Window) bool {
|
||||
self.app.config.@"gtk-titlebar";
|
||||
}
|
||||
|
||||
/// Set the title of the window.
|
||||
pub fn setTitle(self: *Window, title: [:0]const u8) void {
|
||||
if (self.isAdwWindow() and self.app.config.@"gtk-titlebar") {
|
||||
self.header.?.setTitle(title);
|
||||
} else {
|
||||
c.gtk_window_set_title(self.window, title);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the subtitle of the window if it has one.
|
||||
pub fn setSubtitle(self: *Window, subtitle: [:0]const u8) void {
|
||||
if (self.isAdwWindow() and self.app.config.@"gtk-titlebar") {
|
||||
self.header.?.setSubtitle(subtitle);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a new tab to this window.
|
||||
pub fn newTab(self: *Window, parent: ?*CoreSurface) !void {
|
||||
const alloc = self.app.core_app.alloc;
|
||||
|
@ -14,14 +14,15 @@ pub const HeaderBar = union(enum) {
|
||||
if ((comptime adwaita.versionAtLeast(1, 4, 0)) and
|
||||
adwaita.enabled(&window.app.config))
|
||||
{
|
||||
return initAdw();
|
||||
return initAdw(window);
|
||||
}
|
||||
|
||||
return initGtk();
|
||||
}
|
||||
|
||||
fn initAdw() HeaderBar {
|
||||
fn initAdw(window: *Window) HeaderBar {
|
||||
const headerbar = c.adw_header_bar_new();
|
||||
c.adw_header_bar_set_title_widget(@ptrCast(headerbar), @ptrCast(c.adw_window_title_new(c.gtk_window_get_title(window.window) orelse "Ghostty", null)));
|
||||
return .{ .adw = @ptrCast(headerbar) };
|
||||
}
|
||||
|
||||
@ -66,4 +67,26 @@ pub const HeaderBar = union(enum) {
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setTitle(self: HeaderBar, title: [:0]const u8) void {
|
||||
switch (self) {
|
||||
.adw => |headerbar| if (comptime adwaita.versionAtLeast(0, 0, 0)) {
|
||||
const window_title: *c.AdwWindowTitle = @ptrCast(c.adw_header_bar_get_title_widget(@ptrCast(headerbar)));
|
||||
c.adw_window_title_set_title(window_title, title);
|
||||
},
|
||||
// The title is owned by the window when not using Adwaita
|
||||
.gtk => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setSubtitle(self: HeaderBar, subtitle: [:0]const u8) void {
|
||||
switch (self) {
|
||||
.adw => |headerbar| if (comptime adwaita.versionAtLeast(0, 0, 0)) {
|
||||
const window_title: *c.AdwWindowTitle = @ptrCast(c.adw_header_bar_get_title_widget(@ptrCast(headerbar)));
|
||||
c.adw_window_title_set_subtitle(window_title, subtitle);
|
||||
},
|
||||
// There is no subtitle unless Adwaita is used
|
||||
.gtk => unreachable,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -440,7 +440,7 @@ fn adwSelectPage(_: *c.GObject, _: *c.GParamSpec, ud: ?*anyopaque) void {
|
||||
const window: *Window = @ptrCast(@alignCast(ud.?));
|
||||
const page = c.adw_tab_view_get_selected_page(window.notebook.adw_tab_view) orelse return;
|
||||
const title = c.adw_tab_page_get_title(page);
|
||||
c.gtk_window_set_title(window.window, title);
|
||||
window.setTitle(std.mem.span(title));
|
||||
}
|
||||
|
||||
fn gtkSwitchPage(_: *c.GtkNotebook, page: *c.GtkWidget, _: usize, ud: ?*anyopaque) callconv(.C) void {
|
||||
@ -448,7 +448,7 @@ fn gtkSwitchPage(_: *c.GtkNotebook, page: *c.GtkWidget, _: usize, ud: ?*anyopaqu
|
||||
const gtk_label_box = @as(*c.GtkWidget, @ptrCast(c.gtk_notebook_get_tab_label(window.notebook.gtk_notebook, page)));
|
||||
const gtk_label = @as(*c.GtkLabel, @ptrCast(c.gtk_widget_get_first_child(gtk_label_box)));
|
||||
const label_text = c.gtk_label_get_text(gtk_label);
|
||||
c.gtk_window_set_title(window.window, label_text);
|
||||
window.setTitle(std.mem.span(label_text));
|
||||
}
|
||||
|
||||
fn adwTabViewCreateWindow(
|
||||
|
Reference in New Issue
Block a user