Skip to content

Support macOS clear glass background blur - #3313

Merged
lawrencecchen merged 7 commits into
mainfrom
task-background-blur-macos-glass-clear
Apr 30, 2026
Merged

lawrencecchen merged 7 commits into
mainfrom
task-background-blur-macos-glass-clear

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Apr 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Support background-blur = macos-glass-clear and macos-glass-regular in cmux window appearance.
  • Use Ghostty glass blur config to force transparent hosting, clear the normal root backdrop, and choose the native clear/regular glass style.
  • Add parser and window appearance unit coverage for the new glass path.

Testing

  • ./scripts/reload.sh --tag bgclr passed.

Issues

  • Task: support background-blur = macos-glass-clear in cmux

Summary by cubic

Adds native macOS glass background blur for terminal windows, including a clear glass style, applied at the window root for safe layering. Glass forces transparent hosting at any opacity, tints from the terminal background, clears native titlebar fills, and updates tint when the window gains/loses focus; fulfills the task to support background-blur = macos-glass-clear.

  • New Features

    • Config: parse background-blur (macos-glass-clear, macos-glass-regular, true/radius); snapshots/signatures include blur/style to drive refresh.
    • Rendering: apply glass at the window root with a background layer and foreground container; support regular/clear; fall back to NSVisualEffectView; treat glass as transparent even at 1.0; add inactive tint overlay that reacts to key window state; clear titlebar backgrounds only when glass is active.
    • Portals: central installation target so terminal/browser portals mount above glass and below SwiftUI; auto geometry resync when the glass root changes.
    • Infra: WindowAccessor accepts a refreshID; appearance.appKitWindowMutationID is used to re-run window setup on appearance changes.
  • Bug Fixes

    • Apply glass at the window root to preserve AppKit controls and layering; restore the original content view and layout on removal.
    • Reset compositor blur when switching to/from macOS glass; skip legacy blur when glass is active and include glass style in transparency decisions.
    • Refresh native glass tint on key window changes; avoid duplicate file-drop overlay constraints by checking existing attachments.
    • Tests cover glass lifecycle and layering (including portal target), key/not-key tint behavior, WindowAccessor refresh dedupe, parsing, snapshot decisions, and transparency outcomes.

Written for commit 7914f4e. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added configurable background-blur (disabled, boolean, macOS glass styles, or numeric radius) and propagated it to terminal/window/titlebar behavior and appearance signatures.
    • Window glass effects gain explicit style/tint support, reuse/update semantics, and restore original content hierarchy on removal.
    • Window-accessor deduping now keys by a refresh ID to control callback invocation.
  • Bug Fixes

    • Avoid unnecessary overlay reattach/remove cycles; synchronize geometry when glass state truly changes; conditional native titlebar backdrop clearing for glass style.
  • Tests

    • Expanded parsing, glass-style, snapshot, transparency decision, and content-restoration tests.

@vercel

vercel Bot commented Apr 29, 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 Apr 30, 2026 2:35am
cmux-staging Building Building Preview, Comment Apr 30, 2026 2:35am

@coderabbitai

coderabbitai Bot commented Apr 29, 2026 •

Copy link
Copy Markdown

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

Adds Ghostty background-blur support through config, snapshots, and GhosttyApp; refactors window-glass into a GlassBackgroundView with a style parameter and reuse semantics; updates ContentView titlebar/backdrop handling and file-drop overlay idempotency; introduces refreshID-based deduping in WindowAccessor and routes portal installation to WindowGlassEffect helpers.

Changes

Cohort / File(s) Summary
Configuration
Sources/GhosttyConfig.swift
Add backgroundBlur property and parse background-blur directive (boolean, named macOS glass tokens, or numeric radius).
Appearance model & plumbing
Sources/Windowing/WindowAppearanceSnapshot.swift, Sources/WorkspaceContentView.swift
Add GhosttyBackgroundBlur, thread terminalBackgroundBlur and optional terminalGlassTintColor into snapshots; derive WindowGlass style from blur and include blur in appearance mutation IDs and Workspace signature.
Ghostty app & terminal view
Sources/GhosttyTerminalView.swift
Add defaultBackgroundBlur, update applyDefaultBackground(...) signature and logic, plumb blur into transparency/blur decisions and logging, skip numeric blur when macOS-glass style is used.
Window glass effect core
Sources/Windowing/WindowGlassEffect.swift
Introduce WindowGlassEffect.Style, new GlassRoot/GlassBackgroundView hierarchy (wrap original contentView), add apply/remove reuse/update semantics, tint overlay, native-style setters, and helpers to query original/foreground containers.
ContentView & titlebar/backdrop
Sources/ContentView.swift, Sources/WorkspaceContentView.swift
Make file-drop overlay installation idempotent via constraint-based check; use WindowGlassEffect.originalContentView(for:) when available; capture whether glass root changed and only schedule external geometry sync when actual changes occur; titlebar backdrop sync accepts usesGlassStyle and conditionally clears native titlebar backgrounds.
Portal installation & portals
Sources/BrowserWindowPortal.swift, Sources/TerminalWindowPortal.swift
Delegate installationTarget selection to WindowGlassEffect.portalInstallationTarget(for:), falling back to prior contentView/superview behavior when nil.
Window accessor / dedupe
Sources/WindowAccessor.swift
Add optional refreshID to WindowAccessor; coordinator deduping now suppresses callbacks only when same window + equal refreshID, and updates stored state on invocation.
Tests
cmuxTests/* (GhosttyConfigTests.swift, WindowAndDragTests.swift, WindowAppearanceSnapshotTests.swift)
Expand parsing tests for macos-glass-clear; add snapshot and transparency-decision tests for macOS-glass; refactor glass apply/remove tests to use new helpers and identifiers; add WindowAccessorTests for dedupe semantics.

Sequence Diagram(s)

sequenceDiagram
    participant Config as GhosttyConfig
    participant App as GhosttyApp
    participant Snapshot as WindowAppearanceSnapshot
    participant Glass as WindowGlassEffect
    participant Window as NSWindow

    Config->>App: provide backgroundBlur
    App->>Snapshot: build appearance (terminalBackgroundBlur, tint)
    Snapshot->>App: resolved glass settings (style, shouldApply)
    App->>Glass: apply(to: window, tintColor, style)
    Glass->>Window: install/update GlassRoot/GlassBackgroundView and foregroundContainer
    Window-->>Glass: report contentView/root state
    Glass-->>App: applied/changed (indicates whether root changed)
    App->>PortalRegistries: schedule external geometry sync if changed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐇 I nudged the blur into the light,
I wrapped the glass beneath each view,
A tint, a root that fits just right,
Windows clear — the spring hops through. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main feature being added—macOS clear glass background blur support—and is concise and specific.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed PR description includes the core required sections: summary of changes and rationale, testing information, and a checklist. However, the description lacks a demo video link and bot review comments section.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 task-background-blur-macos-glass-clear

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Apr 29, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds background-blur = macos-glass-clear and macos-glass-regular support by introducing a GhosttyBackgroundBlur enum, wiring it through the config parse and C API paths, and using a private-API setStyle: call on NSGlassEffectView to select the clear or regular glass variant.

  • P1 — shouldApply bypasses glassEffectAvailable: When isMacOSGlassStyle is true, WindowGlassSettingsSnapshot.shouldApply() returns true unconditionally, ignoring the glassEffectAvailable parameter. On macOS < 26, this forces transparent hosting and a .clear backdrop policy even though NSGlassEffectView is absent, potentially breaking normal background rendering on older OS versions.

Confidence Score: 3/5

The shouldApply logic gap could produce incorrect window appearance on macOS < 26; should be addressed before merging to a broad audience.

One P1 (glass-style forcing transparent hosting on macOS < 26 regardless of availability) pulls the score below the P1 ceiling of 4. The remaining P2 findings (IMP nil-guard, Int16 width assumption, missing regular-variant test) are non-blocking but add minor risk.

Sources/Windowing/WindowAppearanceSnapshot.swift — the shouldApply method needs to respect glassEffectAvailable for glass styles.

Important Files Changed

Filename Overview
Sources/Windowing/WindowAppearanceSnapshot.swift Adds GhosttyBackgroundBlur enum and integrates blur state into snapshot/policy; shouldApply ignores glassEffectAvailable when glass style is set, risking incorrect behaviour on macOS < 26
Sources/Windowing/WindowGlassEffect.swift Adds Style enum and private-API style setter via unsafeBitCast; IMP nil-guard is absent but low-risk given the preceding responds(to:) check
Sources/GhosttyTerminalView.swift Threads defaultBackgroundBlur through background-update pipeline and conditionally skips applyWindowBlurIfNeeded for glass styles; C API reads Int16 which may silently truncate if the underlying field is wider
Sources/GhosttyConfig.swift Adds backgroundBlur field and parseBackgroundBlur switch; parsing looks correct with appropriate range cap for numeric radii
Sources/ContentView.swift Straightforward pass-through of style from windowGlassSettings to WindowGlassEffect.apply
Sources/WorkspaceContentView.swift Adds backgroundBlur to the config cache key to trigger redraws on blur changes — correct and complete
cmuxTests/GhosttyConfigTests.swift Good snapshot and transparency decision coverage for the glass-clear path; missing symmetric test for macos-glass-regular parse branch

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Ghostty config file\nbackground-blur = macos-glass-clear"] --> B["GhosttyConfig.parseBackgroundBlur()\n→ .macosGlassClear"]
    A2["C API ghostty_config_get\n(Int16 value: -2)"] --> B2["GhosttyBackgroundBlur.init(cValue:)\n→ .macosGlassClear"]
    B --> C["GhosttyApp.defaultBackgroundBlur\n(stored, change notified)"]
    B2 --> C
    C --> D["WindowAppearanceSnapshot.current()\nterminalBackgroundBlur = .macosGlassClear"]
    D --> E{"terminalBackgroundBlur\n.isMacOSGlassStyle?"}
    E -- yes --> F["terminalBackdropPolicy() → .clear\n(clears normal root backdrop)"]
    E -- yes --> G["WindowGlassSettingsSnapshot\n.shouldApply() → true ⚠️ ignores glassEffectAvailable"]
    E -- no --> H["Normal ghosttyTerminalBackdrop policy"]
    G --> I{"NSGlassEffectView\navailable? (macOS 26+)"}
    I -- yes --> J["WindowGlassEffect.apply()\nstyle: .clear (rawValue 1)\nunsafeBitCast IMP → setStyle:"]
    I -- no --> K["NSVisualEffectView fallback\n(no style distinction)"]
    F --> L["Window: backgroundColor = clear\nisOpaque = false\nskip applyWindowBlurIfNeeded"]
Loading

Comments Outside Diff (1)

  1. Sources/Windowing/WindowAppearanceSnapshot.swift, line 173-182 (link)

    P1 glassEffectAvailable ignored for glass styles

    shouldApply(glassEffectAvailable:) always returns true when isMacOSGlassStyle is true, bypassing the glassEffectAvailable guard that prevents window-glass from being applied on macOS < 26. On macOS 15 and earlier, this forces the NSVisualEffectView fallback path — meaning both macos-glass-clear and macos-glass-regular produce an identical .behindWindow blur with no style distinction. More importantly, the transparent-hosting and .clear backdrop policies are still activated unconditionally, which can break the normal background rendering on those OS versions since NSGlassEffectView is absent.

    func shouldApply(glassEffectAvailable: Bool = WindowGlassEffect.isAvailable) -> Bool {
        if terminalBackgroundBlur.isMacOSGlassStyle {
    -       return true
    +       return glassEffectAvailable
        }
        return cmuxShouldApplyWindowGlass(
            sidebarBlendMode: sidebarBlendModeRawValue,
            bgGlassEnabled: isEnabled,
            glassEffectAvailable: glassEffectAvailable
        )
    }

Reviews (1): Last reviewed commit: "Support macOS clear glass background blu..." | Re-trigger Greptile

Comment thread Sources/GhosttyTerminalView.swift
Comment thread cmuxTests/GhosttyConfigTests.swift
Comment thread Sources/Windowing/WindowGlassEffect.swift Outdated

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmuxTests/GhosttyConfigTests.swift`:
- Around line 215-219: Add a second assertion exercising the other public blur
value: in the testParseBackgroundBlurReadsMacOSGlassClear test (or a new
adjacent test), call config.parse("background-blur = macos-glass-regular") on a
fresh GhosttyConfig and assert that config.backgroundBlur == .macosGlassRegular
so both macos-glass-clear and macos-glass-regular parser paths are covered.

In `@Sources/GhosttyTerminalView.swift`:
- Around line 3870-3880: The compositing blur state can remain stale because
applyWindowBlurIfNeeded(window) is skipped when
defaultBackgroundBlur.isMacOSGlassStyle; always invoke the blur updater on every
background-application path (including inside cmuxShouldUseClearWindowBackground
handling) so transitions/disable are applied and stale CGS blur radius is reset
— ensure applyWindowBlurIfNeeded(window) is called even for macOS glass-style
branches and when blur should be disabled pass a radius of 0; update the other
similar branch (the code around the other occurrence near the second location)
the same way and keep logBackground calls as-is.

In `@Sources/WorkspaceContentView.swift`:
- Line 567: The refresh logic currently gating calls to
applyWindowBackgroundIfActive() only on background color/opacity changes must
also consider config.backgroundBlur so blur-only updates run; update the
comparison/dirty-checks (the branches around where
applyWindowBackgroundIfActive() is invoked) to include backgroundBlur in the
equality/changed set and always call applyWindowBackgroundIfActive() when blur
changed, ensuring applyWindowBackgroundIfActive() receives a radius of 0 to
explicitly disable blur when appropriate (instead of skipping the update).
Locate references to applyWindowBackgroundIfActive(), config.backgroundBlur, and
the surrounding titlebar/window refresh logic (the conditional blocks around the
existing background color/opacity checks) and adjust them so blur changes cannot
be skipped and blur is explicitly applied or removed every update.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 10a9bc3d-6b6a-4649-96d3-d731520677cc

📥 Commits

Reviewing files that changed from the base of the PR and between e181f99 and 4a80c0c.

📒 Files selected for processing (7)
  • Sources/ContentView.swift
  • Sources/GhosttyConfig.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Windowing/WindowAppearanceSnapshot.swift
  • Sources/Windowing/WindowGlassEffect.swift
  • Sources/WorkspaceContentView.swift
  • cmuxTests/GhosttyConfigTests.swift

Comment thread cmuxTests/GhosttyConfigTests.swift
Comment thread Sources/GhosttyTerminalView.swift
Comment thread Sources/WorkspaceContentView.swift

@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: 1

🧹 Nitpick comments (2)
Sources/Windowing/WindowGlassEffect.swift (1)

7-16: ⚡ Quick win

Replace the raw glass-style integers with SDK constants if they're available.

Hard-coding 0/1 makes the clear/regular mapping easy to invert silently if the native enum ordering differs from what this code assumes. If the macOS 26 SDK exposes the typed style enum, prefer that and verify both modes render distinctly on-device.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Windowing/WindowGlassEffect.swift` around lines 7 - 16, The Style
enum currently returns hard-coded integers in fileprivate var
rawNSGlassEffectViewStyle which can break if native ordering changes; update
rawNSGlassEffectViewStyle to return the platform SDK's typed constants or native
enum cases (for example use the macOS SDK's NSGlassEffectView/NSVisualEffectView
style constants or map from the native enum's .regular/.clear cases) instead of
0/1, using the native enum's cases or rawValue to drive the mapping in Style
(keep the mapping inside Style), and verify on-device that both .regular and
.clear produce distinct visuals.
Sources/Windowing/WindowAppearanceSnapshot.swift (1)

169-170: ⚡ Quick win

Don't force .regular on the legacy window-glass path.

style now resolves to .regular for .disabled and .radius(_), so existing callers that enable window glass will start explicitly mutating the native style too. I'd keep this optional and only return a concrete style for the new macos-glass-* modes, then verify the pre-PR bg-glass appearance stays unchanged.

Suggested change
-    var style: WindowGlassEffect.Style {
-        terminalBackgroundBlur.windowGlassStyle ?? .regular
+    var style: WindowGlassEffect.Style? {
+        terminalBackgroundBlur.windowGlassStyle
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Windowing/WindowAppearanceSnapshot.swift` around lines 169 - 170, The
computed property WindowAppearanceSnapshot.var style should not force a fallback
of .regular for legacy window-glass cases; change the logic so style returns
terminalBackgroundBlur.windowGlassStyle as an Optional (nil for
legacy/disabled/radius(_) cases) and only map to a concrete
WindowGlassEffect.Style for the new macos-glass-* modes, ensuring callers that
rely on the old bg-glass appearance continue to receive nil and thus preserve
native behavior instead of being forced to .regular.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/GhosttyConfig.swift`:
- Around line 485-500: The parseBackgroundBlur helper currently maps malformed
tokens to .disabled which can overwrite a prior valid setting; change
parseBackgroundBlur to return an optional GhosttyBackgroundBlur? (i.e.
GhosttyBackgroundBlur?) and return nil for invalid tokens so callers can ignore
malformed values; keep explicit mappings for "false" -> .disabled, "true" ->
.radius(20), "macos-glass-regular" -> .macosGlassRegular, "macos-glass-clear" ->
.macosGlassClear, and only return .radius(radius) when
parseIntegerLiteral(value) yields a valid radius (1...UInt8.max), otherwise
return nil. Ensure callers that consume parseBackgroundBlur handle the optional
by keeping the existing value when nil.

---

Nitpick comments:
In `@Sources/Windowing/WindowAppearanceSnapshot.swift`:
- Around line 169-170: The computed property WindowAppearanceSnapshot.var style
should not force a fallback of .regular for legacy window-glass cases; change
the logic so style returns terminalBackgroundBlur.windowGlassStyle as an
Optional (nil for legacy/disabled/radius(_) cases) and only map to a concrete
WindowGlassEffect.Style for the new macos-glass-* modes, ensuring callers that
rely on the old bg-glass appearance continue to receive nil and thus preserve
native behavior instead of being forced to .regular.

In `@Sources/Windowing/WindowGlassEffect.swift`:
- Around line 7-16: The Style enum currently returns hard-coded integers in
fileprivate var rawNSGlassEffectViewStyle which can break if native ordering
changes; update rawNSGlassEffectViewStyle to return the platform SDK's typed
constants or native enum cases (for example use the macOS SDK's
NSGlassEffectView/NSVisualEffectView style constants or map from the native
enum's .regular/.clear cases) instead of 0/1, using the native enum's cases or
rawValue to drive the mapping in Style (keep the mapping inside Style), and
verify on-device that both .regular and .clear produce distinct visuals.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9104d080-486b-4add-afd6-8f5512cd7119

📥 Commits

Reviewing files that changed from the base of the PR and between 4a80c0c and f8ad970.

📒 Files selected for processing (8)
  • Sources/ContentView.swift
  • Sources/GhosttyConfig.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Windowing/WindowAppearanceSnapshot.swift
  • Sources/Windowing/WindowGlassEffect.swift
  • Sources/WorkspaceContentView.swift
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/WindowAndDragTests.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • Sources/WorkspaceContentView.swift
  • Sources/GhosttyTerminalView.swift
  • cmuxTests/GhosttyConfigTests.swift

Comment thread Sources/GhosttyConfig.swift Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f8ad970244

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/GhosttyTerminalView.swift Outdated

@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.

♻️ Duplicate comments (2)
Sources/WorkspaceContentView.swift (1)

631-637: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Blur-only updates still skip titlebar/window background refresh paths.

config.backgroundBlur is now part of the signature, but blur-only changes still won’t trigger onThemeRefreshRequest or applyWindowBackgroundIfActive() because these flags ignore blur deltas. Please include blur in both refresh predicates.

💡 Suggested patch
         let configChanged = previousSignature != nextSignature
         let backgroundChanged = previousBackgroundHex != next.backgroundColor.hexString()
         let opacityChanged = abs(config.backgroundOpacity - next.backgroundOpacity) > 0.0001
+        let blurChanged = config.backgroundBlur != next.backgroundBlur
         let shouldForceInitialApply = forceInitialApply || reason == "onAppear"
-        let shouldRequestTitlebarRefresh = backgroundChanged || opacityChanged || shouldForceInitialApply
+        let shouldRequestTitlebarRefresh =
+            backgroundChanged || opacityChanged || blurChanged || shouldForceInitialApply
         let shouldApplyChrome = configChanged || shouldForceInitialApply
-        let shouldRefreshWindowBackground = backgroundChanged || opacityChanged || shouldForceInitialApply
+        let shouldRefreshWindowBackground =
+            backgroundChanged || opacityChanged || blurChanged || shouldForceInitialApply

Based on learnings: “CGS window background blur is stateful… always call cmuxApplyBackgroundBlur(...), passing radius 0 when blur should be disabled.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/WorkspaceContentView.swift` around lines 631 - 637, Add a blur-delta
boolean and include it in the titlebar/window refresh predicates: compute
something like let blurChanged = config.backgroundBlur != next.backgroundBlur
(or compare previousBackgroundBlur and next.backgroundBlur if those exist) and
then update shouldRequestTitlebarRefresh and shouldRefreshWindowBackground to
include blurChanged (i.e. let shouldRequestTitlebarRefresh = backgroundChanged
|| opacityChanged || blurChanged || shouldForceInitialApply and similarly for
shouldRefreshWindowBackground) so blur-only changes trigger
onThemeRefreshRequest/applyWindowBackgroundIfActive().
Sources/GhosttyConfig.swift (1)

420-421: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Malformed background-blur values currently wipe prior valid config.

Invalid tokens are converted to .disabled and assigned immediately, so a typo in a later config/include can silently reset a previously valid blur mode instead of being ignored.

Suggested fix
-                case "background-blur":
-                    backgroundBlur = Self.parseBackgroundBlur(value)
+                case "background-blur":
+                    if let blur = Self.parseBackgroundBlur(value) {
+                        backgroundBlur = blur
+                    }

-    private static func parseBackgroundBlur(_ value: String) -> GhosttyBackgroundBlur {
+    private static func parseBackgroundBlur(_ value: String) -> GhosttyBackgroundBlur? {
         switch value {
         case "false":
-            return .disabled
+            return .disabled
         case "true":
-            return .radius(20)
+            return .radius(20)
         case "macos-glass-regular":
-            return .macosGlassRegular
+            return .macosGlassRegular
         case "macos-glass-clear":
-            return .macosGlassClear
+            return .macosGlassClear
         default:
             guard let radius = parseIntegerLiteral(value), radius > 0, radius <= Int(UInt8.max) else {
-                return .disabled
+                return nil
             }
             return .radius(radius)
         }
     }

Also applies to: 485-500

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/GhosttyConfig.swift` around lines 420 - 421, The current assignment
backgroundBlur = Self.parseBackgroundBlur(value) overwrites a prior valid
setting because parseBackgroundBlur converts malformed tokens to .disabled;
change the parsing/assignment so invalid inputs are ignored instead of assigned:
update Self.parseBackgroundBlur to return an optional (e.g. BackgroundBlur?) or
a Result and have the caller check the return before assigning (only assign
backgroundBlur when the parse result is non-nil / successful), and apply the
same guard/conditional assignment pattern to the other parsing site that uses
Self.parseBackgroundBlur in the file (the similar block around the later
background blur handling).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Sources/GhosttyConfig.swift`:
- Around line 420-421: The current assignment backgroundBlur =
Self.parseBackgroundBlur(value) overwrites a prior valid setting because
parseBackgroundBlur converts malformed tokens to .disabled; change the
parsing/assignment so invalid inputs are ignored instead of assigned: update
Self.parseBackgroundBlur to return an optional (e.g. BackgroundBlur?) or a
Result and have the caller check the return before assigning (only assign
backgroundBlur when the parse result is non-nil / successful), and apply the
same guard/conditional assignment pattern to the other parsing site that uses
Self.parseBackgroundBlur in the file (the similar block around the later
background blur handling).

In `@Sources/WorkspaceContentView.swift`:
- Around line 631-637: Add a blur-delta boolean and include it in the
titlebar/window refresh predicates: compute something like let blurChanged =
config.backgroundBlur != next.backgroundBlur (or compare previousBackgroundBlur
and next.backgroundBlur if those exist) and then update
shouldRequestTitlebarRefresh and shouldRefreshWindowBackground to include
blurChanged (i.e. let shouldRequestTitlebarRefresh = backgroundChanged ||
opacityChanged || blurChanged || shouldForceInitialApply and similarly for
shouldRefreshWindowBackground) so blur-only changes trigger
onThemeRefreshRequest/applyWindowBackgroundIfActive().

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec43e873-82f1-4a53-bdb9-ebebc482ae78

📥 Commits

Reviewing files that changed from the base of the PR and between f8ad970 and 9faf327.

📒 Files selected for processing (8)
  • Sources/ContentView.swift
  • Sources/GhosttyConfig.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Windowing/WindowAppearanceSnapshot.swift
  • Sources/Windowing/WindowGlassEffect.swift
  • Sources/WorkspaceContentView.swift
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/WindowAndDragTests.swift
✅ Files skipped from review due to trivial changes (1)
  • Sources/GhosttyTerminalView.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • Sources/Windowing/WindowGlassEffect.swift

@lawrencecchen
lawrencecchen force-pushed the task-background-blur-macos-glass-clear branch from 9faf327 to 204b672 Compare April 30, 2026 00:31

@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.

♻️ Duplicate comments (4)
Sources/GhosttyConfig.swift (1)

420-421: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Preserve the existing blur value on parse failures.

The new parser still maps every unrecognized background-blur token to .disabled, so a typo in a later config can silently clobber an earlier valid blur mode. Keep the prior value when parsing fails instead of resetting it here.

💡 Suggested fix
                 case "background-blur":
-                    backgroundBlur = Self.parseBackgroundBlur(value)
+                    if let blur = Self.parseBackgroundBlur(value) {
+                        backgroundBlur = blur
+                    }
@@
-    private static func parseBackgroundBlur(_ value: String) -> GhosttyBackgroundBlur {
+    private static func parseBackgroundBlur(_ value: String) -> GhosttyBackgroundBlur? {
         switch value {
         case "false":
             return .disabled
         case "true":
             return .radius(20)
         case "macos-glass-regular":
             return .macosGlassRegular
         case "macos-glass-clear":
             return .macosGlassClear
         default:
             guard let radius = parseIntegerLiteral(value), radius > 0, radius <= Int(UInt8.max) else {
-                return .disabled
+                return nil
             }
             return .radius(radius)
         }
     }

Based on learnings: malformed background-blur values should be ignored so earlier valid settings survive.

Also applies to: 485-501

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/GhosttyConfig.swift` around lines 420 - 421, The current parsing in
the "background-blur" case unconditionally assigns backgroundBlur =
Self.parseBackgroundBlur(value), which treats unknown/malformed tokens as
.disabled and can clobber a previously valid value; change this to only update
backgroundBlur when the parser returns a valid result (i.e., non-nil or a
success case) and otherwise leave backgroundBlur unchanged. Locate the
"background-blur" switch case and adjust the logic around
Self.parseBackgroundBlur(value) so it preserves the existing backgroundBlur on
parse failure (apply the same defensive check to the other parse sites in the
nearby block at lines ~485–501 that use the same parser).
Sources/WorkspaceContentView.swift (1)

563-573: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Blur-only changes still skip the refresh path.

backgroundBlur now affects configChanged, but shouldRequestTitlebarRefresh and shouldRefreshWindowBackground still ignore it. A blur-only config change can therefore update config without reapplying the window blur/glass state.

💡 Suggested fix
         let nextUsesHostLayerBackground = GhosttyApp.shared.usesHostLayerBackground
         let nextSignature = Self.ghosttyAppearanceSignature(
             next,
             usesHostLayerBackground: nextUsesHostLayerBackground
         )
+        let blurChanged = config.backgroundBlur != next.backgroundBlur
         let eventLabel = backgroundEventId.map(String.init) ?? "nil"
         let sourceLabel = backgroundSource ?? "nil"
         let payloadLabel = notificationPayloadHex ?? "nil"
         let configChanged = previousSignature != nextSignature
         let backgroundChanged = previousBackgroundHex != next.backgroundColor.hexString()
         let opacityChanged = abs(config.backgroundOpacity - next.backgroundOpacity) > 0.0001
         let shouldForceInitialApply = forceInitialApply || reason == "onAppear"
-        let shouldRequestTitlebarRefresh = backgroundChanged || opacityChanged || shouldForceInitialApply
+        let shouldRequestTitlebarRefresh =
+            backgroundChanged || opacityChanged || blurChanged || shouldForceInitialApply
         let shouldApplyChrome = configChanged || shouldForceInitialApply
-        let shouldRefreshWindowBackground = backgroundChanged || opacityChanged || shouldForceInitialApply
+        let shouldRefreshWindowBackground =
+            backgroundChanged || opacityChanged || blurChanged || shouldForceInitialApply

Based on learnings: CGS window background blur is stateful, so background updates must explicitly reapply or clear the blur radius.

Also applies to: 631-637

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/WorkspaceContentView.swift` around lines 563 - 573, The change to
include backgroundBlur in the appearance signature means blur-only updates can
now change config but won't trigger UI refresh; update the decision logic in
shouldRequestTitlebarRefresh and shouldRefreshWindowBackground to consider
changes to config.backgroundBlur (compare old vs new blur) so blur-only diffs
return true, and when a blur change is detected ensure the window blur state is
explicitly reapplied/cleared (call the existing window blur/ glass reapply
routine used elsewhere) so CGS receives the new radius; check the related
configChanged handling that uses ghosttyAppearanceSignature and mirror this
blur-aware refresh behavior there as well.
cmuxTests/GhosttyConfigTests.swift (1)

215-219: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cover macos-glass-regular too.

This still only exercises macos-glass-clear; please add the sibling parse assertion here or in an adjacent test so the new public blur value stays covered.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmuxTests/GhosttyConfigTests.swift` around lines 215 - 219, Add coverage for
the "macos-glass-regular" variant: create either a new test (e.g.,
testParseBackgroundBlurReadsMacOSGlassRegular) or extend
testParseBackgroundBlurReadsMacOSGlassClear to parse "background-blur =
macos-glass-regular" on a GhosttyConfig instance and assert the parsed value
equals the enum case (config.backgroundBlur == .macosGlassRegular) so the public
blur value is exercised.
Sources/GhosttyTerminalView.swift (1)

3870-3888: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't gate the blur updater out of the glass path.

applyWindowBlurIfNeeded(_:) is stateful, so skipping it when defaultBackgroundBlur.isMacOSGlassStyle can leave the previous CGS radius in place when users toggle between radius blur and native glass. Please still drive the reset path on every background application and let the helper clear the compositor state instead of short-circuiting here. Based on learnings: CGS window background blur is stateful. Always call cmuxApplyBackgroundBlur(to: NSWindow, radius: Int) on background updates and pass radius 0 when blur should be disabled (opacity >= 1.0 or configured radius == 0).

Also applies to: 6041-6065

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/GhosttyTerminalView.swift` around lines 3870 - 3888, The blur
reset/update is being skipped when defaultBackgroundBlur.isMacOSGlassStyle,
which leaves previous CGS blur state intact; remove the short-circuit and always
invoke the blur updater so the compositor can be reset—call
applyWindowBlurIfNeeded(window) (or directly cmuxApplyBackgroundBlur(to:radius:)
with radius 0 when blur should be disabled) in both branches after setting
window.backgroundColor/isOpaque, ensuring you pass radius 0 for fully opaque or
configured-radius==0 cases; keep backgroundLogEnabled/logBackground behavior
as-is but ensure the blur helper runs on every background application (also
apply the same change in the other occurrence mentioned).
🧹 Nitpick comments (1)
Sources/Windowing/WindowGlassEffect.swift (1)

95-109: ⚡ Quick win

Make style == nil semantics explicit to prevent stale native glass style.

On a reused GlassBackgroundView, style: nil skips setStyle:. That means a prior .clear style can persist across later re-applies unless the view is recreated. Consider resolving style explicitly in apply (e.g., default .regular) and reserving “preserve current style” for updateTint only.

Proposed direction
-        func configure(
+        func configure(
             tintColor: NSColor?,
             style: Style?,
             cornerRadius: CGFloat?,
-            isKeyWindow: Bool
+            isKeyWindow: Bool,
+            preserveExistingStyleWhenNil: Bool = false
         ) {
+            let resolvedStyle: Style? = {
+                if preserveExistingStyleWhenNil { return style }
+                return style ?? .regular
+            }()
             effectView.layer?.cornerRadius = cornerRadius ?? 0
             if usesNativeGlass {
                 updateNativeGlassConfiguration(
                     on: effectView,
                     color: tintColor,
-                    style: style,
+                    style: resolvedStyle,
                     cornerRadius: cornerRadius
                 )
                 updateInactiveTintOverlay(tintColor: tintColor, isKeyWindow: isKeyWindow)
             } else if let tintColor {
                 ...
             }
         }
-        glassView.configure(
+        glassView.configure(
             tintColor: color,
             style: nil,
             cornerRadius: windowCornerRadius(for: window),
-            isKeyWindow: window.isKeyWindow
+            isKeyWindow: window.isKeyWindow,
+            preserveExistingStyleWhenNil: true
         )

Also applies to: 190-198, 222-229

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Windowing/WindowGlassEffect.swift` around lines 95 - 109, The
configure/apply path currently treats style == nil as "do nothing", letting a
previous native glass style persist; change it so configure/apply resolves nil
to an explicit default (e.g., .regular) before calling
updateNativeGlassConfiguration or setStyle:, ensuring
updateNativeGlassConfiguration(on:effectView, color:tintColor,
style:resolvedStyle, cornerRadius:cornerRadius) always receives a non-nil Style;
reserve the "preserve existing style" semantics for updateTint (or a new
updateTint(preserveStyle: Bool)) so that updateTint can skip changing style when
preservation is intended, while configure/apply always sets an explicit style on
GlassBackgroundView via setStyle:/updateNativeGlassConfiguration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@cmuxTests/GhosttyConfigTests.swift`:
- Around line 215-219: Add coverage for the "macos-glass-regular" variant:
create either a new test (e.g., testParseBackgroundBlurReadsMacOSGlassRegular)
or extend testParseBackgroundBlurReadsMacOSGlassClear to parse "background-blur
= macos-glass-regular" on a GhosttyConfig instance and assert the parsed value
equals the enum case (config.backgroundBlur == .macosGlassRegular) so the public
blur value is exercised.

In `@Sources/GhosttyConfig.swift`:
- Around line 420-421: The current parsing in the "background-blur" case
unconditionally assigns backgroundBlur = Self.parseBackgroundBlur(value), which
treats unknown/malformed tokens as .disabled and can clobber a previously valid
value; change this to only update backgroundBlur when the parser returns a valid
result (i.e., non-nil or a success case) and otherwise leave backgroundBlur
unchanged. Locate the "background-blur" switch case and adjust the logic around
Self.parseBackgroundBlur(value) so it preserves the existing backgroundBlur on
parse failure (apply the same defensive check to the other parse sites in the
nearby block at lines ~485–501 that use the same parser).

In `@Sources/GhosttyTerminalView.swift`:
- Around line 3870-3888: The blur reset/update is being skipped when
defaultBackgroundBlur.isMacOSGlassStyle, which leaves previous CGS blur state
intact; remove the short-circuit and always invoke the blur updater so the
compositor can be reset—call applyWindowBlurIfNeeded(window) (or directly
cmuxApplyBackgroundBlur(to:radius:) with radius 0 when blur should be disabled)
in both branches after setting window.backgroundColor/isOpaque, ensuring you
pass radius 0 for fully opaque or configured-radius==0 cases; keep
backgroundLogEnabled/logBackground behavior as-is but ensure the blur helper
runs on every background application (also apply the same change in the other
occurrence mentioned).

In `@Sources/WorkspaceContentView.swift`:
- Around line 563-573: The change to include backgroundBlur in the appearance
signature means blur-only updates can now change config but won't trigger UI
refresh; update the decision logic in shouldRequestTitlebarRefresh and
shouldRefreshWindowBackground to consider changes to config.backgroundBlur
(compare old vs new blur) so blur-only diffs return true, and when a blur change
is detected ensure the window blur state is explicitly reapplied/cleared (call
the existing window blur/ glass reapply routine used elsewhere) so CGS receives
the new radius; check the related configChanged handling that uses
ghosttyAppearanceSignature and mirror this blur-aware refresh behavior there as
well.

---

Nitpick comments:
In `@Sources/Windowing/WindowGlassEffect.swift`:
- Around line 95-109: The configure/apply path currently treats style == nil as
"do nothing", letting a previous native glass style persist; change it so
configure/apply resolves nil to an explicit default (e.g., .regular) before
calling updateNativeGlassConfiguration or setStyle:, ensuring
updateNativeGlassConfiguration(on:effectView, color:tintColor,
style:resolvedStyle, cornerRadius:cornerRadius) always receives a non-nil Style;
reserve the "preserve existing style" semantics for updateTint (or a new
updateTint(preserveStyle: Bool)) so that updateTint can skip changing style when
preservation is intended, while configure/apply always sets an explicit style on
GlassBackgroundView via setStyle:/updateNativeGlassConfiguration.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a4f2f19c-cf7c-470f-b047-e35a82b20be5

📥 Commits

Reviewing files that changed from the base of the PR and between 9faf327 and 204b672.

📒 Files selected for processing (8)
  • Sources/ContentView.swift
  • Sources/GhosttyConfig.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Windowing/WindowAppearanceSnapshot.swift
  • Sources/Windowing/WindowGlassEffect.swift
  • Sources/WorkspaceContentView.swift
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/WindowAndDragTests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • Sources/Windowing/WindowAppearanceSnapshot.swift

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 204b67244a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/Windowing/WindowGlassEffect.swift Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f3c1443b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/Windowing/WindowGlassEffect.swift

@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.

🧹 Nitpick comments (1)
cmuxTests/WindowAndDragTests.swift (1)

41-43: ⚡ Quick win

Assert portal-installation cleanup on remove.

This test proves the portal installation target exists in the applied state on Line 36, but it never checks that WindowGlassEffect.remove(from:) clears that association. Adding the symmetric XCTAssertNil(WindowGlassEffect.portalInstallationTarget(for: window)) here would catch stale portal-host targets leaking across glass lifecycle transitions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmuxTests/WindowAndDragTests.swift` around lines 41 - 43, The test currently
asserts that foregroundContainer and originalContentView are cleared and that no
glass background remains after removing glass, but it omits verifying the portal
installation target is cleared; update the post-removal assertions in the test
to also call XCTAssertNil(WindowGlassEffect.portalInstallationTarget(for:
window)) to ensure WindowGlassEffect.remove(from:) clears the
portal-installation association and prevents leaking stale portal-host targets.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@cmuxTests/WindowAndDragTests.swift`:
- Around line 41-43: The test currently asserts that foregroundContainer and
originalContentView are cleared and that no glass background remains after
removing glass, but it omits verifying the portal installation target is
cleared; update the post-removal assertions in the test to also call
XCTAssertNil(WindowGlassEffect.portalInstallationTarget(for: window)) to ensure
WindowGlassEffect.remove(from:) clears the portal-installation association and
prevents leaking stale portal-host targets.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3e854641-1998-4fb5-8413-27ab5e76f3bc

📥 Commits

Reviewing files that changed from the base of the PR and between 204b672 and 2f3c144.

📒 Files selected for processing (7)
  • Sources/BrowserWindowPortal.swift
  • Sources/ContentView.swift
  • Sources/TerminalWindowPortal.swift
  • Sources/WindowAccessor.swift
  • Sources/Windowing/WindowAppearanceSnapshot.swift
  • Sources/Windowing/WindowGlassEffect.swift
  • cmuxTests/WindowAndDragTests.swift

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 582c4f1fab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/Windowing/WindowGlassEffect.swift
@lawrencecchen
lawrencecchen merged commit 4f7360b into main Apr 30, 2026
19 checks passed

This branch was successfully deployed

1 active deployment
Preview – cmux — 7914f4e4 Deployed Apr 30, 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