Skip to content

fix: detach platform input when presentation source closes - #21782

Merged
MrJul merged 4 commits into
AvaloniaUI:mainfrom
NathanDrake2406:nathan/fix-popup-input-after-close
Jul 21, 2026
Merged

fix: detach platform input when presentation source closes#21782
MrJul merged 4 commits into
AvaloniaUI:mainfrom
NathanDrake2406:nathan/fix-popup-input-after-close

Conversation

@NathanDrake2406

Copy link
Copy Markdown
Contributor

What does the pull request do?

Detaches the platform input callback when a presentation source closes. This prevents late native input, including Win32 WM_CAPTURECHANGED, from reaching an already disposed popup or window.

What is the current behavior?

The Win32 handling added by #19685 forwards WM_CAPTURECHANGED through ITopLevelImpl.Input. When a menu item closes a native popup while that popup owns mouse capture, Win32 can destroy the popup and then send the capture-loss message.

PresentationSource.Dispose clears its PlatformImpl reference but leaves ITopLevelImpl.Input assigned to PresentationSource.HandleInput. The late message therefore enters the disposed presentation source, logs PlatformImpl is null, couldn't handle input, and can route later input work toward a detached visual tree.

What is the updated/expected behavior with this PR?

Closing a top level clears ITopLevelImpl.Input before layout and renderer teardown, so the native implementation cannot dispatch input after close handling starts.

Validation:

  • Added Closing_Should_Detach_Platform_Input_Handler, which fails before the fix because the closed top level retains the callback.
  • Ran the presentation source, context menu, menu item, and popup root tests: 66 passed.
  • Ran the full Avalonia.Controls.UnitTests executable: 3,643 passed, 1 existing test skipped, 0 failed.

How was the solution implemented (if it's not obvious)?

PresentationSource assigns and owns the platform input callback. Disposal now clears it alongside ScalingChanged before layout and renderer teardown.

The change does not alter pointer capture, popup close ordering, or public API. The regression test verifies the framework/platform ownership boundary using the mock top-level implementation. Native Win32 UI automation was not run because the development host is macOS.

Checklist

  • Added unit tests (if possible)?
  • Added XML documentation to any related classes? No public API was added or changed.
  • Consider submitting a PR to https://github.com/AvaloniaUI/avalonia-docs with user documentation. No documentation change is needed for an internal lifecycle fix.

Breaking changes

None.

Obsoletions / Deprecations

None.

Fixed issues

Fixes #19892

Closed top levels retain the presentation source as the platform input callback. A late platform input event can therefore target an already disposed visual tree.\n\nThe regression test requires top-level closure to clear ITopLevelImpl.Input.
Win32 can deliver WM_CAPTURECHANGED while destroying a popup that owns mouse capture. The platform then calls the input handler retained by the disposed presentation source, which logs a warning and can route input into a detached visual tree.\n\nClear the platform input callback at the start of presentation source disposal, alongside the existing scaling event unsubscription.
@NathanDrake2406
NathanDrake2406 marked this pull request as ready for review July 15, 2026 08:03
@MrJul MrJul added bug backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Jul 15, 2026
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0067482-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul MrJul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM!

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0067569-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul
MrJul added this pull request to the merge queue Jul 21, 2026
Merged via the queue into AvaloniaUI:main with commit c8da7f8 Jul 21, 2026
9 checks passed
MrJul added a commit that referenced this pull request Jul 29, 2026
* test: cover platform input detachment on close

Closed top levels retain the presentation source as the platform input callback. A late platform input event can therefore target an already disposed visual tree.\n\nThe regression test requires top-level closure to clear ITopLevelImpl.Input.

* fix: detach platform input when presentation source closes

Win32 can deliver WM_CAPTURECHANGED while destroying a popup that owns mouse capture. The platform then calls the input handler retained by the disposed presentation source, which logs a warning and can route input into a detached visual tree.\n\nClear the platform input callback at the start of presentation source disposal, alongside the existing scaling event unsubscription.

---------

Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
@MrJul MrJul added backported-12.1.x and removed backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clicking ToolTip.Tip/ContextMenu popups shows warning: PlatformImpl is null, couldn't handle input.

3 participants