feat: ALC-scoped AdaptiveTrigger window-size override - #23902
Draft
DerekRaven wants to merge 7 commits into
Draft
Conversation
A host that loads a guest app into a collectible AssemblyLoadContext can now scope the simulated window size to that context's triggers only, via a new SetWindowSizeOverride(Size?, AssemblyLoadContext) overload, without affecting the host UI. Triggers resolve their owner ALC by walking to the nearest ancestor typed in a non-default ALC (lazily, cached per attach). Storage is weakly keyed and self-clears on unload, so a scoped override never roots the collectible context. Precedence: scoped > global > window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Guest elements are staged by loading a second copy of the view library into a collectible AssemblyLoadContext, mirroring a hosted guest app's page types. Covers guest-only application, scoped-over-global precedence, revert-on-clear chains, pre-attach overrides, argument validation, foreign-scope isolation, no-rooting of the target ALC, and scope self-clearing on unload. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Runtime coverage in the real AlcContentHost shape, where guest triggers live inside the host's visual tree and share its XamlRoot: a scoped override activates only the guest's adaptive state (probe added to the AlcApp main page), host-owned triggers stay untouched, and the scoped value wins over — and falls back to — the global override. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-resolve the owner ALC on every attach so a subtree built before being parented under a guest-typed ancestor doesn't keep a stale no-ALC cache. Ignore new overrides for an ALC whose unload has already been initiated (its Unloading event can never fire to self-clean), make the scoped holder immutable for the lock-free read path, share one WeakReference per ALC across triggers, and contain + re-evaluate from the Unloading handler, which can run on the finalizer thread. Covered by new unit tests: pre-parenting resolution, two concurrent scoped ALCs, and unloading-ALC override rejection. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contain the trigger re-evaluation raised from ALC-unload paths (it can run enqueued on the dispatcher or on the finalizer thread, where an escaping subscriber exception had no handler), and make the application ALC-cleanup backstop log its removals and re-evaluate live triggers like the Unloading path already did. Consolidate the owner-cache reset into ResetOwnerAlcCache, document the writers-only lock and the benign fast-path latch race, and link the scoped unit tests to the issue with GitHubWorkItem. New When_NestedScopedAlcs_InnermostWins test pins the documented innermost-context resolution for nested guest ALCs. Validated: Given_AdaptiveTrigger unit tests 32/32, Given_AlcContentHost runtime tests 39/39 (Skia desktop). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-23902/wasm-skia-net9/index.html |
|
|
||
| for (var i = 0; i < 10 && weakAlc.IsAlive; i++) | ||
| { | ||
| GC.Collect(); |
Comment on lines
+235
to
+241
| catch (Exception ex) | ||
| { | ||
| if (typeof(AdaptiveTrigger).Log().IsEnabled(LogLevel.Warning)) | ||
| { | ||
| typeof(AdaptiveTrigger).Log().Warn($"Failure while handling the unload of ALC '{alc.Name}'", ex); | ||
| } | ||
| } |
Comment on lines
+254
to
+260
| catch (Exception ex) | ||
| { | ||
| if (typeof(AdaptiveTrigger).Log().IsEnabled(LogLevel.Warning)) | ||
| { | ||
| typeof(AdaptiveTrigger).Log().Warn("Failed to re-evaluate adaptive triggers after a scoped window-size override was dropped", ex); | ||
| } | ||
| } |
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.
GitHub Issue: closes #23721
PR Type:
✨ Feature
What changed? 🚀
AdaptiveTrigger.SetWindowSizeOverride(Size?)(added in #23445 for #23444) is a process-global static override: because a host and its hosted guest apps share the same Uno.UI instance from the defaultAssemblyLoadContext, simulating a form factor for a guest also re-evaluated everyAdaptiveTriggerin the host's own UI, collapsing/expanding the host chrome based on the guest's simulated size.This PR adds an ALC-scoped overload,
SetWindowSizeOverride(Size?, AssemblyLoadContext), so a host can apply a simulated size to the triggers of a guest app loaded in a (collectible) ALC without affecting its own UI:XamlRoot) bounds. The existing global overload's behavior is unchanged.ConditionalWeakTable, and trigger-side caching uses sharedWeakReferences. The scope self-clears via the ALC'sUnloadingevent (with anApplicationALC-cleanup backstop), re-evaluating any still-live guest triggers so they don't stay frozen at the simulated size. Overrides for an ALC whose unload has already been initiated are ignored.doc/articles/features/AdaptiveTrigger.mddocuments both overloads, the precedence chain, and the attribution limits (guest content composed solely of shared framework types — e.g. popup/flyout subtrees re-parented under the host's popup root — falls back to the global override).Validation: unit tests
Given_AdaptiveTrigger32/32 passed (guest-only application, scoped-over-global precedence, revert-on-clear chains, pre-attach and pre-parenting overrides, two concurrent scoped ALCs, nested-ALC innermost-wins, argument validation, foreign-scope isolation, no-rooting, self-clear on unload, unloading-ALC rejection); runtime testsGiven_AlcContentHost39/39 passed on Skia desktop (X11), including two new hosted-topology tests where guest triggers live inside the host's visual tree sharing itsXamlRoot. An eight-lens review panel ran on the branch; all actionable findings are addressed in the last commit. Non-Skia heads are compile-verified by CI only (the new code usesSystem.Runtime.LoaderandNativeDispatcher, both available on all heads).PR Checklist ✅
Screenshots Compare Test Runresults.🤖 Generated with Claude Code