1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-14 13:41:12 +00:00

Refactor mouse_entered and mouse_exited notifications

The previous implementation for signals mouse_entered and mouse_exited
had shortcomings that relate to focused windows and pressed mouse buttons.
For example a Control can be hovered by mouse, even if it is occluded by
an embedded window.

This patch changes the behavior, so that Control and Viewport send
their mouse-enter/exit-notifications based solely on mouse position,
visible area, and input restrictions and not on which window has
focus or which mouse buttons are pressed. This implicitly also
changes when the mouse_entered and mouse_exited signals are sent.

This functionality can not be implemented as a part of
Viewport::_gui_input_event, because of its interplay with Windows and
because Viewport::_gui_input_event is based on input and not on
visibility.
This commit is contained in:
Markus Sauermann
2023-01-06 21:48:20 +01:00
parent da81ca62a5
commit 1c3c17c608
8 changed files with 213 additions and 56 deletions

View File

@@ -677,16 +677,20 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
switch (p_event) {
case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: {
_propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER);
emit_signal(SNAME("mouse_entered"));
Window *root = get_tree()->get_root();
DEV_ASSERT(!root->gui.windowmanager_window_over); // Entering a window while a window is hovered should never happen.
root->gui.windowmanager_window_over = this;
notification(NOTIFICATION_VP_MOUSE_ENTER);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) {
DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape
}
} break;
case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: {
notification(NOTIFICATION_VP_MOUSE_EXIT);
Window *root = get_tree()->get_root();
DEV_ASSERT(root->gui.windowmanager_window_over); // Exiting a window, while no window is hovered should never happen.
root->gui.windowmanager_window_over->_mouse_leave_viewport();
root->gui.windowmanager_window_over = nullptr;
_propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT);
emit_signal(SNAME("mouse_exited"));
} break;
case DisplayServer::WINDOW_EVENT_FOCUS_IN: {
focused = true;
@@ -1283,6 +1287,14 @@ void Window::_notification(int p_what) {
RS::get_singleton()->viewport_set_active(get_viewport_rid(), false);
} break;
case NOTIFICATION_VP_MOUSE_ENTER: {
emit_signal(SceneStringNames::get_singleton()->mouse_entered);
} break;
case NOTIFICATION_VP_MOUSE_EXIT: {
emit_signal(SceneStringNames::get_singleton()->mouse_exited);
} break;
}
}
@@ -2495,6 +2507,10 @@ bool Window::is_directly_attached_to_screen() const {
return is_inside_tree();
}
bool Window::is_attached_in_viewport() const {
return get_embedder();
}
void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);