diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d405fd90903..ae329e1e9cf 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -184,6 +184,7 @@ public: Viewport::GUI::GUI() { dragging = false; drag_successful = false; + mouse_in_window = true; mouse_focus = nullptr; mouse_click_grabber = nullptr; mouse_focus_mask = 0; @@ -398,21 +399,26 @@ void Viewport::_notification(int p_what) { _process_picking(false); } } break; - case SceneTree::NOTIFICATION_WM_MOUSE_EXIT: { - _drop_physics_mouseover(); - - // Unlike on loss of focus (NOTIFICATION_WM_WINDOW_FOCUS_OUT), do not - // drop the gui mouseover here, as a scrollbar may be dragged while the - // mouse is outside the window (without the window having lost focus). - // See bug #39634 + case NOTIFICATION_WM_MOUSE_ENTER: { + gui.mouse_in_window = true; } break; - case SceneTree::NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_WM_MOUSE_EXIT: { + gui.mouse_in_window = false; + _drop_physics_mouseover(); + _drop_mouse_over(); + // When the mouse exits the window, we want to end mouse_over, but + // not mouse_focus, because, for example, we want to continue + // dragging a scrollbar even if the mouse has left the window. + } break; + case NOTIFICATION_WM_FOCUS_OUT: { _drop_physics_mouseover(); - if (gui.mouse_focus) { - //if mouse is being pressed, send a release event _drop_mouse_focus(); } + // When the window focus changes, we want to end mouse_focus, but + // not the mouse_over. Note: The OS will trigger a separate mouse + // exit event if the change in focus results in the mouse exiting + // the window. } break; } } @@ -1861,9 +1867,6 @@ void Viewport::_gui_input_event(Ref p_event) { if (mb.is_valid()) { gui.key_event_accepted = false; - - Control *over = nullptr; - Point2 mpos = mb->get_position(); if (mb->is_pressed()) { Size2 pos = mpos; @@ -2057,6 +2060,8 @@ void Viewport::_gui_input_event(Ref p_event) { // it is different, rather than wait for it to be updated the next time the // mouse is moved, notify the control so that it can e.g. drop the highlight. // This code is duplicated from the mm.is_valid()-case further below. + + Control *over = nullptr; if (gui.mouse_focus) { over = gui.mouse_focus; } else { @@ -2087,8 +2092,6 @@ void Viewport::_gui_input_event(Ref p_event) { gui.last_mouse_pos = mpos; - Control *over = nullptr; - // D&D if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) { gui.drag_accum += mm->get_relative(); @@ -2135,12 +2138,10 @@ void Viewport::_gui_input_event(Ref p_event) { } } - // These sections of code are reused in the mb.is_valid() case further up - // for the purpose of notifying controls about potential changes in focus - // when the mousebutton is released. + Control *over = nullptr; if (gui.mouse_focus) { over = gui.mouse_focus; - } else { + } else if (gui.mouse_in_window) { over = _gui_find_control(mpos); } @@ -2187,11 +2188,10 @@ void Viewport::_gui_input_event(Ref p_event) { if (over) { _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER); + gui.mouse_over = over; } } - gui.mouse_over = over; - Control *drag_preview = _gui_get_drag_preview(); if (drag_preview) { drag_preview->set_position(mpos); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 8d1de3dfa80..500b46bde7f 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -295,6 +295,7 @@ private: // info used when this is a window bool key_event_accepted; + bool mouse_in_window; Control *mouse_focus; Control *last_mouse_focus; Control *mouse_click_grabber;