Browse Source

fix crash on hiding grandparent on mouse exit

(cherry picked from commit 78e1702adbfe9313a3747703c5e7abe6864cbcdf)
kit 1 year ago
parent
commit
29811357a3
2 changed files with 27 additions and 1 deletions
  1. 26 1
      scene/main/viewport.cpp
  2. 1 0
      scene/main/viewport.h

+ 26 - 1
scene/main/viewport.cpp

@@ -2459,6 +2459,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<Control *> new_mouse_over_hierarchy;
 	LocalVector<Control *> needs_enter;
@@ -2515,6 +2523,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);
@@ -2536,6 +2546,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 {
@@ -3208,10 +3220,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.
@@ -3219,6 +3233,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;
 		}
 	}
@@ -3260,6 +3276,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<SubViewportContainer>(gui.mouse_over);
 	if (c) {
@@ -3271,6 +3293,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);
 	}
@@ -3284,6 +3308,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<InputEvent> &p_event, bool p_local_coords) {

+ 1 - 0
scene/main/viewport.h

@@ -362,6 +362,7 @@ private:
 		Control *key_focus = nullptr;
 		Control *mouse_over = nullptr;
 		LocalVector<Control *> 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;