From be48a89b35e1b1d6f2b981e6c4d7049418d3a48f Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 14 Feb 2021 13:48:28 -0700 Subject: [PATCH] WindowServer: Fix double click handling while using cursor tracking We need to first deliver the mouse event and possibly the double click event and record these facts. Then, we need to iterate all global tracking listeners and deliver the mouse event (but not the double click event) to any such listener, unless they already had these events delivered. Fixes #4703 --- .../Services/WindowServer/MenuManager.cpp | 4 +- .../Services/WindowServer/WindowManager.cpp | 39 ++++++++++--------- .../Services/WindowServer/WindowManager.h | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Userland/Services/WindowServer/MenuManager.cpp b/Userland/Services/WindowServer/MenuManager.cpp index f7521ff060..5f57c4dc03 100644 --- a/Userland/Services/WindowServer/MenuManager.cpp +++ b/Userland/Services/WindowServer/MenuManager.cpp @@ -225,7 +225,7 @@ void MenuManager::handle_mouse_event(MouseEvent& mouse_event) if (event_is_inside_current_menu) { WindowManager::the().set_hovered_window(window); auto translated_event = mouse_event.translated(-window->position()); - WindowManager::the().deliver_mouse_event(*window, translated_event); + WindowManager::the().deliver_mouse_event(*window, translated_event, true); return; } @@ -262,7 +262,7 @@ void MenuManager::handle_mouse_event(MouseEvent& mouse_event) continue; WindowManager::the().set_hovered_window(menu->menu_window()); auto translated_event = mouse_event.translated(-menu->menu_window()->position()); - WindowManager::the().deliver_mouse_event(*menu->menu_window(), translated_event); + WindowManager::the().deliver_mouse_event(*menu->menu_window(), translated_event, true); break; } } diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index e2dc90e86a..d9b3c729a3 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -716,7 +716,7 @@ bool WindowManager::process_ongoing_drag(MouseEvent& event, Window*& hovered_win auto translated_event = event.translated(-window.position()); translated_event.set_drag(true); translated_event.set_mime_data(*m_dnd_mime_data); - deliver_mouse_event(window, translated_event); + deliver_mouse_event(window, translated_event, false); return IterationDecision::Break; }); } @@ -875,10 +875,10 @@ void WindowManager::process_event_for_doubleclick(Window& window, MouseEvent& ev metadata.last_position = event.position(); } -void WindowManager::deliver_mouse_event(Window& window, MouseEvent& event) +void WindowManager::deliver_mouse_event(Window& window, MouseEvent& event, bool process_double_click) { window.dispatch_event(event); - if (event.type() == Event::MouseUp) { + if (process_double_click && event.type() == Event::MouseUp) { process_event_for_doubleclick(window, event); if (event.type() == Event::MouseDoubleClick) window.dispatch_event(event); @@ -887,21 +887,13 @@ void WindowManager::deliver_mouse_event(Window& window, MouseEvent& event) void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_window) { - HashTable windows_who_received_mouse_event_due_to_cursor_tracking; + Window* received_mouse_event = nullptr; // We need to process ongoing drag events first. Otherwise, global tracking // and dnd collides, leading to duplicate GUI::DragOperation instances if (process_ongoing_drag(event, hovered_window)) return; - for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) { - if (!window->global_cursor_tracking() || !window->is_visible() || window->is_minimized() || window->blocking_modal_window()) - continue; - windows_who_received_mouse_event_due_to_cursor_tracking.set(window); - auto translated_event = event.translated(-window->position()); - deliver_mouse_event(*window, translated_event); - } - hovered_window = nullptr; if (process_ongoing_window_move(event, hovered_window)) @@ -939,11 +931,10 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind // // This prevents e.g. moving on one window out of the bounds starting // a move in that other unrelated window, and other silly shenanigans. - if (!windows_who_received_mouse_event_due_to_cursor_tracking.contains(m_active_input_tracking_window)) { - auto translated_event = event.translated(-m_active_input_tracking_window->position()); - deliver_mouse_event(*m_active_input_tracking_window, translated_event); - windows_who_received_mouse_event_due_to_cursor_tracking.set(m_active_input_tracking_window.ptr()); - } + auto translated_event = event.translated(-m_active_input_tracking_window->position()); + deliver_mouse_event(*m_active_input_tracking_window, translated_event, true); + received_mouse_event = m_active_input_tracking_window.ptr(); + if (event.type() == Event::MouseUp && event.buttons() == 0) { m_active_input_tracking_window = nullptr; } @@ -1002,9 +993,10 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind // Well okay, let's see if we're hitting the frame or the window inside the frame. if (window.rect().contains(event.position())) { hovered_window = &window; - if (!window.global_cursor_tracking() && !windows_who_received_mouse_event_due_to_cursor_tracking.contains(&window) && !window.blocking_modal_window()) { + if (!window.global_cursor_tracking() && !window.blocking_modal_window()) { auto translated_event = event.translated(-window.position()); - deliver_mouse_event(window, translated_event); + deliver_mouse_event(window, translated_event, true); + received_mouse_event = &window; if (event.type() == Event::MouseDown) { m_active_input_tracking_window = window; } @@ -1034,6 +1026,15 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind set_active_window(nullptr); } + for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) { + if (received_mouse_event == window) + continue; + if (!window->global_cursor_tracking() || !window->is_visible() || window->is_minimized() || window->blocking_modal_window()) + continue; + auto translated_event = event.translated(-window->position()); + deliver_mouse_event(*window, translated_event, false); + } + if (event_window_with_frame != m_resize_candidate.ptr()) clear_resize_candidate(); } diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index 7711a19af9..21cb345f85 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -190,7 +190,7 @@ public: bool update_theme(String theme_path, String theme_name); void set_hovered_window(Window*); - void deliver_mouse_event(Window& window, MouseEvent& event); + void deliver_mouse_event(Window& window, MouseEvent& event, bool process_double_click); void did_popup_a_menu(Badge);