Visitar URL original
fix: Release only ToolTips the service opened by ajpinedam · Pull Request #26096 · unoplatform/uno · GitHub
Skip to content

fix: Release only ToolTips the service opened - #26096

Merged
ajpinedam merged 3 commits into
unoplatform:masterfrom
ajpinedam:dev/anpi/tooltip-release-closed
Nov 5, 2026
Merged

ajpinedam merged 3 commits into
unoplatform:masterfrom
ajpinedam:dev/anpi/tooltip-release-closed

Conversation

@ajpinedam

@ajpinedam ajpinedam commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

GitHub Issue: related to #25099 and unoplatform/kahua-private#565 (follow-up to #25137)

PR Type:

🐞 Bugfix

What changed? 🚀

#25137 makes ToolTipService let go of a ToolTip whenever that ToolTip closes. WinUI does that only for a ToolTip the service opened itself: ToolTip::OnIsOpenChanged clears m_tpCurrentToolTip only when m_bIsOpenAsAutomaticToolTip is set. So on master, an app that opens and closes a ToolTip while its owner is hovered, before the show delay elapses, cancels the hover open, whereas on WinUI the ToolTip still opens.

Changes

  • Ported WinUI's s_bOpeningAutomaticToolTip / m_bIsOpenAsAutomaticToolTip. The service flags the open it drives from its show-delay timer, and ToolTip.OnOpenChanged calls ToolTipService.OnToolTipClosed only for a ToolTip opened that way.
  • The service's own close paths (CloseToolTipImpl and the show-duration timer) still release the ToolTip, so the leak fix(tooltip): Let go of a ToolTip in the service when it closes, however it closed #25137 fixed stays fixed. Its tests still pass.
  • If the app opens the ToolTip itself while it waits to open, the service's timer no longer takes it over. In WinUI, OpenAutomaticToolTip's put_IsOpen(TRUE) changes nothing, so the service never holds that ToolTip. Before this change, Uno's show-duration timer closed the app's ToolTip.

Testing

  • When_Pending_ToolTip_Opened_And_Closed_By_App_Then_Still_Opens_Automatically fails on master and passes with this change. It opens and closes the ToolTip back to back, so it does not race the show delay. On Uno, it also checks right away that the service still holds the pending ToolTip.
  • When_Automatic_ToolTip_Reopened_By_App_Then_ShowDuration_Does_Not_Close_It checks that the show-duration timer does not close a ToolTip the app reopened after closing the automatic one. It also fails if the service's open is not flagged.
  • When_Pending_ToolTip_Opened_By_App_Then_ShowDuration_Does_Not_Close_It covers the app opening the ToolTip during the show delay.
  • Given_ToolTip passes 26/26 on Skia desktop.

The servicing/6.8 fix for kahua-private#565 (the leak and this parity together) is #26098.

PR Checklist ✅

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Sample App stage site is ready! Visit it here:

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 243945 found UI Test snapshots differences: skia-linux-screenshots: 2458, skia-windows-screenshots: 2458

Details
  • skia-linux-screenshots: 2458 changed over 2494

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Accessibility_ScreenReader.png
    • AppBarButtonWithIconTest.png
    • ApplicationViewMode.png-dark
    • ApplicationViewSpanningRectsPage.png-dark
    • AppWindowFeatures.png-dark
    • AppWindowPresenters.png-dark
    • ArcSegment.png-dark
    • Attributed_text_Simple.png-dark
    • Attributed_text_Supserscript.png
    • AuthenticationBroker_Cancel.png-dark
    • AutomationProperties_AutomationId.png
    • AutomationProperties_Landmark.png-dark
    • AutoSizedTopLeft.png-dark
    • AutoSizedTopLeft.png
    • BackGesture.png-dark
    • BackGesture.png
    • BasicEnability.png-dark
    • BasicEnability.png
    • BenchmarkDotNet.png-dark
    • BenchmarkDotNet.png
  • skia-windows-screenshots: 2458 changed over 2494

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • AnimatedIconPage.png-dark
    • AnimatedVisualsTestbedPage.png-dark
    • AppBarButtonWithIconTest.png
    • ApplicationViewMode.png-dark
    • Application_DispatcherShutdownMode.png-dark
    • AppWindowPositionAndSize.png
    • ArcSegment.png-dark
    • AuthenticationBroker_Cancel.png
    • AutoBorderStretchwithtopmargin.png-dark
    • AutoBorderStretchwithtopmargin.png
    • AutomationProperties_Relations.png
    • AutomationProperties_StructureAndProps.png-dark
    • BackGesture.png-dark
    • BackGesture.png
    • BasicEnability.png-dark
    • BasicEnability.png
    • BenchmarkDotNet.png-dark
    • BenchmarkDotNet.png
    • BitmapIcon_Monochromatic.png-dark
    • BitmapIcon_Monochromatic.png

@ajpinedam
ajpinedam force-pushed the dev/anpi/tooltip-release-closed branch from a0e86bc to 63a3075 Compare November 5, 2026 18:21
@ajpinedam ajpinedam changed the title fix: Release the current ToolTip when it closes fix: Release only ToolTips the service opened Nov 5, 2026

@Xiaoy312 Xiaoy312 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good. This is a faithful port of WinUI's automatic-ToolTip tracking:

  • m_bIsOpenAsAutomaticToolTip is captured from s_bOpeningAutomaticToolTip when the ToolTip opens (ToolTip::OnIsOpenChanged, ToolTip_Partial.cpp:277).
  • The service lets go of the ToolTip only when that flag is set (:392).
  • The service sets the static around its own put_IsOpen(TRUE) (OpenAutomaticToolTip).

CloseToolTipImpl and the show-duration timer still clear m_CurrentToolTip before closing, so the #25137 leak stays fixed. Nothing below blocks merging.

1. When_Pending_ToolTip_Opened_And_Closed_By_App_Then_Still_Opens_Automatically can flake.
The mouse move, the app's open/close and three WaitForIdles all have to finish inside the show delay. That is 1000 ms on Uno, and 800 ms (600 ms on reshow) on native WinUI, where this test also runs.

If the open timer fires while the app holds the ToolTip open, IsOpen = true doesn't change anything, so the open is never flagged. The app's close then releases nothing, nothing reopens the ToolTip, and the test fails with "did not open".

Changing FeatureConfiguration.ToolTip.ShowDelay in the test won't help, because EnsureOpenTimer reads the interval only once, when the static timer is created.

The behaviour under test runs synchronously in the property-changed callback, so I'd suggest:

  • set toolTip.IsOpen = true; toolTip.IsOpen = false; back to back, with no waits in between;
  • under HAS_UNO, assert ToolTipService.CurrentToolTipForTesting is still the ToolTip right after the close, which checks the regression without depending on the timer.

2. The second test's comment claims more than the test checks.
"A reopen is the app's to close" holds only for the show-duration timer. CloseToolTipImpl (ToolTipService.cs:141) still sets toolTip.IsOpen = false no matter who opened it, so these still close a ToolTip the app reopened:

  • pointer exit
  • KeyDown
  • a pointer press on a ButtonBase
  • LostFocus
  • the owner becoming invisible

WinUI's CancelAutomaticToolTip / CloseAutomaticToolTip only close m_tpCurrentToolTip. That behaviour predates this PR, so I'd scope the comment to the timer and track parity of those close paths separately.

3. Follow-up: one pending case is still never flagged.
If the app opens the ToolTip during the show delay and leaves it open, the timer's open is a no-op and the ToolTip is never flagged. m_CurrentToolTip still points at it, so the close timer closes the app's ToolTip after ShowDuration.

In WinUI, m_tpCurrentToolTip is only set on the automatic path, so the service never takes over that ToolTip. This also predates the PR.

4. Nit: RemoveAutomaticStatusFromOpenToolTip, which Slider calls, is still a [NotImplemented] stub. Now that the flag exists, porting it is short: stop the close timer, clear the flag, release m_CurrentToolTip.

5. Nits:

  • The new tests could carry [GitHubWorkItem], like the #25137 tests next to them.
  • The commit subject could use a tooltip scope: fix(tooltip): ....

CI: the WinAppSDK Sync Generator Check failure is an NU1900 network error during restore (the vulnerability-data request failed), so a rerun should clear it.

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Sample App stage site is ready! Visit it here:

@ajpinedam

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Here is what changed, point by point:

  1. Flaky pending test (293a11e2f7): the test now sets IsOpen = true; IsOpen = false; back to back, with no waits. On Uno it also checks ToolTipService.CurrentToolTipForTesting right after the close. That check fails on master straight away, without waiting for the timer.
  2. Comment (293a11e2f7): it now covers only the show-duration timer. I agree the close paths that still close a ToolTip the app reopened (pointer exit, KeyDown, a ButtonBase press, LostFocus, the owner hidden) are older than this PR and need their own change.
  3. App opens the ToolTip during the show delay (d05dac1043): fixed in this PR. When the open timer fires and finds the ToolTip already open, the service lets go of it and doesn't start the close timer, so it never takes over a ToolTip it didn't open. That matches WinUI's OpenAutomaticToolTip, where put_IsOpen(TRUE) changes nothing. The new test When_Pending_ToolTip_Opened_By_App_Then_ShowDuration_Does_Not_Close_It fails without the fix.
  4. RemoveAutomaticStatusFromOpenToolTip: not done here. Porting it changes how Slider's thumb ToolTip behaves during a drag, so I'd rather do it in a follow-up with a Slider test.
  5. Nits: the new tests now carry [GitHubWorkItem] for [Skia] Shared dependency objects (style setter values, static brushes, input scopes, current tooltip) retain elements and DataContext of pages that are gone #25099. The two new commits use the tooltip scope. I left the first commit's subject unchanged so the branch didn't need another force-push.

Given_ToolTip passes 26/26 on Skia desktop. With master's ToolTip sources, the pending test fails on the new check and the new test fails. With only the new guard removed, only the new test fails.

@ajpinedam
ajpinedam enabled auto-merge November 5, 2026 20:03

@Xiaoy312 Xiaoy312 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, the follow-ups look good.

  • Pending test (293a11e2f7): this removes the race. CurrentToolTipForTesting is checked right after the back-to-back open/close, so the test no longer depends on the show-delay timer.
  • Guard in OnOpenTimerTick (d05dac1043): this is correct. If the ToolTip is already open when the timer fires, the service now lets go of it instead of taking it over. That matches WinUI's OpenAutomaticToolTip, where setting IsOpen = true on an open ToolTip changes nothing and leaves m_tpCurrentToolTip unset. Skipping the close-timer setup is safe, since every other use of m_CloseTimer is null-checked.
  • Deferred items: I agree with leaving RemoveAutomaticStatusFromOpenToolTip (it needs a Slider test) and the close paths that close an app-owned ToolTip to their own change.

One correction to my earlier review: the three new tests don't run on native WinUI (they're NotExecuted in the WinUI Runtime Tests run), so my WinUI timing concern doesn't apply.

CI on build 244142:

  • WinAppSDK Runtime Tests: Given_ToolTip.When_Closed_Then_DataContext_Kept fails with content.Text "" instead of "VM1". This PR can't cause that: the WinAppSDK head doesn't compile Uno.UI, and the new tests are skipped there. The test came in with #25137 and passed on master's WinUI run (build 243954), so it looks like a new flake. Please rerun the job. Given_ScrollViewer_Zoom failing in the same job is unrelated.
  • Android Skia shard 1: the Given_BitmapIcon and Given_InputPane failures are unrelated to ToolTip.

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 244142 found UI Test snapshots differences: skia-linux-screenshots: 2458, skia-windows-screenshots: 2458

Details
  • skia-linux-screenshots: 2458 changed over 2494

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • AnimatedBackVisualSourceSamplePage.png-dark
    • Accessibility_ScreenReader.png
    • Accessibility_ScreenReader.png-dark
    • AppBarButtonWithIconTest.png-dark
    • AppBarButtonWithIconTest.png
    • AnimatedIconPage.png
    • AppBarToggleButtonTest.png
    • AppBar_KeyBoard.png
    • AppBarToggleButtonTest.png-dark
    • Application_DispatcherShutdownMode.png-dark
    • ApplicationViewSizing.png
    • ApplicationViewSizing.png-dark
    • AppWindowPositionAndSize.png
    • AppWindowPositionAndSize.png-dark
    • AppWindowFeatures.png
    • Arrange_Performance01.png
    • AppXamlDefinedResources.png-dark
    • AppXamlDefinedResources.png
    • AuthenticationBroker_Cancel.png-dark
    • Attributed_text_FontSize_Changing.png-dark
  • skia-windows-screenshots: 2458 changed over 2494

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Accessibility_ScreenReader.png
    • AndroidWindowInsets.png
    • AnimatedIconPage.png
    • AnimatedVisualsTestbedPage.png
    • ApplicationViewMode.png-dark
    • AppWindowClosing.png-dark
    • AppWindowTitleBar Properties.png-dark
    • Attributed_text_FontSize_Changing.png-dark
    • AuthenticationBroker_Demo.png-dark
    • AuthenticationBroker_Demo.png
    • AutomationProperties_Landmark.png
    • AutomationProperties_Name.png-dark
    • AutoSuggestBox_BitmapIcon.png-dark
    • AutoSuggestBox_BitmapIcon.png
    • BasicAutoSuggestBox.png-dark
    • BasicAutoSuggestBox.png
    • BasicThemeResources.png-dark
    • BasicThemeResources.png
    • BitmapIcon_Generic.png-dark
    • BitmapIcon_Generic.png

ajpinedam added a commit that referenced this pull request Nov 5, 2026
…sed-6.8

fix: Release the current ToolTip when it closes (backport #25137, #26096)
@ajpinedam
ajpinedam merged commit ff60576 into unoplatform:master Nov 5, 2026
47 checks passed
@ajpinedam
ajpinedam deleted the dev/anpi/tooltip-release-closed branch November 5, 2026 23:55
agneszitte added a commit that referenced this pull request Nov 10, 2026
…6.7/pr-26098

fix: Release the current ToolTip when it closes (backport #25137, #26096) (backport #26098)
mikernet added a commit to Singulink/uno that referenced this pull request Nov 14, 2026
Takes Uno's servicing/6.8 from 6951c2c up to 5254ace (42 pull
requests). Conflicts, by area:

IME and TextBox (unoplatform#25984, backport of unoplatform#25804; unoplatform#25952, backport of unoplatform#25619;
unoplatform#25976, backport of unoplatform#25818)
- Takes upstream's composition design (unoplatform#25804): the browser's input is
  the source of truth for the text, compositions included. This drops
  the composition parts of the unoplatform#24502 port (90746b8): its
  TypeScript composition handling, the StartIndex/TextChangePending
  event arguments, the IsReadOnly forwarding to the hidden input, and
  its Given_TextBox.BrowserSoftKeyboard tests.
- Keeps the non-IME browser fixes on top of it, in the form their
  master pull requests have on unoplatform#25804: Enter raised once per press and
  tracked by key code (unoplatform#25174, with Given_TextBox.BrowserEnterKey from
  master in place of the Enter tests that lived in the dropped file),
  the iOS refocus on tap (unoplatform#25185), pastes without text and isIOS from
  BrowserInputHelper.
- Moves the unoplatform#26005 MaxLength fixes onto unoplatform#25804's native input path, as
  master has them: a refused browser edit keeps the TextBox's selection,
  TextBoxView.UpdateTextFromNative reports whether the edit went in, and
  the IME keeps its range on the applied text (master be85699, which
  d226897 had ported onto the unoplatform#24502 IME). Adds that commit's browser
  and platform-applied IME tests.
- TextBox.pointers.skia.cs: upstream's file (unoplatform#25619 iOS touch editing,
  unoplatform#25818, unoplatform#25804), with the unoplatform#25126 port (the hold acts when it starts,
  a touch right-tap keeps the caret) in the form master's unoplatform#25126 branch
  has it on unoplatform#25619, including focusing before the iOS hold timer acts
  and its iOS not-focusable test.

Pointers (unoplatform#25976, backport of unoplatform#25818)
- Tapped and RightTapped are raised once the PointerReleased bubbled
  (unoplatform#25818), with the unoplatform#25732 port's window coordinates (2-argument
  routed event args, RawPosition for ContextRequested), as master's
  unoplatform#25732 branch has them.
- The release wrapper of unoplatform#25818 keeps the unoplatform#25126 port's
  StopContextMenuTimer at the start of the release.

DependencyObject (unoplatform#26142, backport of unoplatform#26123)
- Takes upstream, then the code of unoplatform#25839 (97a2f17), which replaces
  this branch's unoplatform#25102 ports (800247f, be41da6, fd40bf9,
  7546379). DependencyObjectStore.Binder.cs, .alc.cs,
  Application.Alc.cs, ResourceDictionary.alc.cs and their tests now
  match unoplatform#25839; this drops 800247f's own
  SingleParentNonFE_Parent_Removes_Value_Then_Next_Parent_Starts_Clean
  test, which unoplatform#25839 doesn't have.

Imaging (unoplatform#25597, unoplatform#25915, unoplatform#25911, unoplatform#25897)
- Keeps this branch's side: it has the later forms of these fixes
  (unoplatform#25124, unoplatform#25559, unoplatform#25633 and unoplatform#26370 ports), where upstream has the
  6.8-only unoplatform#25597 design and earlier snapshots. Upstream's shared
  download, IgnoreImageCache and failed-load fixes are covered by
  SharedImageDecode. Adds upstream's When_Source_Outlives_Brushes test.

ToolTip (unoplatform#26098, backport of unoplatform#25137 and unoplatform#26096)
- Keeps this branch's unoplatform#25137 port and adds unoplatform#26096 in master's form: the
  service releases only a ToolTip it opened, and leaves one the app
  opened during the show delay to the app. Keeps both sides' tests.

Flyout (unoplatform#26062, backport of unoplatform#26060)
- This branch had the same commits already; keeps the "Keep
  non-resizable flyouts in window" port and its tests.

Also removes a helper pair in Given_AccessibleTextBox that both sides
added.
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.

4 participants