macOS: Fix more `macos-titlebar-style` related issues (#9163)

Ghosty is active will result in similar nastiness.

https://github.com/user-attachments/assets/fcd7761e-a521-4382-8d7a-9d93dc0806bc

- [Sequoia/Ventura] Fix flickering new tab icon, and it also didn't
respond to window's key status change correctly
- [Sequoia/Ventura] Fix after changing appearance, tab bar may disappear
or have inconsistent background colour
- Fix initial tint of reset zoom button on Sequoia/Ventura with
`macos-titlebar-style=tabs` and all `native/transparent` titlebars
- Fix title alignment with custom font with `native/transparent`
titlebar
1.2.x
Xiangbao Meng 2025-10-12 16:31:42 +02:00 committed by Mitchell Hashimoto
parent 537b304cd6
commit 5c9ceab0bf
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
2 changed files with 43 additions and 38 deletions

View File

@ -124,6 +124,12 @@ class TerminalWindow: NSWindow {
} else {
tabBarDidDisappear()
}
viewModel.isMainWindow = true
}
override func resignMain() {
super.resignMain()
viewModel.isMainWindow = false
}
override func mergeAllWindows(_ sender: Any?) {
@ -260,7 +266,7 @@ class TerminalWindow: NSWindow {
button.isBordered = false
button.allowsExpansionToolTips = true
button.toolTip = "Reset Zoom"
button.contentTintColor = .controlAccentColor
button.contentTintColor = isMainWindow ? .controlAccentColor : .secondaryLabelColor
button.state = .on
button.image = NSImage(named:"ResetZoom")
button.frame = NSRect(x: 0, y: 0, width: 20, height: 20)
@ -286,6 +292,7 @@ class TerminalWindow: NSWindow {
let font = titlebarFont ?? NSFont.titleBarFont(ofSize: NSFont.systemFontSize)
titlebarTextField?.font = font
titlebarTextField?.usesSingleLineMode = true
tab.attributedTitle = attributedTitle
}
}
@ -467,6 +474,7 @@ extension TerminalWindow {
class ViewModel: ObservableObject {
@Published var isSurfaceZoomed: Bool = false
@Published var hasToolbar: Bool = false
@Published var isMainWindow: Bool = true
}
struct ResetZoomAccessoryView: View {
@ -488,7 +496,7 @@ extension TerminalWindow {
VStack {
Button(action: action) {
Image("ResetZoom")
.foregroundColor(.accentColor)
.foregroundColor(viewModel.isMainWindow ? .accentColor : .secondary)
}
.buttonStyle(.plain)
.help("Reset Split Zoom")

View File

@ -141,6 +141,7 @@ class TitlebarTabsVenturaTerminalWindow: TerminalWindow {
super.syncAppearance(surfaceConfig)
// Update our window light/darkness based on our updated background color
let themeChanged = isLightTheme != OSColor(surfaceConfig.backgroundColor).isLightColor
isLightTheme = OSColor(surfaceConfig.backgroundColor).isLightColor
// Update our titlebar color
@ -150,7 +151,7 @@ class TitlebarTabsVenturaTerminalWindow: TerminalWindow {
titlebarColor = derivedConfig.backgroundColor.withAlphaComponent(derivedConfig.backgroundOpacity)
}
if (isOpaque) {
if (isOpaque || themeChanged) {
// If there is transparency, calling this will make the titlebar opaque
// so we only call this if we are opaque.
updateTabBar()
@ -183,41 +184,33 @@ class TitlebarTabsVenturaTerminalWindow: TerminalWindow {
// so we need to do it manually.
private func updateNewTabButtonOpacity() {
guard let newTabButton: NSButton = titlebarContainer?.firstDescendant(withClassName: "NSTabBarNewTabButton") as? NSButton else { return }
guard let newTabButtonImageView: NSImageView = newTabButton.subviews.first(where: {
$0 as? NSImageView != nil
}) as? NSImageView else { return }
guard let newTabButtonImageView = newTabButton.firstDescendant(withClassName: "NSImageView") as? NSImageView else { return }
newTabButtonImageView.alphaValue = isKeyWindow ? 1 : 0.5
}
// Color the new tab button's image to match the color of the tab title/keyboard shortcut labels,
// just as it does in the stock tab bar.
/// Update: This method only add a vibrant overlay now,
/// since the image itself supports light/dark tint,
/// and system could restore it any time,
/// altering it will only cause maintenance burden for us.
///
/// And if we hide original image,
/// ``updateNewTabButtonOpacity`` will not work
///
/// ~~Color the new tab button's image to match the color of the tab title/keyboard shortcut labels,~~
/// ~~just as it does in the stock tab bar.~~
private func updateNewTabButtonImage() {
guard let newTabButton: NSButton = titlebarContainer?.firstDescendant(withClassName: "NSTabBarNewTabButton") as? NSButton else { return }
guard let newTabButtonImageView: NSImageView = newTabButton.subviews.first(where: {
$0 as? NSImageView != nil
}) as? NSImageView else { return }
guard let newTabButtonImageView = newTabButton.firstDescendant(withClassName: "NSImageView") as? NSImageView else { return }
guard let newTabButtonImage = newTabButtonImageView.image else { return }
let imageLayer = newTabButtonImageLayer ?? VibrantLayer(forAppearance: isLightTheme ? .light : .dark)!
imageLayer.frame = NSRect(origin: NSPoint(x: newTabButton.bounds.midX - newTabButtonImage.size.width/2, y: newTabButton.bounds.midY - newTabButtonImage.size.height/2), size: newTabButtonImage.size)
imageLayer.contentsGravity = .resizeAspect
imageLayer.opacity = 0.5
if newTabButtonImageLayer == nil {
let fillColor: NSColor = isLightTheme ? .black.withAlphaComponent(0.85) : .white.withAlphaComponent(0.85)
let newImage = NSImage(size: newTabButtonImage.size, flipped: false) { rect in
newTabButtonImage.draw(in: rect)
fillColor.setFill()
rect.fill(using: .sourceAtop)
return true
}
let imageLayer = VibrantLayer(forAppearance: isLightTheme ? .light : .dark)!
imageLayer.frame = NSRect(origin: NSPoint(x: newTabButton.bounds.midX - newTabButtonImage.size.width/2, y: newTabButton.bounds.midY - newTabButtonImage.size.height/2), size: newTabButtonImage.size)
imageLayer.contentsGravity = .resizeAspect
imageLayer.contents = newImage
imageLayer.opacity = 0.5
newTabButtonImageLayer = imageLayer
newTabButtonImageLayer = imageLayer
}
newTabButtonImageView.isHidden = true
newTabButton.layer?.sublayers?.first(where: { $0.className == "VibrantLayer" })?.removeFromSuperlayer()
newTabButton.layer?.addSublayer(newTabButtonImageLayer!)
}
@ -448,6 +441,13 @@ class TitlebarTabsVenturaTerminalWindow: TerminalWindow {
}
private func addWindowButtonsBackdrop(titlebarView: NSView, toolbarView: NSView) {
guard windowButtonsBackdrop?.superview != titlebarView else {
/// replacing existing backdrop aggressively
/// may cause incorrect hierarchy
///
/// because multiple windows are adding this around the 'same time'
return
}
windowButtonsBackdrop?.removeFromSuperview()
windowButtonsBackdrop = nil
@ -466,16 +466,11 @@ class TitlebarTabsVenturaTerminalWindow: TerminalWindow {
private func addWindowDragHandle(titlebarView: NSView, toolbarView: NSView) {
// If we already made the view, just make sure it's unhidden and correctly placed as a subview.
if let view = windowDragHandle {
view.removeFromSuperview()
view.isHidden = false
titlebarView.superview?.addSubview(view)
view.leftAnchor.constraint(equalTo: toolbarView.leftAnchor).isActive = true
view.rightAnchor.constraint(equalTo: toolbarView.rightAnchor).isActive = true
view.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: toolbarView.topAnchor, constant: 12).isActive = true
guard windowDragHandle?.superview != titlebarView.superview else {
// similar to `addWindowButtonsBackdrop`
return
}
windowDragHandle?.removeFromSuperview()
let view = WindowDragView()
view.identifier = NSUserInterfaceItemIdentifier("_windowDragHandle")
@ -536,7 +531,10 @@ fileprivate class WindowButtonsBackdropView: NSView {
// This must be weak because the window has this view. Otherwise
// a retain cycle occurs.
private weak var terminalWindow: TitlebarTabsVenturaTerminalWindow?
private let isLightTheme: Bool
private var isLightTheme: Bool {
// using up-to-date value from hosting window directly
terminalWindow?.isLightTheme ?? false
}
private let overlayLayer = VibrantLayer()
var isHighlighted: Bool = true {
@ -565,7 +563,6 @@ fileprivate class WindowButtonsBackdropView: NSView {
init(window: TitlebarTabsVenturaTerminalWindow) {
self.terminalWindow = window
self.isLightTheme = window.isLightTheme
super.init(frame: .zero)