Update standard title/tab bar when config changes

This commit is contained in:
Pete Schaffner
2024-04-05 15:19:20 +02:00
parent da9df865ef
commit 4ede25dd00
2 changed files with 54 additions and 43 deletions

View File

@ -166,15 +166,9 @@ class TerminalController: NSWindowController, NSWindowDelegate,
private func syncAppearance() { private func syncAppearance() {
guard let window = self.window as? TerminalWindow else { return } guard let window = self.window as? TerminalWindow else { return }
// We match the appearance depending on the lightness/darkness of the let backgroundColor = OSColor(ghostty.config.backgroundColor)
// background color. We have to do this because our titlebars in tabs inherit let appearance = NSAppearance(named: backgroundColor.isLightColor ? .aqua : .darkAqua)
// our background color for the focused tab but use the macOS theme for the window.appearance = appearance
// rest of the titlebar.
if (window.titlebarTabs) {
let color = OSColor(ghostty.config.backgroundColor)
let appearance = NSAppearance(named: color.isLightColor ? .aqua : .darkAqua)
window.appearance = appearance
}
// Set the font for the window and tab titles. // Set the font for the window and tab titles.
if let titleFontName = ghostty.config.windowTitleFontFamily { if let titleFontName = ghostty.config.windowTitleFontFamily {
@ -182,6 +176,10 @@ class TerminalController: NSWindowController, NSWindowDelegate,
} else { } else {
window.titlebarFont = nil window.titlebarFont = nil
} }
window.backgroundColor = backgroundColor
window.titlebarColor = backgroundColor.withAlphaComponent(ghostty.config.backgroundOpacity)
window.updateToolbar()
} }
/// Update all surfaces with the focus state. This ensures that libghostty has an accurate view about /// Update all surfaces with the focus state. This ensures that libghostty has an accurate view about
@ -254,10 +252,11 @@ class TerminalController: NSWindowController, NSWindowDelegate,
window.center() window.center()
// Set the background color of the window // Set the background color of the window
window.backgroundColor = NSColor(ghostty.config.backgroundColor) let backgroundColor = NSColor(ghostty.config.backgroundColor)
window.backgroundColor = backgroundColor
// This makes sure our titlebar renders correctly when there is a transparent background // This makes sure our titlebar renders correctly when there is a transparent background
window.titlebarOpacity = ghostty.config.backgroundOpacity window.titlebarColor = backgroundColor.withAlphaComponent(ghostty.config.backgroundOpacity)
// Handle titlebar tabs config option. Something about what we do while setting up the // Handle titlebar tabs config option. Something about what we do while setting up the
// titlebar tabs interferes with the window restore process unless window.tabbingMode // titlebar tabs interferes with the window restore process unless window.tabbingMode

View File

@ -4,14 +4,14 @@ class TerminalWindow: NSWindow {
@objc dynamic var surfaceIsZoomed: Bool = false @objc dynamic var surfaceIsZoomed: Bool = false
@objc dynamic var keyEquivalent: String = "" @objc dynamic var keyEquivalent: String = ""
var titlebarOpacity: CGFloat = 1 { lazy var titlebarColor: NSColor = backgroundColor {
didSet { didSet {
guard let titlebarContainer = contentView?.superview?.subviews.first(where: { guard let titlebarContainer = contentView?.superview?.subviews.first(where: {
$0.className == "NSTitlebarContainerView" $0.className == "NSTitlebarContainerView"
}) else { return } }) else { return }
titlebarContainer.wantsLayer = true titlebarContainer.wantsLayer = true
titlebarContainer.layer?.backgroundColor = backgroundColor.withAlphaComponent(titlebarOpacity).cgColor titlebarContainer.layer?.backgroundColor = titlebarColor.cgColor
} }
} }
@ -182,6 +182,12 @@ class TerminalWindow: NSWindow {
// MARK: - // MARK: -
func updateToolbar() {
newTabButtonImageLayer = nil
effectViewIsHidden = false
}
private var newTabButtonImage: NSImage? = nil
private var newTabButtonImageLayer: VibrantLayer? = nil private var newTabButtonImageLayer: VibrantLayer? = nil
// Since we are coloring the new tab button's image, it doesn't respond to the // Since we are coloring the new tab button's image, it doesn't respond to the
@ -209,7 +215,12 @@ class TerminalWindow: NSWindow {
guard let newTabButtonImageView: NSImageView = newTabButton.subviews.first(where: { guard let newTabButtonImageView: NSImageView = newTabButton.subviews.first(where: {
$0 as? NSImageView != nil $0 as? NSImageView != nil
}) as? NSImageView else { return } }) as? NSImageView else { return }
guard let newTabButtonImage = newTabButtonImageView.image else { return }
if newTabButtonImage == nil {
newTabButtonImage = newTabButtonImageView.image
}
guard let newTabButtonImage else { return }
let isLightTheme = backgroundColor.isLightColor let isLightTheme = backgroundColor.isLightColor
@ -242,8 +253,6 @@ class TerminalWindow: NSWindow {
backgroundColor.luminance < 0.05 backgroundColor.luminance < 0.05
} }
lazy var backgroundColorWithOpacity: NSColor = backgroundColor.withAlphaComponent(titlebarOpacity)
private func updateTabsForVeryDarkBackgrounds() { private func updateTabsForVeryDarkBackgrounds() {
guard hasVeryDarkBackground else { return } guard hasVeryDarkBackground else { return }
@ -255,13 +264,15 @@ class TerminalWindow: NSWindow {
guard let activeTabBackgroundView = titlebarContainer.firstDescendant(withClassName: "NSTabButton")?.superview?.subviews.last?.firstDescendant(withID: "_backgroundView") guard let activeTabBackgroundView = titlebarContainer.firstDescendant(withClassName: "NSTabButton")?.superview?.subviews.last?.firstDescendant(withID: "_backgroundView")
else { return } else { return }
activeTabBackgroundView.layer?.backgroundColor = backgroundColorWithOpacity.cgColor activeTabBackgroundView.layer?.backgroundColor = titlebarColor.cgColor
titlebarContainer.layer?.backgroundColor = backgroundColorWithOpacity.highlight(withLevel: 0.14)?.cgColor titlebarContainer.layer?.backgroundColor = titlebarColor.highlight(withLevel: 0.14)?.cgColor
} else { } else {
titlebarContainer.layer?.backgroundColor = backgroundColorWithOpacity.cgColor titlebarContainer.layer?.backgroundColor = titlebarColor.cgColor
} }
} }
// MARK: - Split zooming
private func updateResetZoomTitlebarButtonVisibility() { private func updateResetZoomTitlebarButtonVisibility() {
guard let tabGroup, let resetZoomTitlebarAccessoryViewController else { return } guard let tabGroup, let resetZoomTitlebarAccessoryViewController else { return }
@ -282,24 +293,6 @@ class TerminalWindow: NSWindow {
} }
} }
// We have to regenerate a toolbar when the titlebar tabs setting changes since our
// custom toolbar conditionally generates the items based on this setting. I tried to
// invalidate the toolbar items and force a refresh, but as far as I can tell that
// isn't possible.
private func generateToolbar() {
let terminalToolbar = TerminalToolbar(identifier: "Toolbar")
toolbar = terminalToolbar
toolbarStyle = .unifiedCompact
if let resetZoomItem = terminalToolbar.items.first(where: { $0.itemIdentifier == .resetZoom }) {
resetZoomItem.view = resetZoomToolbarButton
resetZoomItem.view!.removeConstraints(resetZoomItem.view!.constraints)
resetZoomItem.view!.widthAnchor.constraint(equalToConstant: 22).isActive = true
resetZoomItem.view!.heightAnchor.constraint(equalToConstant: 20).isActive = true
}
updateResetZoomTitlebarButtonVisibility()
}
private func generateResetZoomButton() -> NSButton { private func generateResetZoomButton() -> NSButton {
let button = NSButton() let button = NSButton()
button.target = nil button.target = nil
@ -356,6 +349,24 @@ class TerminalWindow: NSWindow {
} }
} }
// We have to regenerate a toolbar when the titlebar tabs setting changes since our
// custom toolbar conditionally generates the items based on this setting. I tried to
// invalidate the toolbar items and force a refresh, but as far as I can tell that
// isn't possible.
func generateToolbar() {
let terminalToolbar = TerminalToolbar(identifier: "Toolbar")
toolbar = terminalToolbar
toolbarStyle = .unifiedCompact
if let resetZoomItem = terminalToolbar.items.first(where: { $0.itemIdentifier == .resetZoom }) {
resetZoomItem.view = resetZoomToolbarButton
resetZoomItem.view!.removeConstraints(resetZoomItem.view!.constraints)
resetZoomItem.view!.widthAnchor.constraint(equalToConstant: 22).isActive = true
resetZoomItem.view!.heightAnchor.constraint(equalToConstant: 20).isActive = true
}
updateResetZoomTitlebarButtonVisibility()
}
// Find the NSTextField responsible for displaying the titlebar's title. // Find the NSTextField responsible for displaying the titlebar's title.
private var titlebarTextField: NSTextField? { private var titlebarTextField: NSTextField? {
guard let titlebarContainer = contentView?.superview?.subviews guard let titlebarContainer = contentView?.superview?.subviews
@ -382,14 +393,15 @@ class TerminalWindow: NSWindow {
// The tab bar controller ID from macOS // The tab bar controller ID from macOS
static private let TabBarController = NSUserInterfaceItemIdentifier("_tabBarController") static private let TabBarController = NSUserInterfaceItemIdentifier("_tabBarController")
// Look through the titlebar's view hierarchy and hide any of the internal
// views used to create a separator between the title/toolbar and unselected
// tabs in the tab bar.
override func updateConstraintsIfNeeded() { override func updateConstraintsIfNeeded() {
super.updateConstraintsIfNeeded() super.updateConstraintsIfNeeded()
// For titlebar tabs, we want to hide the separator view so that we get rid hideTitleBarSeparators()
// of an aesthetically unpleasing shadow. }
// For titlebar tabs, we want to hide the separator view so that we get rid
// of an aesthetically unpleasing shadow.
private func hideTitleBarSeparators() {
guard titlebarTabs else { return } guard titlebarTabs else { return }
guard let titlebarContainer = contentView?.superview?.subviews.first(where: { guard let titlebarContainer = contentView?.superview?.subviews.first(where: {
@ -589,7 +601,7 @@ fileprivate class WindowButtonsBackdropView: NSView {
layer?.backgroundColor = .clear layer?.backgroundColor = .clear
} else { } else {
let systemOverlayColor = NSColor(cgColor: CGColor(genericGrayGamma2_2Gray: 0.0, alpha: 0.45))! let systemOverlayColor = NSColor(cgColor: CGColor(genericGrayGamma2_2Gray: 0.0, alpha: 0.45))!
let titlebarBackgroundColor = terminalWindow.backgroundColorWithOpacity.blended(withFraction: 1, of: systemOverlayColor) let titlebarBackgroundColor = terminalWindow.titlebarColor.blended(withFraction: 1, of: systemOverlayColor)
let highlightedColor = terminalWindow.hasVeryDarkBackground ? terminalWindow.backgroundColor : .clear let highlightedColor = terminalWindow.hasVeryDarkBackground ? terminalWindow.backgroundColor : .clear
let backgroundColor = terminalWindow.hasVeryDarkBackground ? titlebarBackgroundColor : systemOverlayColor let backgroundColor = terminalWindow.hasVeryDarkBackground ? titlebarBackgroundColor : systemOverlayColor