@@ -1687,34 +1687,51 @@ class TerminalManager: NSObject, LocalProcessTerminalViewDelegate {
16871687 TerminalTheme . theme ( forId: currentThemeId)
16881688 }
16891689
1690+ /// The panel's translucency is split across two stacked layers — the
1691+ /// SwiftUI theme tint below and the terminal's per-cell fills above —
1692+ /// each at 1−√(1−opacity) so the composite matches the user's setting.
1693+ /// The cell fills matter for text quality: SwiftTerm hard-enables font
1694+ /// smoothing per glyph, and glyphs rasterized against a clear context
1695+ /// get noisy fringed edges; a real fill color in the same context keeps
1696+ /// them clean. At opacity 1 this resolves to the fully opaque theme
1697+ /// background (crispest possible rendering).
1698+ static func layeredPanelAlpha( ) -> CGFloat {
1699+ let stored = UserDefaults . standard. object ( forKey: " panelOpacity " ) as? Double
1700+ let opacity = min ( max ( stored ?? 1.0 , 0.5 ) , 1.0 )
1701+ return CGFloat ( 1 - ( 1 - opacity) . squareRoot ( ) )
1702+ }
1703+
16901704 private func applyTheme( to terminal: LocalProcessTerminalView ) {
16911705 let theme = currentTheme
1692- // Fully transparent terminal background: SwiftTerm paints its
1693- // background three times (layer + per-run fill + gap fill), which
1694- // double-composites any translucent color. With .clear all three are
1695- // no-ops and the panel's SwiftUI background ( theme color scaled by
1696- // the user's transparency setting) is the single visible backdrop.
1697- terminal. nativeBackgroundColor = . clear
1698- // The setter above does NOT touch the view 's CALayer — SwiftTerm only
1699- // writes layer.backgroundColor during setupOptions() (init/font
1700- // changes), so the layer keeps the opaque default until cleared here.
1701- terminal . layer ? . backgroundColor = NSColor . clear . cgColor
1706+ let alpha = Self . layeredPanelAlpha ( )
1707+ if alpha >= 1 {
1708+ terminal . nativeBackgroundColor = theme . background
1709+ terminal . layer ? . backgroundColor = theme. background . cgColor
1710+ } else {
1711+ terminal. nativeBackgroundColor = theme . background . withAlphaComponent ( alpha )
1712+ // Keep the CALayer clear: SwiftTerm 's setter never updates it, and
1713+ // a colored layer would add a third composite on top of the fills.
1714+ terminal . layer? . backgroundColor = NSColor . clear . cgColor
1715+ }
17021716 terminal. nativeForegroundColor = theme. foreground
17031717 terminal. caretColor = theme. cursor
17041718 terminal. selectedTextBackgroundColor = theme. selection
17051719 terminal. installColors ( theme. swiftTermColors ( ) )
17061720 }
17071721
1722+ /// Re-applies theme backgrounds when the transparency slider moves.
1723+ func refreshPanelOpacity( ) {
1724+ for terminal in terminals. values {
1725+ applyTheme ( to: terminal)
1726+ terminal. setNeedsDisplay ( terminal. bounds)
1727+ }
1728+ }
1729+
17081730 func setTheme( _ themeId: String ) {
17091731 UserDefaults . standard. set ( themeId, forKey: Self . themeKey)
17101732 let theme = TerminalTheme . theme ( forId: themeId)
17111733 for terminal in terminals. values {
1712- terminal. nativeBackgroundColor = . clear
1713- terminal. layer? . backgroundColor = NSColor . clear. cgColor
1714- terminal. nativeForegroundColor = theme. foreground
1715- terminal. caretColor = theme. cursor
1716- terminal. selectedTextBackgroundColor = theme. selection
1717- terminal. installColors ( theme. swiftTermColors ( ) )
1734+ applyTheme ( to: terminal)
17181735 terminal. setNeedsDisplay ( terminal. bounds)
17191736 }
17201737 Task { @MainActor in
0 commit comments