feat(windows): complete WinUI 3 backend - #8733
Conversation
Lands #8722 with its four gate blockers resolved. Replaces the windows-winui scaffold with real WinUI 3 / Fluent rendering through a vendored Windows Reactor snapshot (microsoft/windows-rs 65066a7109c214f317ed66261cfb7518160b8aaf), upstream licenses preserved. The vendored tree moved from `crates/perry-ui-windows-winui/vendor/` to `third_party/windows-winui/`, and this was forced rather than chosen. Cargo's `is_excluded` is `!explicit_member && excluded`, and `explicit_member` matches any `members` entry that is a path PREFIX of the candidate -- so while the snapshot sat under a member directory, `exclude` lost and all 13 crates were real workspace members. Verified empirically: adding `exclude = ["crates/perry-ui-windows-winui/vendor"]` in place left cargo reporting 92 packages with all 13 still members; after the move it reports 79, matching the existing architecture baseline exactly, so no baseline refresh was needed. As members they entered the build graph, so `cargo test --workspace` compiled them and Perry's `[workspace.lints]` would have applied to upstream code. GC roots, the part that mattered: `Node` DOES hold JS values -- every widget callback is stored as a raw closure pointer via `js_nanbox_get_pointer` -- so it gets scanner coverage following #8713's pattern, not a verdict. `AppState` does not: `String`, two `f64` dimensions, an `i64` that indexes NODES rather than an address, two `Option<(f64,f64)>` and a `PresenterKind`, so it takes a `not_a_gc_pointer` verdict. Three further roots the census had not flagged are scanned too (`ON_ACTIVATE`, `ON_TERMINATE`, `PENDING_TIMERS`), and the scanner is armed on the Fluent path, where winui shadows `app_create` and would otherwise have left `perry-ui-windows`' own tables unscanned. The four oversized files are generated upstream bindings and are allowlisted as an immutable snapshot. `build_and_run.rs` was NOT allowlisted -- the block this PR added moved to `link/winui_assets.rs`, 2110 -> 1970. No version bump; the only root Cargo.toml change is the `exclude` entry.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (296)
📝 WalkthroughWalkthroughThis PR adds an opt-in ChangesPerry WinUI Backend Integration
Vendored Windows Reactor Toolkit
Estimated code review effort: 5 (Critical) | ~240 minutes Sequence Diagram(s)sequenceDiagram
participant Compiler as Perry compile/link
participant WinUIAssets as winui_assets.rs
participant AppBackend as perry-ui-windows-winui::app
participant Reactor as windows_reactor::App
participant Win32 as perry-ui-windows (fallback)
Compiler->>WinUIAssets: deploy_winui_runtime_assets()
WinUIAssets-->>Compiler: Bootstrap DLL, resources.pri copied
AppBackend->>AppBackend: app_run()
alt Fluent backend active and WinUI runtime available
AppBackend->>Reactor: run(root_factory)
Reactor-->>AppBackend: WinUI window rendered
else WinUI unavailable
AppBackend->>Win32: app_run()
Win32-->>AppBackend: Win32 window rendered
end
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Lands #8722 with its four gate blockers resolved.
The vendored tree moved — and this was forced, not chosen
I verified this rather than accepting it. Cargo's
is_excludedis!explicit_member && excluded, andexplicit_membermatches anymembersentry that is a path prefix of the candidate. While the snapshot sat undercrates/perry-ui-windows-winui/vendor/, the member entry for its parent won and all 13 crates were genuine workspace members.Empirically, on the PR head:
windows-*as membersexclude = ["crates/perry-ui-windows-winui/vendor"]added in placethird_party/windows-winui/+ excluded79 matches the existing architecture baseline exactly, so no baseline refresh was needed. This mattered substantively, not cosmetically: as members they entered the build graph, so
cargo test --workspacecompiled 73k lines of upstream code and Perry's[workspace.lints]policy would have applied to it.GC roots — the part that actually mattered
Nodeholds JS values. Every widget callback is stored as a raw closure pointer viajs_nanbox_get_pointer(Common::on_click, pluscallbackon Button/TextField/SecureField/Toggle/Slider). So it gets scanner coverage following #8713's pattern — not anot_a_gc_pointerverdict, which would have been false.AppStatedoes not. Its fields areString, twof64dimensions, ani64that indexesNODESrather than an address, twoOption<(f64,f64)>, and aPresenterKind. Rule S fired on the scalars; the verdict is accurate.Three further roots the census had not flagged are scanned as well —
ON_ACTIVATE,ON_TERMINATE,PENDING_TIMERS, all raw closure pointers. And the scanner is armed on the Fluent path, where winui shadowsapp_create, which would otherwise have leftperry-ui-windows' own live tables unscanned.The other two
Four oversized files are generated upstream bindings (up to 26k lines) and are allowlisted as an immutable snapshot that must stay byte-identical for re-diffing.
build_and_run.rswas deliberately not allowlisted — the block this PR added moved intolink/winui_assets.rs, byte-verbatim apart from twopub(super)bumps. 2110 → 1970.Validation
lint-job checkers passcargo check -p perryand-p perry --tests: 0 errors, 0 warningsCargo.tomlchange is theexcludeentry with its rationaleKnown residual — flagged, not fixed
render_handleoperates on a clone of the node and copies the unboxed callback pointer intomoveclosures owned by the Reactor element tree;start_runtime_pumpandapp_rundo the same for timers andon_exit. Those copies live inside boxed Rust closures no scanner can reach or rewrite, so an evacuating collection leaves them stale. Scanning the tables cannot fix this — the real fix is re-reading a scanned slot at invoke time, the indirectionperry-ui-macosgets from its handle-keyed maps, which is a ~15-site refactor. This is a pre-existing property of the PR's design rather than something introduced here, and it is documented at both scanners. Worth a follow-up issue.Not verified
WinUI runtime behaviour was not tested — it cannot be built or run from macOS, and a real cross-compile fails on a C build script (
perry-audio-miniaudioneeds Windows headers). The scanner and type definitions were validated by compiling the real definitions against the realperry_ffi::GcRootVisitorin a scratch crate, which proves match exhaustiveness and signatures but says nothing about the backend working. Someone on Windows should confirm that. The three relocatedwinui_asset_teststype-check but were not executed.Summary by CodeRabbit
New Features
Bug Fixes
Documentation