Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash on hiding grandparent Control on mouse exit #85313

Merged
merged 1 commit into from
Dec 8, 2023

Conversation

kitbdev
Copy link
Contributor

@kitbdev kitbdev commented Nov 24, 2023

fixes crash when changing top level or mouse filter to stop during a mouse notification (#85277 (comment)).

This works by deferring sending new notifications if we are already sending notifications.
Mouse enter and exit notifications are now handled when changing visibility, top level, and mouse filter during the notification callbacks. Previously it would sending duplicate or out of order notifications.

However, with this there is a way to make an infinite loop:
On mouse_entered set the child to mouse filter stop, and on mouse_exited set the child to mouse filter pass. Then mouse over the child. The parent will continuously receive mouse enter and exit notifications.
Previously, it would just send mouse notifications in the wrong order and then stop. This also won't happen with hide() and show() since show() doesn't update the mouse over immediately.

@kitbdev kitbdev requested a review from a team as a code owner November 24, 2023 15:44
@YuriSizov YuriSizov added this to the 4.2 milestone Nov 24, 2023
@YuriSizov YuriSizov requested review from Sauermann and a team November 24, 2023 15:45
@akien-mga akien-mga modified the milestones: 4.2, 4.3 Nov 27, 2023
@akien-mga akien-mga added the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Nov 27, 2023
Copy link
Contributor

@Sauermann Sauermann left a comment

Choose a reason for hiding this comment

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

I have tested and can confirm, that the PR fixes the MRP in #85277 (comment) and #85277 (comment).

@@ -2507,6 +2513,8 @@ void Viewport::_gui_update_mouse_over() {
return;
}

gui.sending_mouse_enter_exit_notifications = true;
Copy link
Contributor

@Sauermann Sauermann Dec 2, 2023

Choose a reason for hiding this comment

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

In the implementation you keep track in every Viewport separately, if sending_mouse_enter_exit_notifications is active or not.
Have you considered the idea to keep track of the state in a global manner (for example only in the root-Viewport (even when the entry-point is not the root-Viewport))? I'm not entirely sure, if there can be edge cases, where these notifications in different Viewports could interfere with each other.

However, for now it looks like a reasonable approach.

scene/main/viewport.cpp Outdated Show resolved Hide resolved
scene/main/viewport.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@Sauermann Sauermann left a comment

Choose a reason for hiding this comment

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

I have tested successfully the MRPs. Code is looking good to me and I don't see any obvious problems.

scene/main/viewport.cpp Outdated Show resolved Hide resolved
scene/main/viewport.cpp Outdated Show resolved Hide resolved
Comment on lines +3271 to +3275
if (gui.sending_mouse_enter_exit_notifications) {
// If notifications are already being sent, defer call.
callable_mp(this, &Viewport::_drop_mouse_over).call_deferred(p_until_control);
return;
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not familiar with this code, but slightly worried at the possibility of a deferred infinite recursion here. Are we absolutely sure that this won't end up deferring itself over and over again without ever reaching a condition that would make gui.sending_mouse_enter_exit_notifications false?

Copy link
Contributor Author

@kitbdev kitbdev Dec 5, 2023

Choose a reason for hiding this comment

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

Yes, since every time gui.sending_mouse_enter_exit_notifications is set to true, it is immediately set to false in the same scope after it is done sending a fixed amount of notifications. So it will never be true by the time deferred calls are made.
I'm not sure if there is a way to tell if this call is being called from the deferred queue, but I could add a check just in case something changes and it is set to true?

Also this method only removes Controls from a list and cannot add any, so it cannot keep calling itself infinitely from user code, like was previously possible in _gui_update_mouse_over.

@YuriSizov YuriSizov merged commit dcbb18d into godotengine:master Dec 8, 2023
15 checks passed
@YuriSizov
Copy link
Contributor

Thanks!

@kitbdev kitbdev deleted the fix-exit-hide branch December 8, 2023 16:31
@YuriSizov YuriSizov removed the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Jan 25, 2024
@YuriSizov
Copy link
Contributor

Cherry-picked for 4.2.2.

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.

Crash when hiding a panel from a NOTIFICATION_MOUSE_ENTER notification
5 participants