From e5c31e8b379f6f850caadc2f11c74ea9e6644f34 Mon Sep 17 00:00:00 2001 From: davidsanchez222 Date: Sat, 28 Feb 2026 15:50:52 -0500 Subject: [PATCH 1/2] macos: opacity-toggle setting persists between tabs in a window and to a newly created window --- .../Terminal/BaseTerminalController.swift | 3 +- .../Terminal/TerminalController.swift | 38 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index 5d9d5d527..eca789d47 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -766,7 +766,8 @@ class BaseTerminalController: NSWindowController, ghostty, tree: newTree, position: notification.userInfo?[Notification.Name.ghosttySurfaceDragEndedNoTargetPointKey] as? NSPoint, - confirmUndo: false) + confirmUndo: false, + inheritBackgroundOpacityFrom: self as? TerminalController) } // MARK: Local Events diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index 56b0b40ad..066e9430c 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -230,6 +230,9 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr // Get our parent. Our parent is the one explicitly given to us, // otherwise the focused terminal, otherwise an arbitrary one. let parent: NSWindow? = explicitParent ?? preferredParent?.window + if let parentController = parent?.windowController as? TerminalController { + c.isBackgroundOpaque = parentController.isBackgroundOpaque + } if let parent, parent.styleMask.contains(.fullScreen) { // If our previous window was fullscreen then we want our new window to @@ -313,8 +316,12 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr tree: SplitTree, position: NSPoint? = nil, confirmUndo: Bool = true, + inheritBackgroundOpacityFrom parentController: TerminalController? = nil ) -> TerminalController { let c = TerminalController.init(ghostty, withSurfaceTree: tree) + if let parentController { + c.isBackgroundOpaque = parentController.isBackgroundOpaque + } // Calculate the target frame based on the tree's view bounds let treeSize: CGSize? = tree.root?.viewBounds() @@ -359,7 +366,11 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr withTarget: ghostty, expiresAfter: target.undoExpiration ) { ghostty in - _ = TerminalController.newWindow(ghostty, tree: tree) + _ = TerminalController.newWindow( + ghostty, + tree: tree, + inheritBackgroundOpacityFrom: parentController + ) } } } @@ -394,6 +405,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr // Create a new window and add it to the parent let controller = TerminalController.init(ghostty, withBaseConfig: baseConfig) + controller.isBackgroundOpaque = parentController.isBackgroundOpaque guard let window = controller.window else { return controller } // If the parent is miniaturized, then macOS exhibits really strange behaviors @@ -491,6 +503,30 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr return controller } + override 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 } + + let newValue = !isBackgroundOpaque + let controllers: [TerminalController] + + if let tabGroup = window.tabGroup { + controllers = tabGroup.windows.compactMap { + $0.windowController as? TerminalController + } + } else { + controllers = [self] + } + + for controller in controllers { + controller.isBackgroundOpaque = newValue + controller.syncAppearance() + } + } + // MARK: - Methods @objc private func ghosttyConfigDidChange(_ notification: Notification) { From 0e49204b95fca41b1342ad56c9a0092f0872d737 Mon Sep 17 00:00:00 2001 From: davidsanchez222 Date: Sun, 5 Apr 2026 12:35:29 -0400 Subject: [PATCH 2/2] refactor(macos): centralize background opacity toggling across controllers --- .../Terminal/BaseTerminalController.swift | 14 +++++--- .../Terminal/TerminalController.swift | 32 +++---------------- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index eca789d47..2c03f87cb 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -767,7 +767,7 @@ class BaseTerminalController: NSWindowController, tree: newTree, position: notification.userInfo?[Notification.Name.ghosttySurfaceDragEndedNoTargetPointKey] as? NSPoint, confirmUndo: false, - inheritBackgroundOpacityFrom: self as? TerminalController) + inheritBackgroundOpacity: isBackgroundOpaque) } // MARK: Local Events @@ -991,11 +991,15 @@ class BaseTerminalController: NSWindowController, // 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() + let newValue = !isBackgroundOpaque + let controllers = NSApplication.shared.windows.compactMap { + $0.windowController as? BaseTerminalController + } - // Update our appearance - syncAppearance() + for controller in controllers { + controller.isBackgroundOpaque = newValue + controller.syncAppearance() + } } /// Override this to resync any appearance related properties. This will be called automatically diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index 066e9430c..7502da8d3 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -316,11 +316,11 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr tree: SplitTree, position: NSPoint? = nil, confirmUndo: Bool = true, - inheritBackgroundOpacityFrom parentController: TerminalController? = nil + inheritBackgroundOpacity: Bool? = nil ) -> TerminalController { let c = TerminalController.init(ghostty, withSurfaceTree: tree) - if let parentController { - c.isBackgroundOpaque = parentController.isBackgroundOpaque + if let inheritBackgroundOpacity { + c.isBackgroundOpaque = inheritBackgroundOpacity } // Calculate the target frame based on the tree's view bounds @@ -369,7 +369,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr _ = TerminalController.newWindow( ghostty, tree: tree, - inheritBackgroundOpacityFrom: parentController + inheritBackgroundOpacity: inheritBackgroundOpacity ) } } @@ -503,30 +503,6 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr return controller } - override 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 } - - let newValue = !isBackgroundOpaque - let controllers: [TerminalController] - - if let tabGroup = window.tabGroup { - controllers = tabGroup.windows.compactMap { - $0.windowController as? TerminalController - } - } else { - controllers = [self] - } - - for controller in controllers { - controller.isBackgroundOpaque = newValue - controller.syncAppearance() - } - } - // MARK: - Methods @objc private func ghosttyConfigDidChange(_ notification: Notification) {