diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index 96c9188a7..432345627 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -235,17 +235,21 @@ class BaseTerminalController: NSWindowController, // Set the main window title window.title = to - - // Get the current working directory from the focused surface - if let pwd = focusedSurface?.pwd { - // Set the window's representedURL to the current working directory - window.representedURL = URL(fileURLWithPath: pwd) + + } + + func pwdDidChange(to: URL?) { + guard let window else { return } + + if ghostty.config.macosTitlebarProxyIcon == .visible { + // Use the 'to' URL directly + window.representedURL = to } else { - // If we don't have a pwd, set representedURL to nil window.representedURL = nil } } + func cellSizeDidChange(to: NSSize) { guard ghostty.config.windowStepResize else { return } self.window?.contentResizeIncrements = to diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index d06cb0d3e..42617e047 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -310,6 +310,14 @@ class TerminalController: BaseTerminalController { // Disallow tabbing if the titlebar is hidden, since that will (should) also hide the tab bar. window.tabbingMode = .disallowed + + // Nuke it from orbit -- hide the titlebar container entirely, just in case. There are + // some operations that appear to bring back the titlebar visibility so this ensures + // it is gone forever. + if let themeFrame = window.contentView?.superview, + let titleBarContainer = themeFrame.firstDescendant(withClassName: "NSTitlebarContainerView") { + titleBarContainer.isHidden = true + } } // In various situations, macOS automatically tabs new windows. Ghostty handles diff --git a/macos/Sources/Features/Terminal/TerminalView.swift b/macos/Sources/Features/Terminal/TerminalView.swift index ec7d7c229..768f57d30 100644 --- a/macos/Sources/Features/Terminal/TerminalView.swift +++ b/macos/Sources/Features/Terminal/TerminalView.swift @@ -10,6 +10,9 @@ protocol TerminalViewDelegate: AnyObject { /// The title of the terminal should change. func titleDidChange(to: String) + + /// The URL of the pwd should change. + func pwdDidChange(to: URL?) /// The cell size changed. func cellSizeDidChange(to: NSSize) @@ -62,7 +65,16 @@ struct TerminalView: View { return title } - + + // The proxy icon URL for our window + private var proxyIconURL: URL? { + guard let proxyURLString = focusedSurface?.pwd else { + return nil + } + // Use fileURLWithPath initializer for file paths + return URL(fileURLWithPath: proxyURLString) + } + var body: some View { switch ghostty.readiness { case .loading: @@ -87,6 +99,9 @@ struct TerminalView: View { .onChange(of: title) { newValue in self.delegate?.titleDidChange(to: newValue) } + .onChange(of: proxyIconURL) { newValue in + self.delegate?.pwdDidChange(to: newValue) + } .onChange(of: cellSize) { newValue in guard let size = newValue else { return } self.delegate?.cellSizeDidChange(to: size) diff --git a/macos/Sources/Ghostty/Ghostty.Config.swift b/macos/Sources/Ghostty/Ghostty.Config.swift index 29639c39e..6e961b31c 100644 --- a/macos/Sources/Ghostty/Ghostty.Config.swift +++ b/macos/Sources/Ghostty/Ghostty.Config.swift @@ -228,6 +228,17 @@ extension Ghostty { guard let ptr = v else { return defaultValue } return String(cString: ptr) } + + var macosTitlebarProxyIcon: MacOSTitlebarProxyIcon { + let defaultValue = MacOSTitlebarProxyIcon.visible + guard let config = self.config else { return defaultValue } + var v: UnsafePointer? = nil + let key = "macos-titlebar-proxy-icon" + guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return defaultValue } + guard let ptr = v else { return defaultValue } + let str = String(cString: ptr) + return MacOSTitlebarProxyIcon(rawValue: str) ?? defaultValue + } var macosWindowShadow: Bool { guard let config = self.config else { return false } diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift index f6fab532e..25d012ec5 100644 --- a/macos/Sources/Ghostty/Package.swift +++ b/macos/Sources/Ghostty/Package.swift @@ -194,6 +194,13 @@ extension Ghostty { } } } + + /// Enum for the macos-titlebar-proxy-icon config option + enum MacOSTitlebarProxyIcon: String { + case visible + case hidden + } + } // MARK: Surface Notifications diff --git a/src/config/Config.zig b/src/config/Config.zig index 9097051ad..6dec34dfc 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -1444,6 +1444,22 @@ keybind: Keybinds = .{}, /// Changing this option at runtime only applies to new windows. @"macos-titlebar-style": MacTitlebarStyle = .transparent, +/// Whether the proxy icon in the macOS titlebar is visible. The proxy icon +/// is the icon that represents the folder of the current working directory. +/// You can see this very clearly in the macOS built-in Terminal.app +/// titlebar. +/// +/// The proxy icon is only visible with the native macOS titlebar style. +/// +/// The default value is `visible`. +/// +/// This setting can be changed at runtime and will affect all currently +/// open windows but only after their working directory changes again. +/// Therefore, to make this work after changing the setting, you must +/// usually `cd` to a different directory, open a different file in an +/// editor, etc. +@"macos-titlebar-proxy-icon": MacTitlebarProxyIcon = .visible, + /// If `true`, the *Option* key will be treated as *Alt*. This makes terminal /// sequences expecting *Alt* to work properly, but will break Unicode input /// sequences on macOS if you use them via the *Alt* key. You may set this to @@ -4430,6 +4446,12 @@ pub const MacTitlebarStyle = enum { hidden, }; +/// See macos-titlebar-proxy-icon +pub const MacTitlebarProxyIcon: type = enum { + visible, + hidden, +}; + /// See gtk-single-instance pub const GtkSingleInstance = enum { desktop,