feat(client): OS-native window backdrop materials (UI/UX v3 P2c) - #75
Merged
Conversation
Records the approved design for the last unchecked P2 item: a `window.backdrop` config mapped to the native material on each OS. Two findings from the pre-flight read are worth calling out, because both contradict what the repo currently documents: - `apply_acrylic_blur` passes `4` to `DWMWA_SYSTEMBACKDROP_TYPE`, which is `DWMSBT_TABBEDWINDOW` — Mica Alt, not Acrylic. The function name, its doc comment, the crate CLAUDE.md and CHANGELOG.md:2898 all say "Acrylic" and all name the constant `DWMWCP_ACRYLIC`, which belongs to the corner-preference enum. Only the plan got it right. - Secondary OS windows from `spawn_os_window` never get a backdrop at all, and neither path treats a requested backdrop as a reason to create the window transparent. `window-vibrancy` is vetted and adopted for macOS only: its Windows Acrylic path falls back to the undocumented `SetWindowCompositionAttribute` on Windows 10, whose resize cost the crate's own README documents. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eight tasks across two PRs. Two of them are shaped by tests that already exist: removing `macos_window_background_blur` breaks `doc_matches_schema::complete_example_uses_only_real_config_keys` until CONFIGURATION.md is updated, and adding a Window row breaks the `window_row_labels().len() == WINDOW_ROW_COUNT` guard until the search labels follow. Both failures are scheduled as steps rather than avoided. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The resolver takes the target OS as a parameter instead of reading cfg!, which is what lets the Windows and macOS routing be asserted from the Linux machines that are the only ones running these tests. auto resolves to Mica Alt on Windows and to nothing on macOS: both are what ships today, and a default that changed either would alter an existing user's window on upgrade.
macos_window_background_blur has never had a reader anywhere in the workspace, while CONFIGURATION.md and ARCHITECTURE.md both described it as a working setting. It is removed rather than deprecated: the TOML parser ignores unknown keys, so config files still carrying it keep loading, and a test pins that. Note on doc_matches_schema: `complete_example_uses_only_real_config_keys` only compares top-level table/key names, so it did not fail on its own for this nested `[window]` field (verified by running the suite before editing the docs — all tests still passed). The drift was caught by manual review instead. `removed_phantom_keys_do_not_return` now names macos_window_background_blur so it cannot silently return. background_opacity's documented default was wrong in the same table (1.0 against the schema's 0.95) and is corrected here, because the backdrop caveat depends on it.
apply_acrylic_blur passed 4 to DWMWA_SYSTEMBACKDROP_TYPE. 4 is DWMSBT_TABBEDWINDOW, i.e. Mica Alt; DWMSBT_TRANSIENTWINDOW (Acrylic) is 3. The name, the doc comment, the crate CLAUDE.md and CHANGELOG.md:2898 all said Acrylic, and all named the constant DWMWCP_ACRYLIC, which belongs to the corner-preference enum. The value mapping is a plain const fn compiled everywhere, so a wrong constant fails on a Linux runner rather than only on Windows CI. The failing HRESULT that older Windows returns is now logged instead of discarded.
Two gaps close here. Requesting a backdrop now makes the window transparent on its own: previously only background_opacity < 1.0 did, so backdrop = "acrylic" on an opaque-configured window produced a surface the material could never show through. And spawn_os_window applied no backdrop at all, so a second OS window never matched the first. When a backdrop is configured against an opaque terminal, the mismatch is logged once at startup. Nothing is overridden: the configured opacity wins and the user is told why they see no material.
window-vibrancy is adopted for macOS only. Its Windows Acrylic path falls back on Windows 10 to the undocumented SetWindowCompositionAttribute, whose resize cost its own README documents, and it wants windows-sys 0.60 against this workspace's 0.59; Nexterm keeps its own DWM call there. Licensed Apache-2.0 OR MIT, matching this workspace. The material constant is an unmeasured initial recipe. Nobody on this project can run macOS, so this arm is written blind and compiles on CI without ever being looked at.
Follows the decorations cycler exactly: a five-value loop, a TOML key distinct from the localised label, and a write-back through toml_edit that preserves the rest of the file. The row itself lands in the next commit.
A Cycle row described once in settings_window.rs; the renderer, the hit-test and the AccessKit tree pick it up from the descriptor, and the sidebar search picks it up from window_row_labels. Restart-scoped, like the decorations row beside it. Mica and Acrylic stay untranslated in all eight locales: they are Microsoft material names, not descriptions. Also, folded into this final P2c-2 commit: - Wire row 16 into window_field_increase/window_field_decrease (window_extra.rs), which the brief's file list omitted; without it, prev_window_backdrop stayed unreachable and clippy's dead-code lint caught it after the Task 7 allow(dead_code) attributes were removed. - Remove the three temporary #[allow(dead_code)] attributes (and their explanatory comment) that Task 7 added to next_window_backdrop, prev_window_backdrop and window_backdrop_label. - Fix docs/ARCHITECTURE.md's stale window.background_opacity default (1.0 -> 0.95, matching the schema). - Name window-vibrancy itself in the P2c spec's "12 new lock entries" parenthetical, which enumerated only 11. - Correct the plan's P2c line: it claimed "shipped via P2c-1/P2c-2" while neither has been merged (no PR opened on this branch); reworded to describe what's actually true.
The final whole-branch review found that adding window-vibrancy (macOS only) re-resolved several existing crates' windows-sys dependency edge from 0.59.0/0.48.0 to 0.61.2 (dirs-sys, errno, is-terminal, nu-ansi-term, rustix, tempfile, and others), and iana-time-zone's windows-core edge to 0.62.2. Both versions were already present elsewhere in the lock file, so no new package version entered the tree and nothing on Linux behaves differently. An SDD ledger entry had disputed this same observation during Task 4 and called it false. That disproof used `grep -c '^-version'`, which matches only a package's own top-level `version =` field, not a version string quoted inside another package's `dependencies` array — the two checks answer different questions, and the disproof could not have detected this class of change either way. Corrected in both places it was recorded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Coverage reportGenerated by |
mizu-jun
added a commit
that referenced
this pull request
Aug 28, 2026
The entry was deliberately left unchecked while the branch was unmerged — every sibling line in this document cites an actual merged PR number, so claiming "shipped" before one existed would have been false. #75 is merged, so it is now true. Also records the two latent defects P2c closed alongside its own feature (a requested backdrop never made the window transparent; secondary OS windows never received one), since neither is obvious from the phase's title. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the last unchecked item of UI/UX v3 phase P2.
window.backdropselects theOS-native window backdrop material, resolved per-OS and applied through Windows'
DwmSetWindowAttributeor macOS'sNSVisualEffectView.auto(default)micamica-altacrylicnonemacOS collapses all three materials onto one vibrancy: AppKit has a single material
family, and mapping
micato "no backdrop" there would silently ignore what the userasked for. Linux has no cross-compositor equivalent —
in_app_blur_enabled(P2b) isthe in-app substitute.
Three defects this also fixes
The Windows material was mislabelled everywhere.
apply_acrylic_blurpassed4to
DWMWA_SYSTEMBACKDROP_TYPE.4isDWMSBT_TABBEDWINDOW— Mica Alt;DWMSBT_TRANSIENTWINDOW(Acrylic) is3. The function name, its doc comment, thecrate
CLAUDE.mdandCHANGELOG.md:2898all said Acrylic and all named the constantDWMWCP_ACRYLIC, which belongs to the corner-preference enum.autodeliberatelystill resolves to Mica Alt, so no existing Windows window changes appearance — only
the naming was wrong.
A requested backdrop did not make the window transparent. Transparency keyed off
background_opacity < 1.0alone, sobackdrop = "acrylic"on an opaque-configuredwindow produced a surface the material could never show through.
Secondary OS windows got no backdrop at all.
spawn_os_windownever applied one,so a second window never matched the first.
Also removed:
window.macos_window_background_blur, which had no reader anywhere inthe workspace while
CONFIGURATION.mdandARCHITECTURE.mdboth described it asworking. Unknown keys are ignored by the parser, so config files still carrying it
keep loading — a test pins that.
Design note: the resolver takes the OS as a parameter
WindowBackdrop::resolve(self, BackdropTarget)does not readcfg!, anddwm_backdrop_valueis a plainconst fncompiled on every platform. Both aredeliberate: it means the Windows and macOS routing tables and every DWM constant are
asserted on the Linux runners that are the only machines running these tests. A wrong
constant fails on Linux rather than surviving to a Windows release.
New dependency
window-vibrancy0.8 (Apache-2.0 OR MIT, matching this workspace), macOS only.Windows keeps Nexterm's own
DwmSetWindowAttributecall: the crate's Windows Acrylicpath falls back on Windows 10 to the undocumented
SetWindowCompositionAttribute,whose resize cost its own README documents — a poor trade for a terminal — and it
wants
windows-sys0.60 against this workspace's 0.59.Because
Cargo.lockrecords the union across all targets,windows-sys 0.60.2andthe
objc2subtree do appear there and inpkg/flatpak/cargo-sources.json(12packages, 156 lines) without ever being built on Linux. Adding the dependency also
re-resolved several existing crates'
windows-sysedge onto0.61.2, a versionalready present in the lock; no new package version entered the tree.
Test plan
Machine-verified, all on Linux:
autokeeps its shipped behaviour on Windows (Mica Alt) and macOS (none)DWM_SYSTEMBACKDROP_TYPEenumautodefault, unknown value rejected, and anold config carrying
macos_window_background_blurstill loadingTOML file through the real write-back path
cargo test --workspace(1,747 passing),cargo clippy -- -D warnings,cargo fmt --checkNot verified by anything — please read this before merging. No test executes
DwmSetWindowAttributeorapply_vibrancy; the Windows and macOS CI jobs prove thecode compiles and nothing more. Specifically unverified:
all. The terminal paints
background_opacityover the surface, so at the 0.95default only 5% of any material shows through — which may be why the Mica Alt
that has shipped since v1.1 has never been remarked on
NSVisualEffectMaterial::UnderWindowBackground, an unmeasured initial recipe inthe same class as feat(client): soft drop shadows scaled by the Fluent elevation table (UI/UX v3 P2a) #63's
shadow_paramsand feat(client): in-app acrylic material for overlay panels (UI/UX v3 P2b) #74'sACRYLIC_TINT_OPACITY. ThemacOS arm was written without a macOS machine; its signatures were verified
against vendored source, not a compile
These join the on-device verification backlog in
docs/plans/ui-ux-modernization-v3.mdrather than resolving any of it.Generated with Claude Code
via Happy