Skip to content

Commit

Permalink
Merge pull request #85313 from kitbdev/fix-exit-hide
Browse files Browse the repository at this point in the history
Fix crash on hiding grandparent Control on mouse exit
  • Loading branch information
YuriSizov committed Dec 8, 2023
2 parents 44d544f + 78e1702 commit dcbb18d
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 1 deletion.
27 changes: 26 additions & 1 deletion scene/main/viewport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Control *> new_mouse_over_hierarchy;
LocalVector<Control *> needs_enter;
Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand Down Expand Up @@ -3200,17 +3212,21 @@ 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.
if (gui.mouse_over) {
gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF);
}

gui.sending_mouse_enter_exit_notifications = false;

notify_embedded_viewports = true;
}
}
Expand Down Expand Up @@ -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<SubViewportContainer>(gui.mouse_over);
if (c) {
Expand All @@ -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);
}
Expand All @@ -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<InputEvent> &p_event, bool p_local_coords) {
Expand Down
1 change: 1 addition & 0 deletions scene/main/viewport.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ class Viewport : public Node {
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;
Expand Down

0 comments on commit dcbb18d

Please sign in to comment.