Fix transparent background flash during sidebar toggle (#2378)
* Fix transparent background flash during sidebar toggle Move terminal background rendering from the Metal GPU pass to a CALayer (backgroundView). The GPU bg_color pass is disabled via a new Ghostty config flag (macos-background-from-layer). The CALayer resizes instantly with its parent NSView, eliminating the 3-5 frame gap where the desktop was visible through the transparent window during sidebar toggles and layout transitions. Also simplifies the titlebar and sidebar opacity formulas since there is now a single background layer instead of two stacked semi-transparent layers. * Document macos-background-from-layer fork change * Pin GhosttyKit checksum for macos-background-from-layer * Address review feedback: fix fallback config path, inline identity wrapper - Inject macos-background-from-layer in the fallback config path too, preventing alpha double-stacking when user config is invalid - Inline panelBackgroundFillColor (now an identity function) at its two call sites and remove the wrapper * Address adversarial review: skip fullscreen bg draw call explicitly The bg_color uniform alpha is still zeroed for cell compositing (so transparent cells pass through to the CALayer), but the fullscreen background fill draw step is now explicitly skipped instead of relying on alpha=0 as a no-op. * Pin GhosttyKit checksum for bg draw-call skip --------- Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
This commit is contained in:
parent
2d2d8da1c7
commit
543481ce12
5 changed files with 45 additions and 21 deletions
|
|
@ -2500,14 +2500,13 @@ struct ContentView: View {
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.background(TitlebarDoubleClickMonitorView())
|
.background(TitlebarDoubleClickMonitorView())
|
||||||
.background({
|
.background({
|
||||||
// The terminal area has two stacked semi-transparent layers: the Bonsplit
|
// The terminal background is provided by a single CALayer
|
||||||
// container chrome background plus Ghostty's own Metal-rendered background.
|
// (backgroundView in GhosttySurfaceScrollView), so the titlebar
|
||||||
// Compute the effective composited opacity so the titlebar matches visually.
|
// opacity matches the configured value directly.
|
||||||
let alpha = CGFloat(GhosttyApp.shared.defaultBackgroundOpacity)
|
let alpha = CGFloat(GhosttyApp.shared.defaultBackgroundOpacity)
|
||||||
let effective = alpha >= 0.999 ? alpha : 1.0 - pow(1.0 - alpha, 2)
|
|
||||||
return TitlebarLayerBackground(
|
return TitlebarLayerBackground(
|
||||||
backgroundColor: GhosttyApp.shared.defaultBackgroundColor,
|
backgroundColor: GhosttyApp.shared.defaultBackgroundColor,
|
||||||
opacity: effective
|
opacity: alpha
|
||||||
)
|
)
|
||||||
}())
|
}())
|
||||||
.overlay(alignment: .bottom) {
|
.overlay(alignment: .bottom) {
|
||||||
|
|
@ -14022,14 +14021,13 @@ private struct SidebarBackdrop: View {
|
||||||
let cornerRadius = CGFloat(max(0, sidebarCornerRadius))
|
let cornerRadius = CGFloat(max(0, sidebarCornerRadius))
|
||||||
|
|
||||||
if matchTerminalBackground {
|
if matchTerminalBackground {
|
||||||
// The terminal area has two stacked semi-transparent layers (Bonsplit chrome +
|
// The terminal background is provided by a single CALayer, so
|
||||||
// Ghostty Metal background). Compute the effective composited opacity to match.
|
// the sidebar uses the configured opacity directly.
|
||||||
let alpha = CGFloat(GhosttyApp.shared.defaultBackgroundOpacity)
|
let alpha = CGFloat(GhosttyApp.shared.defaultBackgroundOpacity)
|
||||||
let effective = alpha >= 0.999 ? alpha : 1.0 - pow(1.0 - alpha, 2)
|
|
||||||
return AnyView(
|
return AnyView(
|
||||||
SidebarTerminalBackgroundView(
|
SidebarTerminalBackgroundView(
|
||||||
backgroundColor: GhosttyApp.shared.defaultBackgroundColor,
|
backgroundColor: GhosttyApp.shared.defaultBackgroundColor,
|
||||||
opacity: effective
|
opacity: alpha
|
||||||
)
|
)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous))
|
.clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous))
|
||||||
.onReceive(NotificationCenter.default.publisher(for: .ghosttyDefaultBackgroundDidChange)) { _ in
|
.onReceive(NotificationCenter.default.publisher(for: .ghosttyDefaultBackgroundDidChange)) { _ in
|
||||||
|
|
|
||||||
|
|
@ -1303,6 +1303,12 @@ class GhosttyApp {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadInlineGhosttyConfig(
|
||||||
|
"macos-background-from-layer = true",
|
||||||
|
into: fallbackConfig,
|
||||||
|
prefix: "cmux-layer-bg",
|
||||||
|
logLabel: "layer background (fallback)"
|
||||||
|
)
|
||||||
ghostty_config_finalize(fallbackConfig)
|
ghostty_config_finalize(fallbackConfig)
|
||||||
updateDefaultBackground(from: fallbackConfig, source: "initialize.fallbackConfig")
|
updateDefaultBackground(from: fallbackConfig, source: "initialize.fallbackConfig")
|
||||||
|
|
||||||
|
|
@ -1391,6 +1397,15 @@ class GhosttyApp {
|
||||||
userConfigDefinesShiftEnterBinding = Self.userConfigDefinesShiftEnterBinding()
|
userConfigDefinesShiftEnterBinding = Self.userConfigDefinesShiftEnterBinding()
|
||||||
loadCopyOnSelectOverride(config)
|
loadCopyOnSelectOverride(config)
|
||||||
loadCJKFontFallbackIfNeeded(config)
|
loadCJKFontFallbackIfNeeded(config)
|
||||||
|
// cmux provides the terminal background via backgroundView (CALayer)
|
||||||
|
// instead of the GPU full-screen bg pass, so the layer can provide
|
||||||
|
// instant coverage during sidebar toggle and other layout transitions.
|
||||||
|
loadInlineGhosttyConfig(
|
||||||
|
"macos-background-from-layer = true",
|
||||||
|
into: config,
|
||||||
|
prefix: "cmux-layer-bg",
|
||||||
|
logLabel: "layer background"
|
||||||
|
)
|
||||||
ghostty_config_finalize(config)
|
ghostty_config_finalize(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7485,11 +7500,6 @@ final class GhosttySurfaceScrollView: NSView {
|
||||||
}
|
}
|
||||||
private(set) var searchFocusTarget: SearchFocusTarget = .searchField
|
private(set) var searchFocusTarget: SearchFocusTarget = .searchField
|
||||||
|
|
||||||
private static func panelBackgroundFillColor(for terminalBackgroundColor: NSColor) -> NSColor {
|
|
||||||
// The Ghostty renderer already draws translucent terminal backgrounds. If we paint an
|
|
||||||
// additional translucent layer here, alpha stacks and appears effectively opaque.
|
|
||||||
terminalBackgroundColor.alphaComponent < 0.999 ? .clear : terminalBackgroundColor
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
private var lastDropZoneOverlayLogSignature: String?
|
private var lastDropZoneOverlayLogSignature: String?
|
||||||
|
|
@ -7677,9 +7687,8 @@ final class GhosttySurfaceScrollView: NSView {
|
||||||
backgroundView.wantsLayer = true
|
backgroundView.wantsLayer = true
|
||||||
let initialTerminalBackground = GhosttyApp.shared.defaultBackgroundColor
|
let initialTerminalBackground = GhosttyApp.shared.defaultBackgroundColor
|
||||||
.withAlphaComponent(GhosttyApp.shared.defaultBackgroundOpacity)
|
.withAlphaComponent(GhosttyApp.shared.defaultBackgroundOpacity)
|
||||||
let initialPanelFill = Self.panelBackgroundFillColor(for: initialTerminalBackground)
|
backgroundView.layer?.backgroundColor = initialTerminalBackground.cgColor
|
||||||
backgroundView.layer?.backgroundColor = initialPanelFill.cgColor
|
backgroundView.layer?.isOpaque = initialTerminalBackground.alphaComponent >= 1.0
|
||||||
backgroundView.layer?.isOpaque = initialPanelFill.alphaComponent >= 1.0
|
|
||||||
addSubview(backgroundView)
|
addSubview(backgroundView)
|
||||||
addSubview(scrollView)
|
addSubview(scrollView)
|
||||||
inactiveOverlayView.wantsLayer = true
|
inactiveOverlayView.wantsLayer = true
|
||||||
|
|
@ -8245,11 +8254,10 @@ final class GhosttySurfaceScrollView: NSView {
|
||||||
|
|
||||||
func setBackgroundColor(_ color: NSColor) {
|
func setBackgroundColor(_ color: NSColor) {
|
||||||
guard let layer = backgroundView.layer else { return }
|
guard let layer = backgroundView.layer else { return }
|
||||||
let fillColor = Self.panelBackgroundFillColor(for: color)
|
|
||||||
CATransaction.begin()
|
CATransaction.begin()
|
||||||
CATransaction.setDisableActions(true)
|
CATransaction.setDisableActions(true)
|
||||||
layer.backgroundColor = fillColor.cgColor
|
layer.backgroundColor = color.cgColor
|
||||||
layer.isOpaque = fillColor.alphaComponent >= 1.0
|
layer.isOpaque = color.alphaComponent >= 1.0
|
||||||
CATransaction.commit()
|
CATransaction.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,17 @@ The fork branch HEAD is now the section 6 zsh redraw follow-up commit.
|
||||||
|
|
||||||
The fork branch HEAD is now the section 7 cmux theme picker helper commit.
|
The fork branch HEAD is now the section 7 cmux theme picker helper commit.
|
||||||
|
|
||||||
|
### 8) macos-background-from-layer config flag
|
||||||
|
|
||||||
|
- Branch: `feat-layer-bg`
|
||||||
|
- Files:
|
||||||
|
- `src/config/Config.zig`
|
||||||
|
- `src/renderer/generic.zig`
|
||||||
|
- Summary:
|
||||||
|
- Adds a `macos-background-from-layer` bool config (default false).
|
||||||
|
- When true, sets `bg_color[3] = 0` in the per-frame uniform update so the Metal renderer skips the full-screen background fill.
|
||||||
|
- Allows the host app to provide the terminal background via `CALayer.backgroundColor` for instant coverage during view resizes, avoiding alpha double-stacking.
|
||||||
|
|
||||||
## Upstreamed fork changes
|
## Upstreamed fork changes
|
||||||
|
|
||||||
### cursor-click-to-move respects OSC 133 click-to-move
|
### cursor-click-to-move respects OSC 133 click-to-move
|
||||||
|
|
@ -130,4 +141,9 @@ These files change frequently upstream; be careful when rebasing the fork:
|
||||||
If upstream reorganizes the preview loop or key handling, re-check the cmux mode path and keep the
|
If upstream reorganizes the preview loop or key handling, re-check the cmux mode path and keep the
|
||||||
stock Ghostty behavior unchanged when the cmux env vars are absent.
|
stock Ghostty behavior unchanged when the cmux env vars are absent.
|
||||||
|
|
||||||
|
- `src/renderer/generic.zig`
|
||||||
|
- The `macos-background-from-layer` check sits next to the glass-style check in `updateFrame`.
|
||||||
|
If upstream refactors the bg_color uniform update or the glass conditional, re-check that both
|
||||||
|
paths still zero out `bg_color[3]` correctly.
|
||||||
|
|
||||||
If you resolve a conflict, update this doc with what changed.
|
If you resolve a conflict, update this doc with what changed.
|
||||||
|
|
|
||||||
2
ghostty
2
ghostty
|
|
@ -1 +1 @@
|
||||||
Subproject commit bc9be90a21997a4e5f06bf15ae2ec0f937c2dc42
|
Subproject commit f9030b5c5232db69ba8625bb53d51ce735b80d51
|
||||||
|
|
@ -8,3 +8,5 @@ c47010b80cd9ae6d1ab744c120f011a465521ea3 d6904870a3c920b2787b1c4b950cfdef232606b
|
||||||
312c7b23a7c8dc0704431940d76ba5dc32a46afb ae73cb18a9d6efec42126a1d99e0e9d12022403d7dc301dfa21ed9f7c89c9e30
|
312c7b23a7c8dc0704431940d76ba5dc32a46afb ae73cb18a9d6efec42126a1d99e0e9d12022403d7dc301dfa21ed9f7c89c9e30
|
||||||
404a3f175ba6baafabc46cac807194883e040980 bcbd2954f4746fe5bcb4bfca6efeddd3ea355fda2836371f4c7150271c58acbd
|
404a3f175ba6baafabc46cac807194883e040980 bcbd2954f4746fe5bcb4bfca6efeddd3ea355fda2836371f4c7150271c58acbd
|
||||||
bc9be90a21997a4e5f06bf15ae2ec0f937c2dc42 6b83b66768e8bba871a3753ae8ffbaabd03370b306c429cd86c9cdcc8db82589
|
bc9be90a21997a4e5f06bf15ae2ec0f937c2dc42 6b83b66768e8bba871a3753ae8ffbaabd03370b306c429cd86c9cdcc8db82589
|
||||||
|
41e796064e89eacabdf3a6729475e250a5518e7a 135302bbdf3e83b200f0165ff2a32cdf13017219e6c8ffca17b672edfbfae395
|
||||||
|
f9030b5c5232db69ba8625bb53d51ce735b80d51 6c439d731d97bd35a3289f54478af3ac01e30ba74ec2672490e0c98f95262b55
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue