diff --git a/Sources/WorkspaceContentView.swift b/Sources/WorkspaceContentView.swift index 4ba398be..ad1d48d2 100644 --- a/Sources/WorkspaceContentView.swift +++ b/Sources/WorkspaceContentView.swift @@ -9,7 +9,7 @@ struct WorkspaceContentView: View { let isWorkspaceVisible: Bool let isWorkspaceInputActive: Bool let workspacePortalPriority: Int - @State private var config = GhosttyConfig.load() + @State private var config = WorkspaceContentView.resolveGhosttyAppearanceConfig() @Environment(\.colorScheme) private var colorScheme @EnvironmentObject var notificationStore: TerminalNotificationStore @@ -87,7 +87,7 @@ struct WorkspaceContentView: View { .frame(maxWidth: .infinity, maxHeight: .infinity) .onAppear { syncBonsplitNotificationBadges() - workspace.applyGhosttyChrome(backgroundColor: GhosttyApp.shared.defaultBackgroundColor) + refreshGhosttyAppearanceConfig() } .onChange(of: notificationStore.notifications) { _, _ in syncBonsplitNotificationBadges() @@ -104,9 +104,9 @@ struct WorkspaceContentView: View { } .onReceive(NotificationCenter.default.publisher(for: .ghosttyDefaultBackgroundDidChange)) { notification in if let backgroundColor = notification.userInfo?[GhosttyNotificationKey.backgroundColor] as? NSColor { - workspace.applyGhosttyChrome(backgroundColor: backgroundColor) + refreshGhosttyAppearanceConfig(backgroundOverride: backgroundColor) } else { - workspace.applyGhosttyChrome(backgroundColor: GhosttyApp.shared.defaultBackgroundColor) + refreshGhosttyAppearanceConfig() } } } @@ -141,8 +141,18 @@ struct WorkspaceContentView: View { } } - private func refreshGhosttyAppearanceConfig() { - let next = GhosttyConfig.load() + static func resolveGhosttyAppearanceConfig( + backgroundOverride: NSColor? = nil, + loadConfig: () -> GhosttyConfig = GhosttyConfig.load, + defaultBackground: () -> NSColor = { GhosttyApp.shared.defaultBackgroundColor } + ) -> GhosttyConfig { + var next = loadConfig() + next.backgroundColor = backgroundOverride ?? defaultBackground() + return next + } + + private func refreshGhosttyAppearanceConfig(backgroundOverride: NSColor? = nil) { + let next = Self.resolveGhosttyAppearanceConfig(backgroundOverride: backgroundOverride) config = next workspace.applyGhosttyChrome(from: next) } diff --git a/cmuxTests/GhosttyConfigTests.swift b/cmuxTests/GhosttyConfigTests.swift index 25946b38..2e28bf5f 100644 --- a/cmuxTests/GhosttyConfigTests.swift +++ b/cmuxTests/GhosttyConfigTests.swift @@ -232,6 +232,51 @@ final class WorkspaceChromeThemeTests: XCTestCase { } } +final class WorkspaceAppearanceConfigResolutionTests: XCTestCase { + func testResolvedAppearanceConfigPrefersGhosttyRuntimeBackgroundOverLoadedConfig() { + guard let loadedBackground = NSColor(hex: "#112233"), + let runtimeBackground = NSColor(hex: "#FDF6E3"), + let loadedForeground = NSColor(hex: "#ABCDEF") else { + XCTFail("Expected valid test colors") + return + } + + var loaded = GhosttyConfig() + loaded.backgroundColor = loadedBackground + loaded.foregroundColor = loadedForeground + loaded.unfocusedSplitOpacity = 0.42 + + let resolved = WorkspaceContentView.resolveGhosttyAppearanceConfig( + loadConfig: { loaded }, + defaultBackground: { runtimeBackground } + ) + + XCTAssertEqual(resolved.backgroundColor.hexString(), "#FDF6E3") + XCTAssertEqual(resolved.foregroundColor.hexString(), "#ABCDEF") + XCTAssertEqual(resolved.unfocusedSplitOpacity, 0.42, accuracy: 0.0001) + } + + func testResolvedAppearanceConfigPrefersExplicitBackgroundOverride() { + guard let loadedBackground = NSColor(hex: "#112233"), + let runtimeBackground = NSColor(hex: "#FDF6E3"), + let explicitOverride = NSColor(hex: "#272822") else { + XCTFail("Expected valid test colors") + return + } + + var loaded = GhosttyConfig() + loaded.backgroundColor = loadedBackground + + let resolved = WorkspaceContentView.resolveGhosttyAppearanceConfig( + backgroundOverride: explicitOverride, + loadConfig: { loaded }, + defaultBackground: { runtimeBackground } + ) + + XCTAssertEqual(resolved.backgroundColor.hexString(), "#272822") + } +} + final class NotificationBurstCoalescerTests: XCTestCase { func testSignalsInSameBurstFlushOnce() { let coalescer = NotificationBurstCoalescer(delay: 0.01)