Fix Tooltip child state loss when cursor enters/leaves window#1303
Merged
Fix Tooltip child state loss when cursor enters/leaves window#1303
Conversation
Remove the _handleMouseTrackerChange listener that caused setState to be called when a mouse device connects/disconnects. This setState caused the build method to conditionally add/remove a MouseRegion wrapper, which changed the widget tree depth and caused the child widget to lose its state. Now the MouseRegion is always included in the widget tree (matching the fix in flutter/flutter#119199), and _mouseIsConnected is read directly from RendererBinding as a getter instead of being cached as state. Co-authored-by: bdlukaa <45696119+bdlukaa@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix tooltip widget replacing child on cursor enter/leave
Fix Tooltip child state loss when cursor enters/leaves window
Mar 3, 2026
Owner
|
/gemini review |
Contributor
There was a problem hiding this comment.
Code Review
This pull request addresses a bug causing state loss in a Tooltip's child widget when the mouse enters or leaves the window. The changes remove the stateful tracking of mouse connection and instead make the MouseRegion a permanent part of the widget tree, which stabilizes the tree structure and preserves the child's state. This is achieved by removing the _mouseIsConnected state field and its update logic, replacing it with a getter, and refactoring the build method to always include the MouseRegion. A regression test is also added to verify that the child's initState is called only once during mouse connection changes.
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.
Tooltiprebuilds its child with a newStatewhenever the mouse cursor enters or leaves the window. Root cause:_handleMouseTrackerChangecallssetStateon_mouseIsConnected, which conditionally adds/removes aMouseRegionwrapper inbuild(), changing the widget tree depth and destroying child state.Same class of bug fixed in Flutter material: flutter/flutter#119199
Changes
_handleMouseTrackerChangelistener and its registration/teardown — eliminates thesetStatethat triggered tree restructuring_mouseIsConnectedstate field with a getter reading directly fromRendererBinding.instance.mouseTracker.mouseIsConnectedMouseRegionin the widget tree — tree structure stays stable regardless of mouse connection state, preserving child stateinitStateis called exactly once across mouse pointer add/remove cyclesWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://storage.googleapis.com//usr/bin/curl curl -v REDACTED bash _eng�� b-cache/_temp/dirPIYQRU/bin/shell_completion_generator.dart(http block)https://storage.googleapis.com/flutter_infra_release/flutter/109150893958777c8f2215f6cfd3e89e984e8dea/dart-sdk-linux-x64.zip/usr/bin/curl curl --retry 3 --continue-at - --location --output /tmp/flutter/bin/cache/dart-sdk-linux-x64.zip REDACTED(http block)/usr/bin/curl curl -sI REDACTED(http block)https://storage.googleapis.com/flutter_infra_release/flutter/109150893958777c8f2215f6cfd3e89e984e8dea/linux-x64/font-subset.zip/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart --packages=/tmp/flutter/packages/flutter_tools/.dart_tool/package_config.json /tmp/flutter/bin/cache/flutter_tools.snapshot test test/tooltip_test.dart --no-pub --local /home/REDACTED/.local/bin/git user.name(http block)https://storage.googleapis.com/flutter_infra_release/flutter/109150893958777c8f2215f6cfd3e89e984e8dea/sky_engine.zip/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart --packages=/tmp/flutter/packages/flutter_tools/.dart_tool/package_config.json /tmp/flutter/bin/cache/flutter_tools.snapshot test test/tooltip_test.dart --no-pub --global or_parser credential.usernbash(http block)https://storage.googleapis.com/flutter_infra_release/flutter/18818009497c581ede5d8a3b8b833b81d00cebb7/dart-sdk-linux-x64.zip/usr/bin/curl curl --retry 3 --continue-at - --location --output /tmp/flutter/bin/cache/dart-sdk-linux-x64.zip REDACTED(http block)https://storage.googleapis.com/flutter_infra_release/flutter/327ed814500baca0480a02f8555aa84a9afe32bf/dart-sdk-linux-x64.zip/usr/bin/curl curl --retry 3 --continue-at - --location --output /tmp/flutter/bin/cache/dart-sdk-linux-x64.zip REDACTED(http block)https://storage.googleapis.com/flutter_infra_release/flutter/fonts/3012db47f3130e62f7cc0beabff968a33cbec8d8/fonts.zip/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart --packages=/tmp/flutter/packages/flutter_tools/.dart_tool/package_config.json /tmp/flutter/bin/cache/flutter_tools.snapshot pub get(http block)/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart --packages=/tmp/flutter/packages/flutter_tools/.dart_tool/package_config.json /tmp/flutter/bin/cache/flutter_tools.snapshot test test/tooltip_test.dart(http block)/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart --packages=/tmp/flutter/packages/flutter_tools/.dart_tool/package_config.json /tmp/flutter/bin/cache/flutter_tools.snapshot test test/tooltip_test.dart --no-pub(http block)https://storage.googleapis.com/flutter_infra_release/gradle-wrapper/fd5c1f2c013565a3bea56ada6df9d2b8e96d56aa/gradle-wrapper.tgz/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart --packages=/tmp/flutter/packages/flutter_tools/.dart_tool/package_config.json /tmp/flutter/bin/cache/flutter_tools.snapshot test test/tooltip_test.dart --no-pub(http block)/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart --packages=/tmp/flutter/packages/flutter_tools/.dart_tool/package_config.json /tmp/flutter/bin/cache/flutter_tools.snapshot test test/tooltip_test.dart --no-pub credential.username /usr/local/bin/git(http block)https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json/tmp/flutter/bin/cache/dart-sdk/bin/dart /tmp/flutter/bin/cache/dart-sdk/bin/dart pub --suppress-analytics get --example --directory .(http block)https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.32.0-stable.tar.xz/usr/bin/curl curl -fsSL REDACTED -o /tmp/flutter.tar.xz(http block)storage.flutter-io.cn/usr/bin/curl curl -sI REDACTED(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.