mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-06 07:38:21 +00:00
macOS: refine window tint for liquid glass (#11018)
Depends on #11030 - Update constraints of `TerminalGlassView` - Use `TerminalViewContainer.DerivedConfig` to map styling properties - Add TerminalViewContainerTests - Instead of using delay, now the view updates are explicitly called by window controllers
This commit is contained in:
@@ -137,11 +137,9 @@ class QuickTerminalController: BaseTerminalController {
|
||||
}
|
||||
|
||||
// Setup our content
|
||||
window.contentView = TerminalViewContainer(
|
||||
ghostty: self.ghostty,
|
||||
viewModel: self,
|
||||
delegate: self
|
||||
)
|
||||
window.contentView = TerminalViewContainer {
|
||||
TerminalView(ghostty: ghostty, viewModel: self, delegate: self)
|
||||
}
|
||||
|
||||
// Clear out our frame at this point, the fixup from above is complete.
|
||||
if let qtWindow = window as? QuickTerminalWindow {
|
||||
@@ -161,6 +159,8 @@ class QuickTerminalController: BaseTerminalController {
|
||||
// applies if we can be seen.
|
||||
guard visible else { return }
|
||||
|
||||
terminalViewContainer?.updateGlassTintOverlay(isKeyWindow: true)
|
||||
|
||||
// Re-hide the dock if we were hiding it before.
|
||||
hiddenDock?.hide()
|
||||
}
|
||||
@@ -174,6 +174,8 @@ class QuickTerminalController: BaseTerminalController {
|
||||
// ensures we don't run logic twice.
|
||||
guard visible else { return }
|
||||
|
||||
terminalViewContainer?.updateGlassTintOverlay(isKeyWindow: false)
|
||||
|
||||
// We don't animate out if there is a modal sheet being shown currently.
|
||||
// This lets us show alerts without causing the window to disappear.
|
||||
guard window?.attachedSheet == nil else { return }
|
||||
@@ -706,6 +708,8 @@ class QuickTerminalController: BaseTerminalController {
|
||||
self.derivedConfig = DerivedConfig(config)
|
||||
|
||||
syncAppearance()
|
||||
|
||||
terminalViewContainer?.ghosttyConfigDidChange(config, preferredBackgroundColor: nil)
|
||||
}
|
||||
|
||||
@objc private func onNewTab(notification: SwiftUI.Notification) {
|
||||
|
||||
@@ -585,6 +585,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
|
||||
|
||||
// Call this last in case it uses any of the properties above.
|
||||
window.syncAppearance(surfaceConfig)
|
||||
terminalViewContainer?.ghosttyConfigDidChange(ghostty.config, preferredBackgroundColor: window.preferredBackgroundColor)
|
||||
}
|
||||
|
||||
/// Adjusts the given frame for the configured window position.
|
||||
@@ -1024,11 +1025,9 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
|
||||
}
|
||||
|
||||
// Initialize our content view to the SwiftUI root
|
||||
window.contentView = TerminalViewContainer(
|
||||
ghostty: self.ghostty,
|
||||
viewModel: self,
|
||||
delegate: self,
|
||||
)
|
||||
window.contentView = TerminalViewContainer {
|
||||
TerminalView(ghostty: ghostty, viewModel: self, delegate: self)
|
||||
}
|
||||
|
||||
// If we have a default size, we want to apply it.
|
||||
if let defaultSize {
|
||||
@@ -1148,6 +1147,12 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
|
||||
super.windowDidBecomeKey(notification)
|
||||
self.relabelTabs()
|
||||
self.fixTabBar()
|
||||
terminalViewContainer?.updateGlassTintOverlay(isKeyWindow: true)
|
||||
}
|
||||
|
||||
override func windowDidResignKey(_ notification: Notification) {
|
||||
super.windowDidResignKey(notification)
|
||||
terminalViewContainer?.updateGlassTintOverlay(isKeyWindow: false)
|
||||
}
|
||||
|
||||
override func windowDidMove(_ notification: Notification) {
|
||||
|
||||
@@ -3,20 +3,27 @@ import SwiftUI
|
||||
|
||||
/// Use this container to achieve a glass effect at the window level.
|
||||
/// Modifying `NSThemeFrame` can sometimes be unpredictable.
|
||||
class TerminalViewContainer<ViewModel: TerminalViewModel>: NSView {
|
||||
class TerminalViewContainer: NSView {
|
||||
private let terminalView: NSView
|
||||
|
||||
/// Combined glass effect and inactive tint overlay view
|
||||
private var glassEffectView: NSView?
|
||||
private var derivedConfig: DerivedConfig
|
||||
private(set) var glassEffectView: NSView?
|
||||
private var derivedConfig: DerivedConfig?
|
||||
|
||||
init(ghostty: Ghostty.App, viewModel: ViewModel, delegate: (any TerminalViewDelegate)? = nil) {
|
||||
self.derivedConfig = DerivedConfig(config: ghostty.config)
|
||||
self.terminalView = NSHostingView(rootView: TerminalView(
|
||||
ghostty: ghostty,
|
||||
viewModel: viewModel,
|
||||
delegate: delegate
|
||||
))
|
||||
var windowThemeFrameView: NSView? {
|
||||
window?.contentView?.superview
|
||||
}
|
||||
|
||||
var windowCornerRadius: CGFloat? {
|
||||
guard let window, window.responds(to: Selector(("_cornerRadius"))) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return window.value(forKey: "_cornerRadius") as? CGFloat
|
||||
}
|
||||
|
||||
init<Root: View>(@ViewBuilder rootView: () -> Root) {
|
||||
self.terminalView = NSHostingView(rootView: rootView())
|
||||
super.init(frame: .zero)
|
||||
setup()
|
||||
}
|
||||
@@ -26,10 +33,6 @@ class TerminalViewContainer<ViewModel: TerminalViewModel>: NSView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
/// To make ``TerminalController/DefaultSize/contentIntrinsicSize``
|
||||
/// work in ``TerminalController/windowDidLoad()``,
|
||||
/// we override this to provide the correct size.
|
||||
@@ -46,27 +49,6 @@ class TerminalViewContainer<ViewModel: TerminalViewModel>: NSView {
|
||||
terminalView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
terminalView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
])
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(ghosttyConfigDidChange(_:)),
|
||||
name: .ghosttyConfigDidChange,
|
||||
object: nil
|
||||
)
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(windowDidBecomeKey(_:)),
|
||||
name: NSWindow.didBecomeKeyNotification,
|
||||
object: nil
|
||||
)
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(windowDidResignKey(_:)),
|
||||
name: NSWindow.didResignKeyNotification,
|
||||
object: nil
|
||||
)
|
||||
}
|
||||
|
||||
override func viewDidMoveToWindow() {
|
||||
@@ -84,29 +66,22 @@ class TerminalViewContainer<ViewModel: TerminalViewModel>: NSView {
|
||||
guard let config = notification.userInfo?[
|
||||
Notification.Name.GhosttyConfigChangeKey
|
||||
] as? Ghostty.Config else { return }
|
||||
let newValue = DerivedConfig(config: config)
|
||||
ghosttyConfigDidChange(config, preferredBackgroundColor: (window as? TerminalWindow)?.preferredBackgroundColor)
|
||||
}
|
||||
|
||||
func ghosttyConfigDidChange(_ config: Ghostty.Config, preferredBackgroundColor: NSColor?) {
|
||||
let newValue = DerivedConfig(config: config, preferredBackgroundColor: preferredBackgroundColor, cornerRadius: windowCornerRadius)
|
||||
guard newValue != derivedConfig else { return }
|
||||
derivedConfig = newValue
|
||||
|
||||
// Add some delay to wait TerminalWindow to update first to ensure
|
||||
// that some of our properties are updated. This is a HACK to ensure
|
||||
// light/dark themes work, and we will come up with a better way
|
||||
// in the future.
|
||||
DispatchQueue.main.asyncAfter(
|
||||
deadline: .now() + 0.05,
|
||||
execute: updateGlassEffectIfNeeded)
|
||||
DispatchQueue.main.async(execute: updateGlassEffectIfNeeded)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func windowDidBecomeKey(_ notification: Notification) {
|
||||
guard let window = notification.object as? NSWindow,
|
||||
window == self.window else { return }
|
||||
updateGlassTintOverlay(isKeyWindow: true)
|
||||
}
|
||||
// MARK: - BaseTerminalController + terminalViewContainer
|
||||
|
||||
@objc private func windowDidResignKey(_ notification: Notification) {
|
||||
guard let window = notification.object as? NSWindow,
|
||||
window == self.window else { return }
|
||||
updateGlassTintOverlay(isKeyWindow: false)
|
||||
extension BaseTerminalController {
|
||||
var terminalViewContainer: TerminalViewContainer? {
|
||||
window?.contentView as? TerminalViewContainer
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +93,8 @@ class TerminalViewContainer<ViewModel: TerminalViewModel>: NSView {
|
||||
@available(macOS 26.0, *)
|
||||
private class TerminalGlassView: NSView {
|
||||
private let glassEffectView: NSGlassEffectView
|
||||
private var glassTopConstraint: NSLayoutConstraint?
|
||||
private var topConstraint: NSLayoutConstraint!
|
||||
private let tintOverlay: NSView
|
||||
private var tintTopConstraint: NSLayoutConstraint?
|
||||
|
||||
init(topOffset: CGFloat) {
|
||||
self.glassEffectView = NSGlassEffectView()
|
||||
@@ -132,36 +106,29 @@ private class TerminalGlassView: NSView {
|
||||
// Glass effect view fills this view.
|
||||
glassEffectView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(glassEffectView)
|
||||
glassTopConstraint = glassEffectView.topAnchor.constraint(
|
||||
topConstraint = glassEffectView.topAnchor.constraint(
|
||||
equalTo: topAnchor,
|
||||
constant: topOffset
|
||||
)
|
||||
if let glassTopConstraint {
|
||||
NSLayoutConstraint.activate([
|
||||
glassTopConstraint,
|
||||
glassEffectView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
glassEffectView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
glassEffectView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
])
|
||||
}
|
||||
NSLayoutConstraint.activate([
|
||||
topConstraint,
|
||||
glassEffectView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
glassEffectView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
glassEffectView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
])
|
||||
|
||||
// Tint overlay sits above the glass effect.
|
||||
tintOverlay.translatesAutoresizingMaskIntoConstraints = false
|
||||
tintOverlay.wantsLayer = true
|
||||
tintOverlay.alphaValue = 0
|
||||
addSubview(tintOverlay, positioned: .above, relativeTo: glassEffectView)
|
||||
tintTopConstraint = tintOverlay.topAnchor.constraint(
|
||||
equalTo: topAnchor,
|
||||
constant: topOffset
|
||||
)
|
||||
if let tintTopConstraint {
|
||||
NSLayoutConstraint.activate([
|
||||
tintTopConstraint,
|
||||
tintOverlay.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
tintOverlay.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
tintOverlay.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
tintOverlay.topAnchor.constraint(equalTo: glassEffectView.topAnchor),
|
||||
tintOverlay.leadingAnchor.constraint(equalTo: glassEffectView.leadingAnchor),
|
||||
tintOverlay.bottomAnchor.constraint(equalTo: glassEffectView.bottomAnchor),
|
||||
tintOverlay.trailingAnchor.constraint(equalTo: glassEffectView.trailingAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
@@ -180,17 +147,14 @@ private class TerminalGlassView: NSView {
|
||||
) {
|
||||
glassEffectView.style = style
|
||||
glassEffectView.tintColor = backgroundColor.withAlphaComponent(backgroundOpacity)
|
||||
if let cornerRadius {
|
||||
glassEffectView.cornerRadius = cornerRadius
|
||||
}
|
||||
glassEffectView.cornerRadius = cornerRadius ?? 0
|
||||
updateKeyStatus(isKeyWindow, backgroundColor: backgroundColor)
|
||||
}
|
||||
|
||||
/// Updates the top inset offset for both the glass effect and tint overlay.
|
||||
/// Call this when the safe area insets change (e.g., during layout).
|
||||
func updateTopInset(_ offset: CGFloat) {
|
||||
glassTopConstraint?.constant = offset
|
||||
tintTopConstraint?.constant = offset
|
||||
topConstraint.constant = offset
|
||||
}
|
||||
|
||||
/// Updates the tint overlay visibility based on window key status.
|
||||
@@ -210,15 +174,15 @@ private class TerminalGlassView: NSView {
|
||||
}
|
||||
#endif // compiler(>=6.2)
|
||||
|
||||
private extension TerminalViewContainer {
|
||||
extension TerminalViewContainer {
|
||||
#if compiler(>=6.2)
|
||||
@available(macOS 26.0, *)
|
||||
func addGlassEffectViewIfNeeded() -> TerminalGlassView? {
|
||||
private func addGlassEffectViewIfNeeded() -> TerminalGlassView? {
|
||||
if let existed = glassEffectView as? TerminalGlassView {
|
||||
updateGlassEffectTopInsetIfNeeded()
|
||||
return existed
|
||||
}
|
||||
guard let themeFrameView = window?.contentView?.superview else {
|
||||
guard let themeFrameView = windowThemeFrameView else {
|
||||
return nil
|
||||
}
|
||||
let effectView = TerminalGlassView(topOffset: -themeFrameView.safeAreaInsets.top)
|
||||
@@ -234,9 +198,9 @@ private extension TerminalViewContainer {
|
||||
}
|
||||
#endif // compiler(>=6.2)
|
||||
|
||||
func updateGlassEffectIfNeeded() {
|
||||
private func updateGlassEffectIfNeeded() {
|
||||
#if compiler(>=6.2)
|
||||
guard #available(macOS 26.0, *), derivedConfig.backgroundBlur.isGlassStyle else {
|
||||
guard #available(macOS 26.0, *), let derivedConfig else {
|
||||
glassEffectView?.removeFromSuperview()
|
||||
glassEffectView = nil
|
||||
return
|
||||
@@ -245,61 +209,60 @@ private extension TerminalViewContainer {
|
||||
return
|
||||
}
|
||||
|
||||
let style: NSGlassEffectView.Style
|
||||
switch derivedConfig.backgroundBlur {
|
||||
case .macosGlassRegular:
|
||||
style = NSGlassEffectView.Style.regular
|
||||
case .macosGlassClear:
|
||||
style = NSGlassEffectView.Style.clear
|
||||
default:
|
||||
style = NSGlassEffectView.Style.regular
|
||||
}
|
||||
let backgroundColor = (window as? TerminalWindow)?.preferredBackgroundColor ?? NSColor(derivedConfig.backgroundColor)
|
||||
|
||||
var cornerRadius: CGFloat?
|
||||
if let window, window.responds(to: Selector(("_cornerRadius"))) {
|
||||
cornerRadius = window.value(forKey: "_cornerRadius") as? CGFloat
|
||||
}
|
||||
|
||||
effectView.configure(
|
||||
style: style,
|
||||
backgroundColor: backgroundColor,
|
||||
style: derivedConfig.style.official,
|
||||
backgroundColor: derivedConfig.backgroundColor,
|
||||
backgroundOpacity: derivedConfig.backgroundOpacity,
|
||||
cornerRadius: cornerRadius,
|
||||
cornerRadius: derivedConfig.cornerRadius,
|
||||
isKeyWindow: window?.isKeyWindow ?? true
|
||||
)
|
||||
#endif // compiler(>=6.2)
|
||||
}
|
||||
|
||||
func updateGlassEffectTopInsetIfNeeded() {
|
||||
private func updateGlassEffectTopInsetIfNeeded() {
|
||||
#if compiler(>=6.2)
|
||||
guard #available(macOS 26.0, *), derivedConfig.backgroundBlur.isGlassStyle else {
|
||||
guard
|
||||
#available(macOS 26.0, *),
|
||||
let effectView = glassEffectView as? TerminalGlassView,
|
||||
let themeFrameView = windowThemeFrameView
|
||||
else {
|
||||
return
|
||||
}
|
||||
guard glassEffectView != nil else { return }
|
||||
guard let themeFrameView = window?.contentView?.superview else { return }
|
||||
(glassEffectView as? TerminalGlassView)?.updateTopInset(-themeFrameView.safeAreaInsets.top)
|
||||
effectView.updateTopInset(-themeFrameView.safeAreaInsets.top)
|
||||
#endif // compiler(>=6.2)
|
||||
}
|
||||
|
||||
func updateGlassTintOverlay(isKeyWindow: Bool) {
|
||||
#if compiler(>=6.2)
|
||||
guard #available(macOS 26.0, *) else { return }
|
||||
guard glassEffectView != nil else { return }
|
||||
let backgroundColor = (window as? TerminalWindow)?.preferredBackgroundColor ?? NSColor(derivedConfig.backgroundColor)
|
||||
(glassEffectView as? TerminalGlassView)?.updateKeyStatus(isKeyWindow, backgroundColor: backgroundColor)
|
||||
guard
|
||||
#available(macOS 26.0, *),
|
||||
let effectView = glassEffectView as? TerminalGlassView,
|
||||
let derivedConfig
|
||||
else {
|
||||
return
|
||||
}
|
||||
effectView.updateKeyStatus(isKeyWindow, backgroundColor: derivedConfig.backgroundColor)
|
||||
#endif // compiler(>=6.2)
|
||||
}
|
||||
|
||||
struct DerivedConfig: Equatable {
|
||||
var backgroundOpacity: Double = 0
|
||||
var backgroundBlur: Ghostty.Config.BackgroundBlur
|
||||
var backgroundColor: Color = .clear
|
||||
let style: BackportNSGlassStyle
|
||||
let backgroundColor: NSColor
|
||||
let backgroundOpacity: Double
|
||||
let cornerRadius: CGFloat?
|
||||
|
||||
init(config: Ghostty.Config) {
|
||||
self.backgroundBlur = config.backgroundBlur
|
||||
init?(config: Ghostty.Config, preferredBackgroundColor: NSColor?, cornerRadius: CGFloat?) {
|
||||
switch config.backgroundBlur {
|
||||
case .macosGlassRegular:
|
||||
style = .regular
|
||||
case .macosGlassClear:
|
||||
style = .clear
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
self.backgroundColor = preferredBackgroundColor ?? NSColor(config.backgroundColor)
|
||||
self.backgroundOpacity = config.backgroundOpacity
|
||||
self.backgroundColor = config.backgroundColor
|
||||
self.cornerRadius = cornerRadius
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,3 +117,17 @@ enum BackportPointerStyle {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
enum BackportNSGlassStyle {
|
||||
case regular, clear
|
||||
|
||||
#if canImport(AppKit)
|
||||
@available(macOS 26, *)
|
||||
var official: NSGlassEffectView.Style {
|
||||
switch self {
|
||||
case .regular: return .regular
|
||||
case .clear: return .clear
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
103
macos/Tests/Terminal/TerminalViewContainerTests.swift
Normal file
103
macos/Tests/Terminal/TerminalViewContainerTests.swift
Normal file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// TerminalViewContainerTests.swift
|
||||
// Ghostty
|
||||
//
|
||||
// Created by Lukas on 26.02.2026.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Testing
|
||||
@testable import Ghostty
|
||||
|
||||
class MockTerminalViewContainer: TerminalViewContainer {
|
||||
var _windowCornerRadius: CGFloat?
|
||||
override var windowThemeFrameView: NSView? {
|
||||
NSView()
|
||||
}
|
||||
|
||||
override var windowCornerRadius: CGFloat? {
|
||||
_windowCornerRadius
|
||||
}
|
||||
}
|
||||
|
||||
class MockConfig: Ghostty.Config {
|
||||
internal init(backgroundBlur: Ghostty.Config.BackgroundBlur, backgroundColor: Color, backgroundOpacity: Double) {
|
||||
self._backgroundBlur = backgroundBlur
|
||||
self._backgroundColor = backgroundColor
|
||||
self._backgroundOpacity = backgroundOpacity
|
||||
super.init(config: nil)
|
||||
}
|
||||
|
||||
var _backgroundBlur: Ghostty.Config.BackgroundBlur
|
||||
var _backgroundColor: Color
|
||||
var _backgroundOpacity: Double
|
||||
|
||||
override var backgroundBlur: Ghostty.Config.BackgroundBlur {
|
||||
_backgroundBlur
|
||||
}
|
||||
|
||||
override var backgroundColor: Color {
|
||||
_backgroundColor
|
||||
}
|
||||
|
||||
override var backgroundOpacity: Double {
|
||||
_backgroundOpacity
|
||||
}
|
||||
}
|
||||
|
||||
struct TerminalViewContainerTests {
|
||||
@Test func glassAvailability() async throws {
|
||||
let view = await MockTerminalViewContainer {
|
||||
EmptyView()
|
||||
}
|
||||
|
||||
let config = MockConfig(backgroundBlur: .macosGlassRegular, backgroundColor: .clear, backgroundOpacity: 1)
|
||||
await view.ghosttyConfigDidChange(config, preferredBackgroundColor: nil)
|
||||
try await Task.sleep(nanoseconds: UInt64(1e8)) // wait for the view to be setup if needed
|
||||
if #available(macOS 26.0, *) {
|
||||
#expect(view.glassEffectView != nil)
|
||||
} else {
|
||||
#expect(view.glassEffectView == nil)
|
||||
}
|
||||
}
|
||||
|
||||
#if compiler(>=6.2)
|
||||
@Test func configChangeUpdatesGlass() async throws {
|
||||
guard #available(macOS 26.0, *) else { return }
|
||||
let view = await MockTerminalViewContainer {
|
||||
EmptyView()
|
||||
}
|
||||
let config1 = MockConfig(backgroundBlur: .macosGlassRegular, backgroundColor: .clear, backgroundOpacity: 1)
|
||||
await view.ghosttyConfigDidChange(config1, preferredBackgroundColor: nil)
|
||||
let glassEffectView = await view.descendants(withClassName: "NSGlassEffectView").first as? NSGlassEffectView
|
||||
let effectView = try #require(glassEffectView)
|
||||
try await Task.sleep(nanoseconds: UInt64(1e8)) // wait for the view to be setup if needed
|
||||
#expect(effectView.tintColor?.hexString == NSColor.clear.hexString)
|
||||
|
||||
// Test with same config but with different preferredBackgroundColor
|
||||
await view.ghosttyConfigDidChange(config1, preferredBackgroundColor: .red)
|
||||
#expect(effectView.tintColor?.hexString == NSColor.red.hexString)
|
||||
|
||||
// MARK: - Corner Radius
|
||||
|
||||
#expect(effectView.cornerRadius == 0)
|
||||
await MainActor.run { view._windowCornerRadius = 10 }
|
||||
|
||||
// This won't change, unless ghosttyConfigDidChange is called
|
||||
#expect(effectView.cornerRadius == 0)
|
||||
|
||||
await view.ghosttyConfigDidChange(config1, preferredBackgroundColor: .red)
|
||||
#expect(effectView.cornerRadius == 10)
|
||||
|
||||
// MARK: - Glass Style
|
||||
|
||||
#expect(effectView.style == .regular)
|
||||
|
||||
let config2 = MockConfig(backgroundBlur: .macosGlassClear, backgroundColor: .clear, backgroundOpacity: 1)
|
||||
await view.ghosttyConfigDidChange(config2, preferredBackgroundColor: .red)
|
||||
|
||||
#expect(effectView.style == .clear)
|
||||
|
||||
}
|
||||
#endif // compiler(>=6.2)
|
||||
}
|
||||
Reference in New Issue
Block a user