Add transparent background support - #198
Open
statik wants to merge 19 commits into
Open
Conversation
Route the libghostty background appearance into GhosthubUI via a new terminalBackgroundAppearance environment key, injected from the App module where LibghosttyRuntime lives. Surfaces directly behind the terminal go fully clear when transparent (the surface paints its own background at the configured opacity); chrome surfaces use the new WorkspaceSurfaceColor opacity variants so the window shows one consistent translucency. Opaque config renders exactly as before. Sweep of WorkspaceSurfaceColor/paneFill call sites: - RootView.swift workspaceContent (workspaceColumns background): behind sidebar and terminal -> clear when transparent. - RootView.swift workspaceSidebarColumn background: sidebar chrome surface -> tinted at appearance opacity. - RootView.swift terminalWorkspaceWithPreviewParking: cover layer -> clear when transparent; parked preview surfaces drop to 0.001 opacity so they keep rendering without showing through. - WorkspaceSidebarView.swift host header hierarchy-row background: chrome surface -> tinted; Color.primary overlay unchanged. - WorkspaceWindow.swift root background: behind everything -> clear when transparent. - WorkspaceWindow.swift WorkspaceWindowChrome.apply (nsColor sites): already appearance-aware from the window chrome change; unchanged. - SettingsView.swift .background(paneFill): settings sheet with its own backing -> stays opaque; out of scope. - PaneColors.swift paneFill definition: definition only. Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The sidebar column already paints the tinted surface, so repainting it on the host-header row multiplied the alphas (~0.96 effective at 0.8) and made the header visibly more opaque than the rest of the sidebar. Inherit the column surface when transparent, keeping only the Color.primary overlay for header differentiation; opaque rendering is unchanged. Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The clear-when-transparent ternary was duplicated across four call sites (and its tinted sibling at a fifth), which already caused one alpha-compounding bug. Replace them with two helpers on WorkspaceSurfaceColor: behindTerminal(_:) for layers the terminal surface (or an already-tinted surface) draws over, chrome(_:) for chrome surfaces tinted at the configured opacity. Also from review follow-ups: - Clamp nsColor(opacity:) to 0...1 before withAlphaComponent; out-of-range alpha is unspecified on the public API. - Justify the 0.001 parking opacity from verified behavior: terminal occlusion pausing is window-scoped (TerminalSurfaceView reads only window.occlusionState/isVisible/isKeyWindow), so 0 would not pause the surfaces, but SwiftUI may skip compositing at exactly zero; 0.001 avoids that and matches the near-clear window background in WorkspaceWindowChrome.apply. - Test tinted alpha under both light and dark appearances, assert the base colors differ across appearances (dynamic resolution survives the alpha wrap), compare all RGB channels against the canonical color, and cover the new clamp. Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The non-terminal branches of terminalWorkspaceContent (session detached, opening/loading progress, no-session and error states, the welcome screen) sat over the behindTerminal cover, which goes clear under a transparent config — they floated over the bare desktop at full transparency, breaking the uniform chrome translucency and hurting readability over busy wallpaper. Extract those branches into emptyWorkspaceState — they are the entire tail of the if/else chain after the three terminal branches, so one shared container covers all seven uniformly — and give it a single chrome(_:) background. The shared full-size frame replaces the per-branch max frames, keeping each state centered in the same slot. Opaque rendering is unchanged: these views previously had no background of their own and were drawn over the opaque cover; chrome(.opaque) paints the same canonical surface color over that identical opaque cover, which is visually indistinguishable. Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
The borrowed tmux, Herdr, and Zellij session views painted an opaque textBackgroundColor directly behind the libghostty surface, defeating the surface's configured alpha in the terminal content area. The backdrop is now clear whenever the terminal background appearance is transparent, and unchanged when opaque. Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 18:08 — with
GitHub Actions
Active
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 18:08 — with
GitHub Actions
Active
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 18:08 — with
GitHub Actions
Active
roborev: Combined Review (
|
Ports the snapshot opaque-flatten fix onto the always-live preview rework: the CGContext thumbnail path was replaced upstream by a CoreImage composite, which now flattens over opaqueFill so preview frames stay opaque under a transparent terminal background. The CGImage composite test is superseded by the opaqueFill seam tests; the live-surface smoke tests cover the GPU render. Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 18:24 — with
GitHub Actions
Active
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 18:24 — with
GitHub Actions
Active
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 18:24 — with
GitHub Actions
Active
roborev: Combined Review (
|
The recovery, disconnection, and opening fallback branches of the borrowed tmux, Herdr, and Zellij session views sat over a cover that goes clear under a transparent terminal background, so they floated over the bare desktop instead of the workspace chrome tint; each view now collapses those branches into one sessionFallback container with a shared chrome(_:) background. When opaque, chrome(.opaque) paints the canonical surface color over what was previously the opaque cover behind these views, so opaque rendering is visually unchanged. Claude-Session: https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW
Author
|
Addressed in c156256: the recovery, disconnection, and opening fallback branches of the tmux, Herdr, and Zellij session views now share a single |
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 21:22 — with
GitHub Actions
Active
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 21:22 — with
GitHub Actions
Active
statik
deployed
to
sandbox-image-promotion-status
August 26, 2026 21:23 — with
GitHub Actions
Active
roborev: Combined Review (
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
background-opacityandbackground-blurfrom the terminal config. When opacity is below 1, the window, titlebar, sidebar, and empty states become translucent at one consistent level, and the layers behind the terminal render clear so the desktop shows through — matching how Ghostty.app treats the same settings.ghostty.confapply live without a restart. libghostty remains authoritative for parsing; there is no separate Ghosthub setting.ghostty_set_window_background_blur, the same entry point Ghostty.app uses. macOS 26 glass-style values skip the radius call, matching upstream behavior.background-opacity; the default config's0.95now has a subtle visible effect, and1restores a fully opaque window.https://claude.ai/code/session_01LraXVn3ZPiWmALufmeiDHW