mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Make unselected tabs blend better with background color
This enables the standard effect created by a sytem tab bar, which ensures unselected tabs blend with the window's/titlebar's background color. This also ensures the `windowButtonsBackdrop` view matches the color of the adjacent tab (be it selected or not).
This commit is contained in:
@ -27,7 +27,7 @@ class TerminalWindow: NSWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var windowButtonsBackdrop: NSView? = nil
|
private var windowButtonsBackdrop: WindowButtonsBackdropView? = nil
|
||||||
private var windowDragHandle: WindowDragView? = nil
|
private var windowDragHandle: WindowDragView? = nil
|
||||||
private var storedTitlebarBackgroundColor: CGColor? = nil
|
private var storedTitlebarBackgroundColor: CGColor? = nil
|
||||||
|
|
||||||
@ -51,9 +51,21 @@ class TerminalWindow: NSWindow {
|
|||||||
|
|
||||||
/// This is called by titlebarTabs changing so that we can setup the rest of our window
|
/// This is called by titlebarTabs changing so that we can setup the rest of our window
|
||||||
private func changedTitlebarTabs(to newValue: Bool) {
|
private func changedTitlebarTabs(to newValue: Bool) {
|
||||||
self.titlebarAppearsTransparent = newValue
|
|
||||||
|
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
|
// By hiding the visual effect view, we allow the window's (or titlebar's in this case)
|
||||||
|
// background color to show through. If we were to set `titlebarAppearsTransparent` to true
|
||||||
|
// the selected tab would look fine, but the unselected ones and new tab button backgrounds
|
||||||
|
// would be an opaque color. When the titlebar isn't transparent, however, the system applies
|
||||||
|
// a compositing effect to the unselected tab backgrounds, which makes them blend with the
|
||||||
|
// titlebar's/window's background.
|
||||||
|
if let titlebarContainer = contentView?.superview?.subviews.first(where: {
|
||||||
|
$0.className == "NSTitlebarContainerView"
|
||||||
|
}), let effectView = titlebarContainer.descendants(withClassName: "NSVisualEffectView").first {
|
||||||
|
effectView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
self.titlebarSeparatorStyle = .none
|
||||||
|
|
||||||
// We use the toolbar to anchor our tab bar positions in the titlebar,
|
// We use the toolbar to anchor our tab bar positions in the titlebar,
|
||||||
// so we make sure it's the right size/position, and exists.
|
// so we make sure it's the right size/position, and exists.
|
||||||
self.toolbarStyle = .unifiedCompact
|
self.toolbarStyle = .unifiedCompact
|
||||||
@ -180,7 +192,20 @@ class TerminalWindow: NSWindow {
|
|||||||
self.markHierarchyForLayout(accessoryView)
|
self.markHierarchyForLayout(accessoryView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is called when we open, close, switch, and reorder tabs, at which point we determine if the
|
||||||
|
// first tab in the tab bar is selected. If it is, we make the `windowButtonsBackdrop` color the same
|
||||||
|
// as that of the active tab (i.e. the titlebar's background color), otherwise we make it the same
|
||||||
|
// color as the background of unselected tabs.
|
||||||
|
override func update() {
|
||||||
|
super.update()
|
||||||
|
if let index = windowController?.window?.tabbedWindows?.firstIndex(of: self) {
|
||||||
|
let firstTabIsSelected = index == 0
|
||||||
|
|
||||||
|
windowButtonsBackdrop?.isHighlighted = firstTabIsSelected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func addWindowButtonsBackdrop(titlebarView: NSView, toolbarView: NSView) {
|
private func addWindowButtonsBackdrop(titlebarView: NSView, toolbarView: NSView) {
|
||||||
// If we already made the view, just make sure it's unhidden and correctly placed as a subview.
|
// If we already made the view, just make sure it's unhidden and correctly placed as a subview.
|
||||||
if let view = windowButtonsBackdrop {
|
if let view = windowButtonsBackdrop {
|
||||||
@ -188,32 +213,22 @@ class TerminalWindow: NSWindow {
|
|||||||
view.isHidden = false
|
view.isHidden = false
|
||||||
titlebarView.addSubview(view)
|
titlebarView.addSubview(view)
|
||||||
view.leftAnchor.constraint(equalTo: toolbarView.leftAnchor).isActive = true
|
view.leftAnchor.constraint(equalTo: toolbarView.leftAnchor).isActive = true
|
||||||
view.rightAnchor.constraint(equalTo: toolbarView.leftAnchor, constant: 80).isActive = true
|
view.rightAnchor.constraint(equalTo: toolbarView.leftAnchor, constant: 78).isActive = true
|
||||||
view.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
|
view.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
|
||||||
view.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true
|
view.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let view = NSView()
|
let view = WindowButtonsBackdropView(backgroundColor: storedTitlebarBackgroundColor ?? NSColor.windowBackgroundColor.cgColor)
|
||||||
view.identifier = NSUserInterfaceItemIdentifier("_windowButtonsBackdrop")
|
view.identifier = NSUserInterfaceItemIdentifier("_windowButtonsBackdrop")
|
||||||
titlebarView.addSubview(view)
|
titlebarView.addSubview(view)
|
||||||
|
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.leftAnchor.constraint(equalTo: toolbarView.leftAnchor).isActive = true
|
view.leftAnchor.constraint(equalTo: toolbarView.leftAnchor).isActive = true
|
||||||
view.rightAnchor.constraint(equalTo: toolbarView.leftAnchor, constant: 80).isActive = true
|
view.rightAnchor.constraint(equalTo: toolbarView.leftAnchor, constant: 78).isActive = true
|
||||||
view.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
|
view.topAnchor.constraint(equalTo: toolbarView.topAnchor).isActive = true
|
||||||
view.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true
|
view.heightAnchor.constraint(equalTo: toolbarView.heightAnchor).isActive = true
|
||||||
view.wantsLayer = true
|
|
||||||
|
|
||||||
// This is jank but this makes the background color for light themes on the button
|
|
||||||
// backdrop look MUCH better. I couldn't figure out a perfect color to use that works
|
|
||||||
// for both so we just check the appearance.
|
|
||||||
if effectiveAppearance.name == .aqua {
|
|
||||||
view.layer?.backgroundColor = CGColor(genericGrayGamma2_2Gray: 0.95, alpha: 1)
|
|
||||||
} else {
|
|
||||||
view.layer?.backgroundColor = CGColor(genericGrayGamma2_2Gray: 0.0, alpha: 0.45)
|
|
||||||
}
|
|
||||||
|
|
||||||
windowButtonsBackdrop = view
|
windowButtonsBackdrop = view
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,3 +298,45 @@ fileprivate class WindowDragView: NSView {
|
|||||||
addCursorRect(bounds, cursor: .openHand)
|
addCursorRect(bounds, cursor: .openHand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A view that matches the color of selected and unselected tabs in the adjacent tab bar.
|
||||||
|
fileprivate class WindowButtonsBackdropView: NSView {
|
||||||
|
private let overlayLayer = PlusDarkerBlendingModeLayer()
|
||||||
|
private let backgroundColor: CGColor
|
||||||
|
private let isLightTheme: Bool
|
||||||
|
|
||||||
|
var isHighlighted: Bool = true {
|
||||||
|
didSet {
|
||||||
|
if isLightTheme {
|
||||||
|
overlayLayer.isHidden = isHighlighted
|
||||||
|
layer?.backgroundColor = backgroundColor
|
||||||
|
} else {
|
||||||
|
overlayLayer.isHidden = true
|
||||||
|
layer?.backgroundColor = isHighlighted ? backgroundColor : CGColor(genericGrayGamma2_2Gray: 0.0, alpha: 0.45)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
init(backgroundColor: CGColor) {
|
||||||
|
self.backgroundColor = backgroundColor
|
||||||
|
self.isLightTheme = NSColor(cgColor: backgroundColor)!.isLightColor
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
|
||||||
|
wantsLayer = true
|
||||||
|
|
||||||
|
overlayLayer.frame = layer!.bounds
|
||||||
|
overlayLayer.autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
|
||||||
|
overlayLayer.backgroundColor = CGColor(genericGrayGamma2_2Gray: 0.95, alpha: 1)
|
||||||
|
|
||||||
|
layer?.addSublayer(overlayLayer)
|
||||||
|
|
||||||
|
isHighlighted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user