mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-19 20:18:07 +00:00
macOS: fix title bar clipping custom font
The #9168 fix is no longer needed, since the frame is now higher than the actual glyph.
This commit is contained in:
@@ -1278,6 +1278,13 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
|
||||
|
||||
// Whenever we resize save our last position and size for the next start.
|
||||
LastWindowPosition.shared.save(window)
|
||||
|
||||
if let window = self.window as? TerminalWindow {
|
||||
// Expand the title frame to new width.
|
||||
// This is needed because when the new window size becomes bigger,
|
||||
// window's title will be clipped again.
|
||||
window.syncWindowTitleAppearance()
|
||||
}
|
||||
}
|
||||
|
||||
func windowDidBecomeMain(_ notification: Notification) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import AppKit
|
||||
import Combine
|
||||
import SwiftUI
|
||||
import GhosttyKit
|
||||
|
||||
@@ -277,12 +278,6 @@ class TerminalWindow: NSWindow {
|
||||
/// added.
|
||||
static let tabBarIdentifier: NSUserInterfaceItemIdentifier = .init("_ghosttyTabBar")
|
||||
|
||||
var hasMoreThanOneTabs: Bool {
|
||||
/// accessing ``tabGroup?.windows`` here
|
||||
/// will cause other edge cases, be careful
|
||||
(tabbedWindows?.count ?? 0) > 1
|
||||
}
|
||||
|
||||
func isTabBar(_ childViewController: NSTitlebarAccessoryViewController) -> Bool {
|
||||
if childViewController.identifier == nil {
|
||||
// The good case
|
||||
@@ -396,12 +391,9 @@ class TerminalWindow: NSWindow {
|
||||
// Whenever we change the window title we must also update our
|
||||
// tab title if we're using custom fonts.
|
||||
tab.attributedTitle = attributedTitle
|
||||
/// We also needs to update this here, just in case
|
||||
/// the value is not what we want
|
||||
///
|
||||
/// Check ``titlebarFont`` down below
|
||||
/// to see why we need to check `hasMoreThanOneTabs` here
|
||||
titlebarTextField?.usesSingleLineMode = !hasMoreThanOneTabs
|
||||
guard title != oldValue else { return }
|
||||
|
||||
syncWindowTitleAppearance()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,25 +401,28 @@ class TerminalWindow: NSWindow {
|
||||
var titlebarFont: NSFont? {
|
||||
didSet {
|
||||
let font = titlebarFont ?? NSFont.titleBarFont(ofSize: NSFont.systemFontSize)
|
||||
|
||||
titlebarTextField?.font = font
|
||||
/// We check `hasMoreThanOneTabs` here because the system
|
||||
/// may copy this setting to the tab’s text field at some point(e.g. entering/exiting fullscreen),
|
||||
/// which can cause the title to be vertically misaligned (shifted downward).
|
||||
///
|
||||
/// This behaviour is the opposite of what happens in the title bar’s text field, which is quite odd...
|
||||
titlebarTextField?.usesSingleLineMode = !hasMoreThanOneTabs
|
||||
tab.attributedTitle = attributedTitle
|
||||
|
||||
// We need to call this every time the font is set,
|
||||
// after entering or exiting fullscreen, or other cases,
|
||||
// AppKit will reset the font.
|
||||
syncWindowTitleAppearance(font: font)
|
||||
}
|
||||
}
|
||||
|
||||
// Find the NSTextField responsible for displaying the titlebar's title.
|
||||
private var titlebarTextField: NSTextField? {
|
||||
titlebarContainer?
|
||||
// Find the array of NSTextField responsible for displaying the titlebar's title.
|
||||
// In fullscreen mode, there'll be two of them.
|
||||
private var titlebarTextFields: [NSTextField] {
|
||||
(titlebarContainer?
|
||||
.firstDescendant(withClassName: "NSTitlebarView")?
|
||||
.firstDescendant(withClassName: "NSTextField") as? NSTextField
|
||||
.descendants(withClassName: "NSTextField")
|
||||
.compactMap { $0 as? NSTextField } ?? [])
|
||||
.filter({ $0.superview?.className == "NSTitlebarView" })
|
||||
}
|
||||
|
||||
// Cancellables for the frame change of the text fields in the titlebar.
|
||||
private var titlebarTextFieldFrameCancellables = Set<AnyCancellable>()
|
||||
|
||||
// Return a styled representation of our title property.
|
||||
var attributedTitle: NSAttributedString? {
|
||||
guard let titlebarFont = titlebarFont else { return nil }
|
||||
@@ -463,6 +458,65 @@ class TerminalWindow: NSWindow {
|
||||
|
||||
// MARK: Positioning And Styling
|
||||
|
||||
/// Update titlebarTextField's size and font
|
||||
func syncWindowTitleAppearance(font: NSFont? = nil) {
|
||||
titlebarTextFields.forEach { field in
|
||||
if let font {
|
||||
field.font = font
|
||||
}
|
||||
}
|
||||
|
||||
titlebarTextFieldFrameCancellables.removeAll()
|
||||
|
||||
// macOS 15 doesn't seem to need to adjust the frame.
|
||||
//
|
||||
// When using custom font, we always expand the frame to
|
||||
// show the text properly.
|
||||
//
|
||||
// AppKit will relayout the frame when the font changes, that's
|
||||
// why we need this hack in the first place.
|
||||
guard #available(macOS 26.0, *), titlebarFont != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
titlebarTextFields.forEach { field in
|
||||
setWindowTitleFrameSize(field)
|
||||
}
|
||||
|
||||
// We need to observe changes to make the frame correct in some cases:
|
||||
//
|
||||
// 1. Entering fullscreen mode.
|
||||
// > Updating the frame when it's hidden doesn't seem to work.
|
||||
// 2. Exiting fullscreen mode.
|
||||
// 3. Resizing the window.
|
||||
// 3. Maybe more...
|
||||
|
||||
titlebarTextFields.forEach { field in
|
||||
field.postsFrameChangedNotifications = true
|
||||
NotificationCenter.default
|
||||
.publisher(for: NSView.frameDidChangeNotification, object: field)
|
||||
.compactMap { $0.object as? NSTextField }
|
||||
.sink { [weak self] in
|
||||
self?.setWindowTitleFrameSize($0)
|
||||
}
|
||||
.store(in: &titlebarTextFieldFrameCancellables)
|
||||
}
|
||||
}
|
||||
|
||||
private func setWindowTitleFrameSize(_ textfield: NSTextField) {
|
||||
guard let superview = textfield.superview else { return }
|
||||
|
||||
// Button group size estimate: 92.
|
||||
// Make the available space a little bit smaller.
|
||||
let fittingSize = textfield.sizeThatFits(superview.bounds.insetBy(dx: 92/2 + 6, dy: 0).size)
|
||||
// We make the frame a little bit higher so fixed-width fonts can
|
||||
// align center vertically as well.
|
||||
let properSize = CGSize(width: fittingSize.width, height: fittingSize.height * 1.1)
|
||||
|
||||
guard textfield.frame.size != properSize else { return }
|
||||
textfield.frame.size = properSize
|
||||
}
|
||||
|
||||
/// This is called by the controller when there is a need to reset the window appearance.
|
||||
func syncAppearance(_ surfaceConfig: Ghostty.SurfaceView.DerivedConfig) {
|
||||
// If our window is not visible, then we do nothing. Some things such as blurring
|
||||
|
||||
Reference in New Issue
Block a user