From baf75dfaaf94d8426b86f2198672330bee3c0994 Mon Sep 17 00:00:00 2001 From: Jon Parise Date: Thu, 8 Feb 2024 13:25:54 -0800 Subject: [PATCH] macos: configurable titlebar fonts Add support for configurable fonts for window and tab titles. This is only implemented for macOS (and could be macOS-only if other platforms aren't able to support this using their windowing toolkits). It plays nicely with regular and titlebar tabs. --- .../Terminal/TerminalController.swift | 11 ++++- .../Features/Terminal/TerminalToolbar.swift | 12 +++++- .../Features/Terminal/TerminalWindow.swift | 42 +++++++++++++++++++ macos/Sources/Ghostty/Ghostty.Config.swift | 11 ++++- src/config/Config.zig | 5 +++ 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index 5bb44f341..ea9705e47 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -184,6 +184,13 @@ class TerminalController: NSWindowController, NSWindowDelegate, let appearance = NSAppearance(named: color.isLightColor ? .aqua : .darkAqua) window.appearance = appearance } + + // Set the font for the window and tab titles. + if let titleFontName = ghostty.config.windowTitleFontFamily { + window.titlebarFont = NSFont(name: titleFontName, size: NSFont.systemFontSize) + } else { + window.titlebarFont = nil + } } /// Update all surfaces with the focus state. This ensures that libghostty has an accurate view about @@ -261,7 +268,6 @@ class TerminalController: NSWindowController, NSWindowDelegate, if (ghostty.config.macosTitlebarTabs) { window.tabbingMode = .preferred window.titlebarTabs = true - syncAppearance() DispatchQueue.main.async { window.tabbingMode = .automatic } @@ -305,6 +311,9 @@ class TerminalController: NSWindowController, NSWindowDelegate, window.tabGroup?.removeWindow(window) } } + + // Apply any additional appearance-related properties to the new window. + syncAppearance() } // Shows the "+" button in the tab bar, responds to that click. diff --git a/macos/Sources/Features/Terminal/TerminalToolbar.swift b/macos/Sources/Features/Terminal/TerminalToolbar.swift index b0857cb24..7da8de0cc 100644 --- a/macos/Sources/Features/Terminal/TerminalToolbar.swift +++ b/macos/Sources/Features/Terminal/TerminalToolbar.swift @@ -15,7 +15,17 @@ class TerminalToolbar: NSToolbar, NSToolbarDelegate { titleTextField.stringValue = newValue } } - + + var titleFont: NSFont? { + get { + titleTextField.font + } + + set { + titleTextField.font = newValue + } + } + override init(identifier: NSToolbar.Identifier) { super.init(identifier: identifier) diff --git a/macos/Sources/Features/Terminal/TerminalWindow.swift b/macos/Sources/Features/Terminal/TerminalWindow.swift index 5fa06cfb0..339a5fde0 100644 --- a/macos/Sources/Features/Terminal/TerminalWindow.swift +++ b/macos/Sources/Features/Terminal/TerminalWindow.swift @@ -8,6 +8,12 @@ class TerminalWindow: NSWindow { // MARK: - NSWindow + override var title: String { + didSet { + tab.attributedTitle = attributedTitle + } + } + override func becomeKey() { // This is required because the removeTitlebarAccessoryViewControlle hook does not // catch the creation of a new window by "tearing off" a tab from a tabbed window. @@ -20,6 +26,8 @@ class TerminalWindow: NSWindow { if titlebarTabs { updateNewTabButtonOpacity() } + + tab.attributedTitle = attributedTitle } override func resignKey() { @@ -28,6 +36,8 @@ class TerminalWindow: NSWindow { if titlebarTabs { updateNewTabButtonOpacity() } + + tab.attributedTitle = attributedTitle } // MARK: - Titlebar Tabs @@ -39,6 +49,38 @@ class TerminalWindow: NSWindow { } } + // Used to set the titlebar font. + var titlebarFont: NSFont? { + didSet { + titlebarTextField?.font = titlebarFont + tab.attributedTitle = attributedTitle + + if let toolbar = toolbar as? TerminalToolbar { + toolbar.titleFont = titlebarFont + } + } + } + + // Find the NSTextField responsible for displaying the titlebar's title. + private var titlebarTextField: NSTextField? { + guard let titlebarContainer = contentView?.superview?.subviews + .first(where: { $0.className == "NSTitlebarContainerView" }) else { return nil } + guard let titlebarView = titlebarContainer.subviews + .first(where: { $0.className == "NSTitlebarView" }) else { return nil } + return titlebarView.subviews.first(where: { $0 is NSTextField }) as? NSTextField + } + + // Return a styled representation of our title property. + private var attributedTitle: NSAttributedString? { + guard let titlebarFont else { return nil } + + let attributes: [NSAttributedString.Key: Any] = [ + .font: titlebarFont, + .foregroundColor: isKeyWindow ? NSColor.labelColor : NSColor.secondaryLabelColor, + ] + return NSAttributedString(string: title, attributes: attributes) + } + private var windowButtonsBackdrop: WindowButtonsBackdropView? = nil private var windowDragHandle: WindowDragView? = nil private var storedTitlebarBackgroundColor: CGColor? = nil diff --git a/macos/Sources/Ghostty/Ghostty.Config.swift b/macos/Sources/Ghostty/Ghostty.Config.swift index c26b525eb..a444c1d9a 100644 --- a/macos/Sources/Ghostty/Ghostty.Config.swift +++ b/macos/Sources/Ghostty/Ghostty.Config.swift @@ -197,7 +197,16 @@ extension Ghostty { _ = ghostty_config_get(config, &v, key, UInt(key.count)) return v } - + + var windowTitleFontFamily: String? { + guard let config = self.config else { return nil } + var v: UnsafePointer? = nil + let key = "window-title-font-family" + guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return nil } + guard let ptr = v else { return nil } + return String(cString: ptr) + } + var macosTitlebarTabs: Bool { guard let config = self.config else { return false } var v = false; diff --git a/src/config/Config.zig b/src/config/Config.zig index b3b5d446c..d30492ace 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -603,6 +603,11 @@ keybind: Keybinds = .{}, /// borders. @"window-decoration": bool = true, +/// The font that will be used for the application's window and tab titles. +/// +/// This is currently only supported on macOS. +@"window-title-font-family": ?[:0]const u8 = null, + /// The theme to use for the windows. Valid values: /// /// * `auto` - Determine the theme based on the configured terminal