From 95f4093e96f98dc963575a043ece13778c339cd1 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 16 Dec 2025 12:59:51 -0800 Subject: [PATCH] macos: make syncAppearance a virtual method on BaseTerminalController --- .../QuickTerminalController.swift | 9 +----- .../Terminal/BaseTerminalController.swift | 21 +++++++++++++- .../Terminal/TerminalController.swift | 29 +++++-------------- .../Window Styles/TerminalWindow.swift | 1 + 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift b/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift index d2db44d2d..8a642034f 100644 --- a/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift +++ b/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift @@ -313,13 +313,6 @@ class QuickTerminalController: BaseTerminalController { animateOut() } - override func toggleBackgroundOpacity() { - super.toggleBackgroundOpacity() - - // Sync the window appearance with the new opacity state - syncAppearance() - } - // MARK: Methods func toggle() { @@ -603,7 +596,7 @@ class QuickTerminalController: BaseTerminalController { }) } - private func syncAppearance() { + override func syncAppearance() { guard let window else { return } defer { updateColorSchemeForSurfaceTree() } diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index f8e0cc8e9..5f067c128 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -815,7 +815,7 @@ class BaseTerminalController: NSWindowController, } } - // MARK: Background Opacity + // MARK: Appearance /// Toggle the background opacity between transparent and opaque states. /// Do nothing if the configured background-opacity is >= 1 (already opaque). @@ -823,9 +823,25 @@ class BaseTerminalController: NSWindowController, func toggleBackgroundOpacity() { // Do nothing if config is already fully opaque guard ghostty.config.backgroundOpacity < 1 else { return } + + // Do nothing if in fullscreen (transparency doesn't apply in fullscreen) + guard let window, !window.styleMask.contains(.fullScreen) else { return } // Toggle between transparent and opaque isBackgroundOpaque.toggle() + + // Update our appearance + syncAppearance() + } + + /// Override this to resync any appearance related properties. This will be called automatically + /// when certain window properties change that affect appearance. The list below should be updated + /// as we add new things: + /// + /// - ``toggleBackgroundOpacity`` + func syncAppearance() { + // Purposely a no-op. This lets subclasses override this and we can call + // it virtually from here. } // MARK: Fullscreen @@ -888,6 +904,9 @@ class BaseTerminalController: NSWindowController, } else { updateOverlayIsVisible = defaultUpdateOverlayVisibility() } + + // Always resync our appearance + syncAppearance() } // MARK: Clipboard Confirmation diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index cc5b48700..8a0c5f46d 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -165,28 +165,6 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr } } - - override func fullscreenDidChange() { - super.fullscreenDidChange() - - // When our fullscreen state changes, we resync our appearance because some - // properties change when fullscreen or not. - guard let focusedSurface else { return } - - syncAppearance(focusedSurface.derivedConfig) - } - - override func toggleBackgroundOpacity() { - // Do nothing if in fullscreen (transparency doesn't apply in fullscreen) - guard let window = self.window, !window.styleMask.contains(.fullScreen) else { return } - - super.toggleBackgroundOpacity() - - // Sync the window appearance with the new opacity state - guard let focusedSurface else { return } - syncAppearance(focusedSurface.derivedConfig) - } - // MARK: Terminal Creation /// Returns all the available terminal controllers present in the app currently. @@ -500,6 +478,13 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr tabWindowsHash = v self.relabelTabs() } + + override func syncAppearance() { + // When our focus changes, we update our window appearance based on the + // currently focused surface. + guard let focusedSurface else { return } + syncAppearance(focusedSurface.derivedConfig) + } private func syncAppearance(_ surfaceConfig: Ghostty.SurfaceView.DerivedConfig) { // Let our window handle its own appearance diff --git a/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift b/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift index 730cdea65..4196df97f 100644 --- a/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift +++ b/macos/Sources/Features/Terminal/Window Styles/TerminalWindow.swift @@ -469,6 +469,7 @@ class TerminalWindow: NSWindow { // Window transparency only takes effect if our window is not native fullscreen. // In native fullscreen we disable transparency/opacity because the background // becomes gray and widgets show through. + // // Also check if the user has overridden transparency to be fully opaque. let forceOpaque = terminalController?.isBackgroundOpaque ?? false if !styleMask.contains(.fullScreen) &&