diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index e9ea09a3b1cd..8cb7614dfd8b 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2451,6 +2451,14 @@ void Viewport::_gui_update_mouse_over() { return; } + if (gui.sending_mouse_enter_exit_notifications) { + // If notifications are already being sent, delay call to next frame. + if (get_tree() && !get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over))) { + get_tree()->connect(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over), CONNECT_ONE_SHOT); + } + return; + } + // Rebuild the mouse over hierarchy. LocalVector new_mouse_over_hierarchy; LocalVector needs_enter; @@ -2507,6 +2515,8 @@ void Viewport::_gui_update_mouse_over() { return; } + gui.sending_mouse_enter_exit_notifications = true; + // Send Mouse Exit Self notification. if (gui.mouse_over && !needs_exit.is_empty() && needs_exit[0] == (int)gui.mouse_over_hierarchy.size() - 1) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF); @@ -2528,6 +2538,8 @@ void Viewport::_gui_update_mouse_over() { for (int i = needs_enter.size() - 1; i >= 0; i--) { needs_enter[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); } + + gui.sending_mouse_enter_exit_notifications = false; } Window *Viewport::get_base_window() const { @@ -3200,10 +3212,12 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { gui.mouse_over = over; gui.mouse_over_hierarchy.reserve(gui.mouse_over_hierarchy.size() + over_ancestors.size()); + gui.sending_mouse_enter_exit_notifications = true; + // Send Mouse Enter notifications to parents first. for (int i = over_ancestors.size() - 1; i >= 0; i--) { - over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); gui.mouse_over_hierarchy.push_back(over_ancestors[i]); + over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); } // Send Mouse Enter Self notification. @@ -3211,6 +3225,8 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF); } + gui.sending_mouse_enter_exit_notifications = false; + notify_embedded_viewports = true; } } @@ -3252,6 +3268,12 @@ void Viewport::_mouse_leave_viewport() { } void Viewport::_drop_mouse_over(Control *p_until_control) { + 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; + } + _gui_cancel_tooltip(); SubViewportContainer *c = Object::cast_to(gui.mouse_over); if (c) { @@ -3263,6 +3285,8 @@ void Viewport::_drop_mouse_over(Control *p_until_control) { v->_mouse_leave_viewport(); } } + + gui.sending_mouse_enter_exit_notifications = true; if (gui.mouse_over && gui.mouse_over->is_inside_tree()) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF); } @@ -3276,6 +3300,7 @@ void Viewport::_drop_mouse_over(Control *p_until_control) { } } gui.mouse_over_hierarchy.resize(notification_until); + gui.sending_mouse_enter_exit_notifications = false; } void Viewport::push_input(const Ref &p_event, bool p_local_coords) { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 82a9bfc438dc..6efa98ece85e 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -362,6 +362,7 @@ class Viewport : public Node { Control *key_focus = nullptr; Control *mouse_over = nullptr; LocalVector mouse_over_hierarchy; + bool sending_mouse_enter_exit_notifications = false; Window *subwindow_over = nullptr; // mouse_over and subwindow_over are mutually exclusive. At all times at least one of them is nullptr. Window *windowmanager_window_over = nullptr; // Only used in root Viewport. Control *drag_mouse_over = nullptr;