Skip to content

Extract window chrome domain from ContentView - #6147

Merged
azooz2003-bit merged 18 commits into
mainfrom
feat-contentview-decomp
Jun 17, 2026
Merged

azooz2003-bit merged 18 commits into
mainfrom
feat-contentview-decomp

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 15, 2026 •

Copy link
Copy Markdown
Collaborator

Addressing review (Aziz): why so many types, and folder separation

"Could you explain why there are so many types and that they're not folder-separated? Also can you explain what most of these files are for as someone who is not very familiar with this?"

Why so many small types. "Window chrome" is everything cmux paints around and behind the terminal: the window background, the native titlebar backdrop, the sidebar material, the hairline borders, and the macOS 26 glass effect. The extraction resolves chrome in stages so each stage is independently unit-testable without a live window: read current state into a *Snapshot, resolve it into a *Plan/*Policy, then a thin @MainActor controller applies the plan to a real NSWindow and returns a *Result. Most files are therefore tiny Sendable value types (snapshots, plans, options, results). The AppKit mutation lives only in three controller types. This is what kept every chrome file under the 500-line budget. One major public type per file, named after the type, per the conventions.

Folder separation (this round). The 40 files now sit in descriptive subfolders by concern, all via git mv so history is preserved (no behavior change). The test target mirrors the same split. A new package-root README.md (Packages/macOS/CmuxAppKitSupportUI/README.md) explains each subfolder and file for an unfamiliar reader, and every public type already carries a DocC /// summary.

  • Appearance/ resolves the window's overall appearance for one render pass (terminal + user-settings snapshots into a resolved WindowAppearanceSnapshot).
  • Backdrop/ the window background fill: role, policy, hosting phase, plan, the controller that applies it, and the result.
  • Glass/ the macOS 26 NSGlassEffectView window glass with an NSVisualEffectView fallback.
  • Titlebar/ native titlebar backdrop coordinator and the leading-inset reader.
  • Border/ the one-pixel chrome borders.
  • Color/ separator/compositing/readable-scheme color math.
  • Sidebar/ sidebar backdrop material policy plus the persisted preset/material/blend/state options.
  • TerminalSurface/ how an individual terminal surface paints its own background.
  • Overlay/ where window-level overlays are inserted in the AppKit hierarchy.

De-static check (CONVENTIONS section 10). None needed. The three controllers (WindowBackdropController, WindowGlassEffect, NativeTitlebarBackdropCoordinator) are real instance types with constructor-injected dependencies and an init, not static-only namespaces. The only static members are constant NSUserInterfaceItemIdentifiers, ObjC associated-object keys (a sanctioned AppKit pattern), and value-type factory/derivation methods on TerminalSurfaceBackgroundFillPlan/WindowAppearanceSnapshot (sanctioned by section 9). The lint's namespace-types check is clean.

Re-verified after the rework: scripts/lint-ios-package-conventions.sh is clean (zero new lint:allow), and xcodebuild ... -scheme cmux build reports BUILD SUCCEEDED.


Summary

  • Extract window chrome, titlebar backdrop, glass-effect, backdrop planning, sidebar material, and chrome border code from Sources/ContentView.swift into Packages/CmuxAppKitSupportUI under WindowChrome/.
  • Add Sources/Windowing/AppWindowChromeComposition.swift as the app-side composition root for GhosttyApp, WindowBackgroundComposition, NSApp.windows, and compositor blur side effects.
  • Ratchet .github/swift-file-length-budget.tsv for Sources/ContentView.swift from 16705 to 16038 lines.

Package Boundary

CmuxAppKitSupportUI is the boundary because the extracted domain is AppKit and SwiftUI chrome rendering, not generic window lifecycle. The package now depends on CmuxFoundation for Ghostty background value types and CmuxWorkspaceWindow for the existing injected WindowBackgroundPolicy.

Seams

  • WindowGlassEffectManaging hides native and fallback glass hierarchy operations.
  • WindowBackdropControllerDependencies injects compositor blur reset and Ghostty blur application.
  • WindowTerminalAppearanceSnapshot injects terminal appearance instead of reaching into GhosttyApp.shared from the package.
  • WindowContentOverlayTargetResolver receives the glass-effect seam for overlay placement.
  • NativeTitlebarBackdropCoordinator receives a fullscreen auxiliary window provider instead of reaching into NSApp.windows.
  • TitlebarLeadingInsetReader receives the debug inset provider from the app.

Verification

  • scripts/lint-ios-package-conventions.sh
  • cd Packages/CmuxAppKitSupportUI && swift build
  • cd Packages/CmuxAppKitSupportUI && swift test
  • xcodebuild -project cmux.xcodeproj -scheme cmux -configuration Debug -destination 'platform=macOS' -derivedDataPath /tmp/cmux-contentchrome build > /tmp/cmux-contentchrome-build.log 2>&1
  • grep '** BUILD SUCCEEDED **' /tmp/cmux-contentchrome-build.log

Notes

This is a principled decomposition: the package owns value objects and coordinators with constructor-injected seams, while concrete app dependencies stay in the app target. No lint:allow markers were added.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Extracted window chrome (titlebar, glass, sidebars, borders) from ContentView.swift into Packages/macOS/CmuxAppKitSupportUI/WindowChrome, added AppWindowChromeComposition for glass/backdrop/overlay seams, and split AppWindowBackdropControllerDependencies into its own file to clarify app-side wiring.

  • Refactors

    • Moved chrome code into CmuxAppKitSupportUI/WindowChrome, grouped by concern with a new README.
    • Introduced Sources/Windowing/AppWindowChromeComposition.swift; portals now resolve overlay targets and glass via this composition. Split Sources/Windowing/AppWindowBackdropControllerDependencies.swift into its own concrete adapter.
    • Replaced WindowChromeSeparatorColor with WindowChromeColorResolver; declared CmuxAppKitSupportUI deps on CmuxFoundation and CmuxWorkspaceWindow, and added app aliases to preserve sidebar setting types.
    • Removed app-local chrome files; reduced Sources/ContentView.swift size and updated .github/swift-file-length-budget.tsv (ContentView now 15920 lines).
  • Bug Fixes

    • Tightened transparent-window selection using glass availability and WindowBackgroundComposition.policy; overlay install now falls back to the theme frame when glass is absent.
    • Fixed tests and call sites: import CmuxAppKitSupportUI where needed, pass windowBackgroundPolicy to WindowGlassSettingsSnapshot.shouldApply, move titlebar inset hit-testing to a package test, and restore a direct Bonsplit link in cmuxTests.
    • Cleared @MainActor warnings in AppWindowChromeComposition by moving default evaluations into actor-isolated bodies; added explicit imports to stabilize per-file incremental builds.

Written for commit dffbd4e. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

New Features

  • More flexible window glass effects, including tint color, clear/regular glass style handling, and key-window-aware tint rendering.
  • Role-based, unified window chrome backdrops (root/terminal/sidebar/titlebar) with configurable sidebar material, blend mode, state, opacity, tint, and corner radius.
  • Improved native titlebar backdrop coordination, including synchronized hiding/restoring and titlebar control visibility.

Improvements

  • Theme-aware window chrome separators/borders for clearer contrast and updated sidebar/titlebar edge rendering.
  • Standardized chrome composition for overlay placement and hit-testing (including file-drop), plus updated transparent-background selection for webview/terminal panels.

@vercel

vercel Bot commented Jun 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 17, 2026 7:54pm
cmux-staging Building Building Preview, Comment Jun 17, 2026 7:54pm

@coderabbitai

coderabbitai Bot commented Jun 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR extracts window chrome and backdrop logic into CmuxAppKitSupportUI, adds shared appearance and application components, migrates app window and overlay call sites to that composition layer, replaces several legacy windowing paths, and updates tests and project/package wiring for the new APIs.

Changes

Window chrome pipeline migration

Layer / File(s) Summary
Package and build wiring
Packages/CmuxAppKitSupportUI/Package.swift, cmux.xcodeproj/project.pbxproj
Adds local package dependencies for CmuxFoundation and CmuxWorkspaceWindow, includes AppWindowChromeComposition.swift in the app target, and removes legacy windowing file references from the main target wiring.
Backdrop contracts and option models
Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/*
Adds public models and helpers for backdrop roles, policies, glass styles, sidebar material configuration, overlay targets, terminal appearance snapshots, separator color resolution, and default/sidebar option enums.
Appearance resolution and backdrop controller orchestration
Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowAppearance*.swift, .../WindowBackdrop*.swift, Sources/Windowing/AppWindowChromeComposition.swift
Builds resolved window appearance snapshots from terminal state and settings, derives backdrop plans and mutation identities, and applies those plans to NSWindow through an injected controller dependency layer.
Rendering, glass, and native titlebar components
Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowGlassEffect*.swift, .../NativeTitlebarBackdropCoordinator.swift, .../SidebarVisualEffectBackground.swift, .../WindowChromeBorder.swift, .../WindowBackdropLayer.swift
Adds the instance-based glass view hierarchy, native titlebar backdrop coordination, sidebar/material rendering views, overlay target fallback resolution, titlebar inset reading, layer-backed backdrop colors, and refreshable border rendering.
App composition root and call-site migration
Sources/ContentView.swift, Sources/GhosttyTerminalView.swift, Sources/*Portal.swift, Sources/Panels/*, Sources/Sidebar/SidebarAppearanceSupport.swift, Sources/Workspace.swift, Sources/cmuxApp.swift, Sources/RightSidebarChromeStyle.swift, Sources/KeyboardShortcutSettingsFileStore+Template.swift
Centralizes window chrome composition in AppWindowChromeComposition, migrates overlay installation and backdrop application to that API, updates titlebar control handling and border refresh behavior, and switches several call sites to the new separator color and tint-default helpers.
Window chrome tests and validation
Packages/CmuxAppKitSupportUI/Tests/CmuxAppKitSupportUITests/WindowChrome/*, cmuxTests/*Window*.swift, cmuxTests/GhosttyConfigTests.swift, cmuxTests/SidebarWidthPolicyTests.swift
Adds package tests for appearance resolution, backdrop controller behavior, and overlay target resolution, and updates app tests for the new backdrop-plan signature, separator color resolver, and instance-based WindowGlassEffect API.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~100 minutes

Possibly related PRs

  • manaflow-ai/cmux#5509: Introduces the same terminal surface background fill plan and owner types used by the terminal backdrop path in this PR.
  • manaflow-ai/cmux#3886: Also changes terminal background ownership and fill-plan logic around TerminalSurfaceBackgroundFillPlan.
  • manaflow-ai/cmux#3313: Also extends GhosttyBackgroundBlur to map into window glass style behavior.

Poem

🐇 I hopped through chrome and glass today,
with backdrops packed in a tidier way.
New plans, new borders, bright and neat,
make every window more complete.
I nibble tests and twirl my nose—
this little moonlit refactor glows.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-contentview-decomp

@greptile-apps

greptile-apps Bot commented Jun 15, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extracts window chrome logic from Sources/ContentView.swift into the CmuxAppKitSupportUI package under WindowChrome/, organised by concern (Appearance, Backdrop, Glass, Titlebar, Sidebar, Border, Overlay). AppWindowChromeComposition is introduced as the app-side composition root, replacing a set of static helpers with constructor-injected instance types backed by protocol seams.

  • Package extraction: 40+ new Swift files in CmuxAppKitSupportUI/WindowChrome/, each owning one type; tests mirror the same subfolder split; the package adds CmuxFoundation and CmuxWorkspaceWindow as dependencies.
  • Seam introduction: WindowGlassEffectManaging, WindowBackdropControllerDependencies, WindowContentOverlayTargetResolver, and NativeTitlebarBackdropCoordinator replace file-scoped free functions that reached into GhosttyApp.shared/NSApp.windows directly.
  • Known open issues (flagged in prior review rounds): WindowAppearanceSnapshot.appKitWindowMutationID still hardcodes glassEffectAvailable: false, suppressing WindowAccessor refreshes when only glass tint or style changes; BrowserPanel and TerminalPanelView also hardcode false for transparent-window selection, regressing glass-mode compositing on macOS 26.

Confidence Score: 4/5

The extraction itself is structurally sound and the main WindowAccessor path correctly threads glass availability. Two call sites (BrowserPanel, TerminalPanelView) and the mutation-ID method still hardcode glass unavailability, leaving macOS 26 glass mode with wrong window opacity and stale tint updates; these were flagged in the prior round and remain unaddressed in this commit.

The refactoring compiles cleanly and the core chrome application path in ContentView now correctly consults glassEffect.isAvailable. The three remaining hardcoded-false sites (appKitWindowMutationID, BrowserPanel, TerminalPanelView) are real defects on macOS 26 when glass is enabled: the panel windows may not become transparent when they should, and the WindowAccessor will not re-fire when a user changes only the glass tint color.

WindowAppearanceSnapshot.appKitWindowMutationID (hardcoded glassEffectAvailable: false), Sources/Panels/BrowserPanel.swift, and Sources/Panels/TerminalPanelView.swift both pass false to shouldUseTransparentBackgroundWindow.

Important Files Changed

Filename Overview
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/Appearance/WindowAppearanceSnapshot.swift Central resolved-snapshot type; appKitWindowMutationID still hardcodes glassEffectAvailable: false, so the WindowAccessor does not fire when only glass tint/style changes on macOS 26.
Sources/Windowing/AppWindowChromeComposition.swift New app-side composition root; correctly threads glassEffect.isAvailable in the main WindowAccessor path, but backdropController and contentOverlayTargetResolver are computed properties that allocate fresh instances on every access.
Sources/Panels/BrowserPanel.swift glassEffectAvailable hardcoded to false in shouldUseTransparentBackgroundWindow call, regressing opaque/transparent selection on macOS 26 glass mode.
Sources/Panels/TerminalPanelView.swift Same glassEffectAvailable: false regression as BrowserPanel; PanelAppearance.fromCurrentConfig will compute wrong transparent-window mode when glass is active on macOS 26.
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/Glass/WindowGlassEffect.swift Well-structured instance-based refactor of the old static WindowGlassEffect; associated-object lifecycle looks correct; isAvailable promoted to instance property appropriately.
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/Titlebar/NativeTitlebarBackdropCoordinator.swift Correctly moves native titlebar backdrop coordination out of ContentView; adds restoreNativeTitlebarTransparencyState to the restore path (new vs. old code); constructor injection of fullscreenAuxiliaryWindows eliminates the NSApp.windows reach-in.
Sources/ContentView.swift Significantly slimmed down; correctly uses windowChrome.glassEffect.isAvailable in the main WindowAccessor path; still contains legacy DispatchQueue.main.async for observedWindow assignment (carried over, not new).
Sources/GhosttyTerminalView.swift applyBackgroundToKeyWindow and applyWindowBackgroundIfActive now correctly thread glassEffect.isAvailable and windowBackgroundPolicy through backdropPlan; clean migration.
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/Glass/WindowGlassSettingsSnapshot.swift shouldApply correctly takes glassEffectAvailable and windowBackgroundPolicy; appKitMutationID includes all glass-relevant fields — the bug is upstream in WindowAppearanceSnapshot.appKitWindowMutationID which passes false.
Sources/Sidebar/SidebarAppearanceSupport.swift colorScheme now derived from NSApp.effectiveAppearance (fixes the prior hardcoded .dark issue); titlebarControlForegroundNSColor correctly reconstructs the appearance via WindowAppearanceResolver.
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/Titlebar/TitlebarLeadingInsetReader.swift DispatchQueue.main.async replaced with Task { @mainactor in … }, addressing the concurrency modernization finding from the prior review round.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    CV[ContentView / View body] -->|"stores let windowChrome"| ACC[AppWindowChromeComposition]
    ACC -->|creates| GE[WindowGlassEffect\ninstance]
    ACC -->|creates| NTC[NativeTitlebarBackdropCoordinator\ninstance]
    ACC -->|computed| BC[WindowBackdropController\nnew per access]
    ACC -->|computed| CTR[WindowContentOverlayTargetResolver\nnew per access]

    CV -->|refreshID = appKitWindowMutationID| WA[WindowAccessor]
    WA -->|fires| CMC["configureMainWindowChrome()"]
    CMC -->|glassEffectAvailable = GE.isAvailable ✅| BP[backdropPlan]
    BP -->|apply| BC

    BP2["BrowserPanel\nPanelAppearance"] -->|"glassEffectAvailable: false ❌"| SUT[shouldUseTransparentBackgroundWindow]
    BP3["TerminalPanelView\nPanelAppearance"] -->|"glassEffectAvailable: false ❌"| SUT

    MID["appKitWindowMutationID()"] -->|"glassEffectAvailable: false ❌"| MID2[backdropPlan → mutation ID\nmisses glass tint/style changes]

    GE -.->|objc_associated| WIN[NSWindow\nassociated state]
    NTC -.->|objc_associated| VIEW[NSView\ntitlebar state]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    CV[ContentView / View body] -->|"stores let windowChrome"| ACC[AppWindowChromeComposition]
    ACC -->|creates| GE[WindowGlassEffect\ninstance]
    ACC -->|creates| NTC[NativeTitlebarBackdropCoordinator\ninstance]
    ACC -->|computed| BC[WindowBackdropController\nnew per access]
    ACC -->|computed| CTR[WindowContentOverlayTargetResolver\nnew per access]

    CV -->|refreshID = appKitWindowMutationID| WA[WindowAccessor]
    WA -->|fires| CMC["configureMainWindowChrome()"]
    CMC -->|glassEffectAvailable = GE.isAvailable ✅| BP[backdropPlan]
    BP -->|apply| BC

    BP2["BrowserPanel\nPanelAppearance"] -->|"glassEffectAvailable: false ❌"| SUT[shouldUseTransparentBackgroundWindow]
    BP3["TerminalPanelView\nPanelAppearance"] -->|"glassEffectAvailable: false ❌"| SUT

    MID["appKitWindowMutationID()"] -->|"glassEffectAvailable: false ❌"| MID2[backdropPlan → mutation ID\nmisses glass tint/style changes]

    GE -.->|objc_associated| WIN[NSWindow\nassociated state]
    NTC -.->|objc_associated| VIEW[NSView\ntitlebar state]
Loading

Reviews (14): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment on lines +30 to +37
for accessory in window.titlebarAccessoryViewControllers
where accessory.layoutAttribute == .leading || accessory.layoutAttribute == .left {
leading += accessory.view.frame.width
}
if leading != inset {
inset = leading
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Legacy GCD dispatch in NSViewRepresentable update

DispatchQueue.main.async { … } is the old concurrency pattern. Per cmux-swift-concurrency-modernization, this should use Task { @MainActor in … } instead. Both patterns defer the binding mutation past the SwiftUI update cycle, but the Task form integrates with Swift's structured concurrency and is consistent with the rest of the codebase.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread Sources/ContentView.swift
Comment on lines 166 to 168
@discardableResult
private func ensureInstalled() -> Bool {
guard let window,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Ephemeral AppWindowChromeComposition on every event-driven call

AppWindowChromeComposition() is constructed inline here and in underlyingResponder(atWindowPoint:), WindowTmuxWorkspacePaneOverlayController.ensureInstalled(), installFileDropOverlay, WindowBrowserPortal.installationTarget, and WindowTerminalPortal.installationTarget — none of which share the windowChrome stored in ContentView. Each call allocates a fresh WindowGlassEffect + NativeTitlebarBackdropCoordinator pair just to run a single objc_getAssociatedObject lookup. The correctness is fine (state is keyed to the window), but underlyingResponder(atWindowPoint:) is called during pointer hit-testing and creates two class instances per event. Consider plumbing the contentOverlayTargetResolver from the AppWindowChromeComposition stored in ContentView down to the overlay controllers, or extracting a lightweight free function for the target lookup.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

backgroundBlur: app.defaultBackgroundBlur,
usesHostLayerBackground: app.usesHostLayerBackground
)
).currentFromUserDefaults(defaults: .standard, colorScheme: .dark)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 colorScheme: .dark hardcoded in titlebarControlForegroundNSColor

The old code derived colorScheme from NSApplication.shared.effectiveAppearance at the call site. The new call hardcodes .dark. While colorScheme doesn't affect compositedTerminalBackgroundColor (the only property consumed by this function), the hardcoded value is misleading and will silently produce wrong sidebar tint data if the snapshot is ever used for more than just terminal background composition. Prefer deriving the scheme from the effective appearance, as AppWindowChromeComposition.currentAppColorScheme() does.

Suggested change
).currentFromUserDefaults(defaults: .standard, colorScheme: .dark)
).currentFromUserDefaults(
defaults: .standard,
colorScheme: NSApplication.shared.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua ? .dark : .light
)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/Panels/TerminalPanelView.swift (1)

269-274: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve runtime glass-availability in transparent-window policy resolution.

Line 273 hardcodes glassEffectAvailable: false, which forces the no-glass branch and can compute usesTransparentWindow/usesClearContentBackground incorrectly on capable systems. Please pass the real availability signal (or require callers to provide it) instead of a fixed false.

Based on the PR objective that window chrome decisions are now composed through injected app-side chrome composition, this path should remain capability-aware.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/Panels/TerminalPanelView.swift` around lines 269 - 274, The
fromConfig static method in TerminalPanelView is hardcoding
glassEffectAvailable: false when calling the parameterized fromConfig, which
forces the transparent window policy to ignore actual glass effect capabilities
on capable systems. Replace the hardcoded false value with the actual glass
effect availability signal, either by obtaining it from the current runtime
environment or by refactoring the method signature to accept
glassEffectAvailable as a parameter so that callers can provide the correct
capability information. This ensures the WindowBackgroundComposition.policy
correctly computes usesTransparentWindow and usesClearContentBackground based on
real system capabilities.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/NativeTitlebarBackdropCoordinator.swift`:
- Around line 37-47: The syncNativeTitlebarBackdrop method currently performs
multiple separate recursive traversals of the titlebar container: one
firstNativeDescendant call for "NSTitlebarView" and two separate
nativeDescendants calls for "NSTitlebarBackgroundView" and "NSVisualEffectView".
Replace these three separate scans with a single depth-first search traversal
that collects all three view types in one pass, returning them together. Update
the code at the mentioned location and the additional site at lines 210-240 to
use this consolidated single-pass collector instead of the repeated hierarchy
scans.
- Around line 31-78: The `syncNativeTitlebarBackdrop` method sets
`window.titlebarAppearsTransparent = true` when enabled (line 77) but never
restores the previous value in the disabled path (where
`restoreNativeTitlebarBackdropState` is called). Save the original value of
`window.titlebarAppearsTransparent` when remembering the state in the enabled
branch, storing it as an associated object on the window alongside the other
saved UI properties, then restore that saved value in the
`restoreNativeTitlebarBackdropState` method to ensure the titlebar transparency
mode returns to its original state when disabling.

In
`@Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/SidebarVisualEffectBackground.swift`:
- Around line 59-64: The glass tint persists when tintColor becomes nil because
the setTintColor: selector is only called when tintColor is non-nil. To fix
this, move the selector resolution and responds(to:) check outside the optional
binding, and always invoke nsView.perform(selector, with:...) with either the
unwrapped color value when tintColor is non-nil or nil when tintColor is nil.
This ensures that previously applied tints are properly cleared when tintColor
is removed.

In
`@Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowAppearanceSnapshot.swift`:
- Around line 54-57: There is a type mismatch in the call to
compositedTerminalColor on line 76: the function parameter opacity expects a
Double, but terminalBackgroundOpacity is of type CGFloat. Fix this by converting
terminalBackgroundOpacity to Double when passing it as an argument to the
compositedTerminalColor function call.

In `@Sources/BrowserWindowPortal.swift`:
- Around line 2337-2340: The code is unnecessarily creating a new
AppWindowChromeComposition instance on every call to this function, which is in
a hot UI path during portal install/sync flows. Cache or reuse the
AppWindowChromeComposition instance instead of constructing it repeatedly. Store
the composition as a property or static variable that persists across multiple
calls, then access the cached instance within the guard statement where
contentOverlayTargetResolver is called. This eliminates redundant object
construction in a frequently-triggered UI path.

In `@Sources/cmuxApp.swift`:
- Around line 3116-3118: Replace the hardcoded opacity value of 0.62 assigned to
sidebarTintOpacity with SidebarTintDefaults().opacity to maintain consistency
with the centralized defaults used elsewhere in the code (such as at line 2959).
This ensures that if the default opacity value changes in SidebarTintDefaults,
all reset operations will use the same updated value without requiring multiple
edits.

In `@Sources/Sidebar/SidebarAppearanceSupport.swift`:
- Around line 53-63: The titlebarControlForegroundNSColor function is hardcoding
colorScheme: .dark when calling currentFromUserDefaults on the
WindowAppearanceResolver, which ignores the actual system appearance and causes
incorrect titlebar foreground contrast in light mode. Replace the hardcoded
.dark with the current system color scheme or appearance setting to ensure the
WindowAppearanceSnapshot is computed correctly based on the actual environment
rather than always assuming dark mode.

---

Outside diff comments:
In `@Sources/Panels/TerminalPanelView.swift`:
- Around line 269-274: The fromConfig static method in TerminalPanelView is
hardcoding glassEffectAvailable: false when calling the parameterized
fromConfig, which forces the transparent window policy to ignore actual glass
effect capabilities on capable systems. Replace the hardcoded false value with
the actual glass effect availability signal, either by obtaining it from the
current runtime environment or by refactoring the method signature to accept
glassEffectAvailable as a parameter so that callers can provide the correct
capability information. This ensures the WindowBackgroundComposition.policy
correctly computes usesTransparentWindow and usesClearContentBackground based on
real system capabilities.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d82c4d2e-2650-43e6-849c-8f5790471fda

📥 Commits

Reviewing files that changed from the base of the PR and between bd80f9e and 574970e.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (61)
  • Packages/CmuxAppKitSupportUI/Package.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/GhosttyBackgroundBlur+WindowGlassEffectStyle.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/GhosttyTerminalBackdropRenderingMode.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/LayerBackedBackdropColor.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/NativeTitlebarBackdropCoordinator.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/SidebarBackdropMaterialPolicy.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/SidebarBackdropSettingsSnapshot.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/SidebarVisualEffectBackground.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/TerminalSurfaceBackgroundFillOwner.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/TerminalSurfaceBackgroundFillPlan.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/TitlebarLeadingInsetReader.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowAppearanceResolver.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowAppearanceSnapshot.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowAppearanceUserSettingsSnapshot.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropApplicationResult.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropController.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropControllerDependencies.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropGlassPlan.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropHostingPhase.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropLayer.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropPlan.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropPolicy.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowBackdropRole.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeBorder.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeBorderOrientation.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeColorResolver.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeSidebarBlendModeOption.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeSidebarMaterialOption.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeSidebarPresetOption.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeSidebarStateOption.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowChromeSidebarTintDefaults.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowContentOverlayInstallationTarget.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowContentOverlayTargetResolver.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowGlassEffect.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowGlassEffectManaging.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowGlassEffectStyle.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowGlassSettingsSnapshot.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowRootBackdropResolution.swift
  • Packages/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/WindowChrome/WindowTerminalAppearanceSnapshot.swift
  • Packages/CmuxAppKitSupportUI/Tests/CmuxAppKitSupportUITests/WindowChrome/WindowAppearanceResolverTests.swift
  • Packages/CmuxAppKitSupportUI/Tests/CmuxAppKitSupportUITests/WindowChrome/WindowBackdropControllerTests.swift
  • Packages/CmuxAppKitSupportUI/Tests/CmuxAppKitSupportUITests/WindowChrome/WindowContentOverlayTargetResolverTests.swift
  • Sources/BrowserWindowPortal.swift
  • Sources/ContentView.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/KeyboardShortcutSettingsFileStore+Template.swift
  • Sources/Panels/BrowserPanel.swift
  • Sources/Panels/TerminalPanelView.swift
  • Sources/RightSidebarChromeStyle.swift
  • Sources/Sidebar/SidebarAppearanceSupport.swift
  • Sources/TerminalWindowPortal.swift
  • Sources/Windowing/AppWindowChromeComposition.swift
  • Sources/Windowing/WindowAppearanceSnapshot.swift
  • Sources/Windowing/WindowBackdropController.swift
  • Sources/Workspace.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/SidebarWidthPolicyTests.swift
  • cmuxTests/WindowAndDragTests.swift
  • cmuxTests/WindowAppearanceSnapshotTests.swift
💤 Files with no reviewable changes (2)
  • Sources/Windowing/WindowBackdropController.swift
  • Sources/Windowing/WindowAppearanceSnapshot.swift

Comment thread Sources/BrowserWindowPortal.swift Outdated
Comment on lines +2337 to +2340
guard let target = AppWindowChromeComposition()
.contentOverlayTargetResolver
.installationTarget(for: window) else { return nil }
return (target.container, target.reference)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid rebuilding the chrome composition on each installation-target lookup.

This path runs inside portal install/sync flows; constructing AppWindowChromeComposition() per call adds avoidable repeated work in a hot UI path.

💡 Suggested fix
 final class WindowBrowserPortal: NSObject {
+    private let chromeComposition = AppWindowChromeComposition()
     private static let transientRecoveryRetryBudget: Int = 12
@@
     private func installationTarget(for window: NSWindow) -> (container: NSView, reference: NSView)? {
-        guard let target = AppWindowChromeComposition()
+        guard let target = chromeComposition
             .contentOverlayTargetResolver
             .installationTarget(for: window) else { return nil }
         return (target.container, target.reference)
     }

As per coding guidelines, frequently-triggered UI paths should avoid repeated per-event work when it can be cached/reused.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/BrowserWindowPortal.swift` around lines 2337 - 2340, The code is
unnecessarily creating a new AppWindowChromeComposition instance on every call
to this function, which is in a hot UI path during portal install/sync flows.
Cache or reuse the AppWindowChromeComposition instance instead of constructing
it repeatedly. Store the composition as a property or static variable that
persists across multiple calls, then access the cached instance within the guard
statement where contentOverlayTargetResolver is called. This eliminates
redundant object construction in a frequently-triggered UI path.

Source: Coding guidelines

Comment thread Sources/cmuxApp.swift Outdated
Comment on lines 3116 to 3118
sidebarTintOpacity = 0.62
sidebarTintHex = SidebarTintDefaults.hex
sidebarTintHex = SidebarTintDefaults().hex
sidebarTintHexLight = nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Align reset tint opacity with centralized defaults.

Line 3116 still hardcodes 0.62 while Line 2959 now uses SidebarTintDefaults().opacity. Use the same default source in both places to avoid drift if defaults change.

Suggested patch
                     Button("Reset Tint") {
-                        sidebarTintOpacity = 0.62
+                        sidebarTintOpacity = SidebarTintDefaults().opacity
                         sidebarTintHex = SidebarTintDefaults().hex
                         sidebarTintHexLight = nil
                         sidebarTintHexDark = nil
                     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/cmuxApp.swift` around lines 3116 - 3118, Replace the hardcoded
opacity value of 0.62 assigned to sidebarTintOpacity with
SidebarTintDefaults().opacity to maintain consistency with the centralized
defaults used elsewhere in the code (such as at line 2959). This ensures that if
the default opacity value changes in SidebarTintDefaults, all reset operations
will use the same updated value without requiring multiple edits.

Comment on lines +53 to +63
func titlebarControlForegroundNSColor(opacity: CGFloat) -> NSColor {
let app = GhosttyApp.shared
let appearance = WindowAppearanceResolver(
terminalAppearance: WindowTerminalAppearanceSnapshot(
backgroundColor: app.defaultBackgroundColor,
backgroundOpacity: app.defaultBackgroundOpacity,
backgroundBlur: app.defaultBackgroundBlur,
usesHostLayerBackground: app.usesHostLayerBackground
)
).currentFromUserDefaults(defaults: .standard, colorScheme: .dark)
return titlebarControlForegroundNSColor(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid hardcoding .dark when deriving WindowAppearanceSnapshot.

Using colorScheme: .dark unconditionally can compute the wrong snapshot defaults in light appearance, leading to incorrect titlebar foreground contrast selection.

Suggested fix
 func titlebarControlForegroundNSColor(opacity: CGFloat) -> NSColor {
     let app = GhosttyApp.shared
+    let bestMatch = NSApp?.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua])
+    let colorScheme: ColorScheme = (bestMatch == .darkAqua) ? .dark : .light
     let appearance = WindowAppearanceResolver(
         terminalAppearance: WindowTerminalAppearanceSnapshot(
             backgroundColor: app.defaultBackgroundColor,
             backgroundOpacity: app.defaultBackgroundOpacity,
             backgroundBlur: app.defaultBackgroundBlur,
             usesHostLayerBackground: app.usesHostLayerBackground
         )
-    ).currentFromUserDefaults(defaults: .standard, colorScheme: .dark)
+    ).currentFromUserDefaults(defaults: .standard, colorScheme: colorScheme)
     return titlebarControlForegroundNSColor(
         opacity: opacity,
         appearance: appearance
     )
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/Sidebar/SidebarAppearanceSupport.swift` around lines 53 - 63, The
titlebarControlForegroundNSColor function is hardcoding colorScheme: .dark when
calling currentFromUserDefaults on the WindowAppearanceResolver, which ignores
the actual system appearance and causes incorrect titlebar foreground contrast
in light mode. Replace the hardcoded .dark with the current system color scheme
or appearance setting to ensure the WindowAppearanceSnapshot is computed
correctly based on the actual environment rather than always assuming dark mode.

Comment on lines +182 to +187
public func appKitWindowMutationID(windowBackgroundPolicy: WindowBackgroundPolicy) -> String {
backdropPlan(
glassEffectAvailable: false,
windowBackgroundPolicy: windowBackgroundPolicy
).appKitMutationID
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 appKitWindowMutationID always passes glassEffectAvailable: false, breaking glass-mode tint/style updates

The old implementation used WindowGlassEffect.isAvailable (the actual runtime value) as the default, so appKitWindowMutationID reflected the live glass plan. The new function hardcodes false: on macOS 26+ where NSGlassEffectView is available, the backdrop plan computed with false is a non-glass plan that omits glass tint and style. This means that when a user changes bgGlassTintHex or bgGlassTintOpacity while glass mode is already active, the mutation ID does not change, so the WindowAccessor refresh callback never fires, and the glass tint never updates via the AppKit path.

The fix is to thread glassEffectAvailable through the call site — the equivalent of the old backdropPlan(glassEffectAvailable: WindowGlassEffect.isAvailable).appKitMutationID — by adding glassEffectAvailable: Bool as a parameter and calling backdropPlan(glassEffectAvailable: glassEffectAvailable, windowBackgroundPolicy: windowBackgroundPolicy).appKitMutationID.

azooz2003-bit and others added 2 commits June 15, 2026 21:29
WindowAppearanceSnapshotPaneBackgroundTests references WindowAppearanceSnapshot,
TerminalSurfaceBackgroundFillPlan, and the sidebar/glass snapshot types that this
PR relocated to CmuxAppKitSupportUI, but it was left with only @testable import cmux
and would fail to compile in the cmuxTests target. Add the package imports matching
the sibling WindowAppearanceSnapshotTests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WindowGlassSettingsSnapshot.shouldApply moved into CmuxAppKitSupportUI and now
requires a windowBackgroundPolicy: argument. This wired cmuxTests call still used
the old one-argument signature, build-breaking the test target. Pass
WindowBackgroundComposition.policy to match the sibling backdropPlan /
shouldUseTransparentHosting calls in the same test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts:
#	.github/swift-file-length-budget.tsv
After re-syncing onto main, two failures surfaced that the app-only build
missed:

- cmuxTests/WindowAndDragTests.swift referenced TitlebarLeadingInsetPassthroughView,
  which this PR moved from Sources/ContentView.swift into a private type inside
  CmuxAppKitSupportUI/WindowChrome/TitlebarLeadingInsetReader.swift. The test
  target stopped compiling (tests + activation-session jobs). Make the view
  internal and move its hit-test / mouseDownCanMoveWindow coverage into a
  package test where the type now lives; rename the remaining app-target class
  to MainWindowDragBehaviorTests (it only covers MainWindowHostingView/CmuxMainWindow).
- AppWindowChromeComposition.swift emitted 3 new Swift concurrency warnings
  (over the 0 budget for the new file): main-actor default-arg evaluation of
  NSApplication.shared.effectiveAppearance and a non-Sendable
  fullscreenAuxiliaryWindows default closure. Resolve the actor-isolated
  defaults inside the @mainactor bodies instead of in nonisolated default-arg
  position; behavior unchanged (still defaults to NSApp.windows / current
  effectiveAppearance).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts:
#	.github/swift-file-length-budget.tsv

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/GhosttyTerminalView.swift (1)

4128-4153: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate surface backdrop overrides to the focused panel.

Line 4147 now lets a surface-local backgroundColor drive the shared window-root backdrop, but Lines 4135-4142 only verify that the workspace/tab is selected. In a split workspace, an unfocused terminal receiving an OSC/config background update can therefore recolor the entire window. Require the surface to be the focused panel before applying its override, or pass nil for unfocused surfaces.

Proposed fix
     `@MainActor`
     func applyWindowBackgroundIfActive() {
         guard let window else { return }
         let appDelegate = AppDelegate.shared
         let owningManager = tabId.flatMap { appDelegate?.tabManagerFor(tabId: $0) }
         let owningSelectedTabId = owningManager?.selectedTabId
         let activeSelectedTabId = owningManager == nil ? appDelegate?.tabManager?.selectedTabId : nil
         guard Self.shouldApplyWindowBackground(
             surfaceTabId: tabId,
             owningManagerExists: owningManager != nil,
             owningSelectedTabId: owningSelectedTabId,
             activeSelectedTabId: activeSelectedTabId
         ) else {
             return
         }
+        if let terminalSurface,
+           let workspace = owningManager?.tabs.first(where: { $0.id == terminalSurface.tabId }),
+           workspace.focusedPanelId != terminalSurface.id {
+            return
+        }
         applySurfaceBackground()
         let windowChrome = AppWindowChromeComposition()
         let windowRoot = windowChrome
             .appearanceSnapshotFromUserDefaults(app: GhosttyApp.shared)
             .windowRootBackdropResolution(surfaceBackgroundColor: backgroundColor)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/GhosttyTerminalView.swift` around lines 4128 - 4153, The
applyWindowBackgroundIfActive() function applies a surface-local backgroundColor
to the window-root backdrop without verifying that the surface is the focused
panel, allowing unfocused terminals in split workspaces to unintentionally
recolor the entire window. Enhance the guard condition in the
shouldApplyWindowBackground() check to also verify that the surface is the
focused panel before proceeding, or alternatively, pass nil for the
backgroundColor parameter when the surface is not focused to prevent unfocused
surfaces from overriding the window backdrop through the
windowRoot.snapshot.windowRootBackdropResolution call.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@Sources/GhosttyTerminalView.swift`:
- Around line 4128-4153: The applyWindowBackgroundIfActive() function applies a
surface-local backgroundColor to the window-root backdrop without verifying that
the surface is the focused panel, allowing unfocused terminals in split
workspaces to unintentionally recolor the entire window. Enhance the guard
condition in the shouldApplyWindowBackground() check to also verify that the
surface is the focused panel before proceeding, or alternatively, pass nil for
the backgroundColor parameter when the surface is not focused to prevent
unfocused surfaces from overriding the window backdrop through the
windowRoot.snapshot.windowRootBackdropResolution call.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ad9523c4-7c31-443b-b4d9-8d552f526516

📥 Commits

Reviewing files that changed from the base of the PR and between b372dd8 and b5d70eb.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (5)
  • Sources/ContentView.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/GhosttyConfigTests.swift
💤 Files with no reviewable changes (1)
  • cmuxTests/GhosttyConfigTests.swift

azooz2003-bit and others added 2 commits June 16, 2026 15:24
The re-sync merge absorbed sibling tmux-overlay regression tests
(WorkspaceContentViewVisibilityTests, added by "Add tmux attention
regression tests" on main) that `import Bonsplit` and reference
Bonsplit.PixelRect / PaneState / TabItem / DropZone directly, alongside
the pre-existing PortalTabDragRoutingTests, BrowserPaneDropRoutingTests,
and AppDelegateEqualizeSplitsShortcutTests.

On main those symbols resolved transitively through a directly-linked
package product. This PR's window-chrome extraction into
CmuxAppKitSupportUI perturbed the symbol graph so the linker dead-stripped
the Bonsplit objects the test-only references needed, breaking the
cmuxTests bundle link (ld: symbol(s) not found for architecture arm64) in
the `tests` job. The app-only `xcodebuild build` did not exercise the
test target, so it passed locally.

Fix: link the Bonsplit product directly into the cmuxTests target
(packageProductDependencies + Frameworks phase), mirroring how the app
target depends on it. A target that imports and uses Bonsplit should link
it explicitly rather than rely on a fragile transitive path. Scope is the
test target only; no app/runtime behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The cmuxTests target shared the app target's Bonsplit product-dependency
object (A5001261) and build file, so Xcode associated the link with the
app target only and dropped it from the test bundle. WindowChrome
extraction made two test files import CmuxWorkspaceWindow, which
public-imports Bonsplit, so the test bundle now references Bonsplit type
metadata and the missing link produced undefined Bonsplit.* symbols at
link time.

Give cmuxTests its own XCSwiftPackageProductDependency (A5001262) wired
through both packageProductDependencies and its Frameworks build phase,
mirroring the per-target B2/C2 pattern used by every other package.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…muxAppKitSupportUI (absorb 6278 reorg)

Merge origin/main and adapt the window-chrome extraction to main's
Packages/{Shared,iOS,macOS}/ layout: move the new WindowChrome sources/tests
into Packages/macOS/CmuxAppKitSupportUI (main already carries the matching
CmuxFoundation + CmuxWorkspaceWindow deps). Regenerate the file-length budget
after relocation; preserve the cmuxTests Bonsplit per-target link fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
azooz2003-bit and others added 2 commits June 17, 2026 11:06
Group the 40 window-chrome files into descriptive subfolders (Appearance,
Backdrop, Glass, Titlebar, Border, Color, Sidebar, TerminalSurface, Overlay)
so the package is navigable. Pure git mv, history preserved; no behavior change.
Mirror the same split in the test target. Add a package-root README explaining
what each subfolder and file is for, written for an unfamiliar reader.

Every public type already carries a DocC /// summary. No de-static needed: the
controllers (WindowBackdropController, WindowGlassEffect,
NativeTitlebarBackdropCoordinator) are real instance types with
constructor-injected dependencies; the only statics are constant identifiers,
ObjC associated-object keys, and value-type factory methods (sanctioned by
CONVENTIONS section 9), none a static-only namespace.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment on lines 4494 to +4495
usesTransparentWindow: WindowBackgroundComposition.policy
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: WindowGlassEffect.isAvailable)
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: false)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Transparent-window selection regresses on macOS 26 because glassEffectAvailable is hardcoded to false. The old call site used WindowGlassEffect.isAvailable (a static property that has since moved to an instance). When NSGlassEffectView is present and the user has glass enabled, shouldUseTransparentBackgroundWindow returns a different value than it did before this PR, so BrowserPanel may no longer set isOpaque = false on the window, breaking the compositing pass that glass rendering depends on.

Suggested change
usesTransparentWindow: WindowBackgroundComposition.policy
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: WindowGlassEffect.isAvailable)
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: false)
usesTransparentWindow: WindowBackgroundComposition.policy
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: WindowGlassEffect().isAvailable)

Comment on lines 272 to +273
usesTransparentWindow: WindowBackgroundComposition.policy
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: WindowGlassEffect.isAvailable)
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: false)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Same regression as in BrowserPanel.swift: glassEffectAvailable is hardcoded to false, so PanelAppearance.fromCurrentConfig will always compute transparent-window mode as if glass is unavailable. On macOS 26 with glass enabled this can give the wrong opacity setting for the panel window.

Suggested change
usesTransparentWindow: WindowBackgroundComposition.policy
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: WindowGlassEffect.isAvailable)
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: false)
usesTransparentWindow: WindowBackgroundComposition.policy
.shouldUseTransparentBackgroundWindow(glassEffectAvailable: WindowGlassEffect().isAvailable)

The file uses the CmuxFoundation NSColor.isLightColor extension but only imported
AppKit; it currently resolves via a sibling file's public import under whole-module
compilation, but Swift imports are file-scoped so a per-file/incremental build is
fragile. Make the dependency explicit.
The split-off file uses String(localized:defaultValue:) (Foundation) but had no
imports; it resolves via whole-module compilation today, but Swift imports are
file-scoped so make Foundation explicit. (Other zero-import WindowChrome files are
pure-stdlib enums and correctly need no import.)
…own file

Addresses the cmux-policy file-organization P2 on AppWindowChromeComposition.swift:
AppWindowBackdropControllerDependencies is a separate concrete WindowBackdropControllerDependencies
adapter, not a tightly-coupled helper of the composition struct, so it lives in its own file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts:
#	.github/swift-file-length-budget.tsv
@azooz2003-bit
azooz2003-bit merged commit 936d8db into main Jun 17, 2026
33 of 34 checks passed
@azooz2003-bit
azooz2003-bit deleted the feat-contentview-decomp branch June 17, 2026 20:44
hhsw2015 pushed a commit to hhsw2015/cmux that referenced this pull request Jun 18, 2026
bonsplit submodule: 6 commits (split-button polish, default keep-five-visible)

cmux upstream highlights pulled in:
- Cmd+Shift+K Clear Screen Keep Scrollback (manaflow-ai#6139)
- Window chrome domain extracted from ContentView -> CmuxAppKitSupportUI (manaflow-ai#6147)
- Sidebar models extracted to CmuxSidebar package (Status/Git/Detail/Layout)
- PreferredEditor*Settings -> PreferredEditorService (CmuxFileOpen)
- Renderer realization (off-screen GPU memory reclaim)

Adapter changes (fork-side):
- Resolve 5 conflict deletions (SentryNoiseFilter, Window backdrop/glass moved)
- Take upstream TerminalSection/TerminalCatalogSection/PostHogAnalytics
- Delete 10 local Sidebar* type defs in Workspace.swift (484 lines, now in CmuxSidebar)
- Add 'import CmuxSidebar / CmuxFileOpen / CmuxAppKitSupportUI / CmuxCommandPalette
  / CmuxNotifications' to consumers
- Stub fork-only TS methods on local TerminalSurface:
  clearScreenKeepingScrollback (returns false; not used in fork build)
- Stub v2BrowserFindWithScript body (broken closure scope post-merge,
  cmux_term doesn't use browser-find RPCs)
- Replace v2BrowserFindFirst/Last/Nth/FrameSelect ctx.webView -> browserPanel.webView
- v2RunJavaScript: rename param world->contentWorld inside body
- Wrap v2AwaitCallback calls in MainActor.assumeIsolated for nonisolated callers
- Stub PostHogAnalytics.flushForApplicationTermination (removed upstream)
- AppScrollerStylePolicy.applyAtLaunch -> direct UserDefaults write
- SidebarBranchOrdering: add () for instance methods (multi-line sed missed)
- SidebarBranchOrdering.orderedPanelIds removed -> uuid-sort fallback
- ColorSchemePreference convert local -> CmuxTerminalCore type at boundary
- @mainactor annotations on cmuxShouldUseTransparentBackgroundWindow,
  cmuxShouldUseClearWindowBackground, openCmuxSettingsFileInEditor,
  applyWindowBackgroundIfActive
- WindowGlassEffect: () for instance ctor

Verified intact: 6 cmux_term v2 handlers, chat_source.py, 14 Python lib
files, herdrInbound case.

This branch was successfully deployed

1 active deployment
Preview – cmux — dffbd4ee Deployed Jun 17, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant