diff options
author | Andreas Kling <kling@serenityos.org> | 2021-06-18 12:39:20 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-18 17:40:05 +0200 |
commit | 82a945fa7e69b29100495d1189b495582e1689d6 (patch) | |
tree | b4fcaf926bcf4399eea84931a5c250dd61240b49 /Userland/Services | |
parent | 69dad3b9967bd4ab99aa30a2231de3e4e8552005 (diff) | |
download | serenity-82a945fa7e69b29100495d1189b495582e1689d6.zip |
WindowServer: Always send mouse events to active input tracker first
If a window is currently actively tracking input events (because
sent it a MouseDown and haven't sent it a MouseUp yet), we now simply
send mouse events to that window right away before doing any other
event processing.
This makes it much easier to reason about mouse events.
Diffstat (limited to 'Userland/Services')
-rw-r--r-- | Userland/Services/WindowServer/WindowManager.cpp | 158 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowManager.h | 1 |
2 files changed, 82 insertions, 77 deletions
diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index 70bc4fcbe4..e63860cd01 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -919,17 +919,39 @@ void WindowManager::deliver_mouse_event(Window& window, MouseEvent& event, bool } } +bool WindowManager::process_ongoing_active_input_mouse_event(MouseEvent& event, Window*& hovered_window) +{ + if (!m_active_input_tracking_window) + return false; + + // At this point, we have delivered the start of an input sequence to a + // client application. We must keep delivering to that client + // application until the input sequence is done. + // + // This prevents e.g. moving on one window out of the bounds starting + // a move in that other unrelated window, and other silly shenanigans. + auto translated_event = event.translated(-m_active_input_tracking_window->position()); + deliver_mouse_event(*m_active_input_tracking_window, translated_event, true); + + if (event.type() == Event::MouseUp && event.buttons() == 0) { + m_active_input_tracking_window = nullptr; + } + + hovered_window = m_window_stack.window_at(event.position()); + return true; +} + void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_window) { - Window* received_mouse_event = nullptr; + hovered_window = nullptr; + if (process_ongoing_active_input_mouse_event(event, hovered_window)) + return; // 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; - hovered_window = nullptr; - if (process_ongoing_window_move(event, hovered_window)) return; @@ -972,90 +994,73 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind } Window* event_window_with_frame = nullptr; + Window* received_mouse_event = nullptr; - if (m_active_input_tracking_window) { - // At this point, we have delivered the start of an input sequence to a - // client application. We must keep delivering to that client - // application until the input sequence is done. - // - // This prevents e.g. moving on one window out of the bounds starting - // a move in that other unrelated window, and other silly shenanigans. - 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; - } + auto process_mouse_event_for_window = [&](Window& window) { + if (&window != m_resize_candidate.ptr()) + clear_resize_candidate(); - hovered_window = m_window_stack.window_at(event.position()); - } else { - auto process_mouse_event_for_window = [&](Window& window) { - if (&window != m_resize_candidate.ptr()) - clear_resize_candidate(); - - // First check if we should initiate a move or resize (Super+LMB or Super+RMB). - // In those cases, the event is swallowed by the window manager. - if (window.is_movable()) { - if (!window.is_fullscreen() && m_keyboard_modifiers == Mod_Super && event.type() == Event::MouseDown && event.button() == MouseButton::Left) { - hovered_window = &window; - start_window_move(window, event); - return; - } - if (window.is_resizable() && m_keyboard_modifiers == Mod_Super && event.type() == Event::MouseDown && event.button() == MouseButton::Right && !window.blocking_modal_window()) { - hovered_window = &window; - start_window_resize(window, event); - return; - } + // First check if we should initiate a move or resize (Super+LMB or Super+RMB). + // In those cases, the event is swallowed by the window manager. + if (window.is_movable()) { + if (!window.is_fullscreen() && m_keyboard_modifiers == Mod_Super && event.type() == Event::MouseDown && event.button() == MouseButton::Left) { + hovered_window = &window; + start_window_move(window, event); + return; } - - VERIFY(window.hit_test(event.position()).has_value()); - if (event.type() == Event::MouseDown) { - // We're clicking on something that's blocked by a modal window. - // Flash the modal window to let the user know about it. - if (auto* blocking_modal_window = window.blocking_modal_window()) - blocking_modal_window->frame().start_flash_animation(); - - if (window.type() == WindowType::Normal || window.type() == WindowType::ToolWindow) - move_to_front_and_make_active(window); - else if (window.type() == WindowType::Desktop) - set_active_window(&window); + if (window.is_resizable() && m_keyboard_modifiers == Mod_Super && event.type() == Event::MouseDown && event.button() == MouseButton::Right && !window.blocking_modal_window()) { + hovered_window = &window; + start_window_resize(window, event); + return; } + } - if (window.frame().hit_test(event.position()).has_value()) { - // We are hitting the frame, pass the event along to WindowFrame. - window.frame().handle_mouse_event(event.translated(-window.frame().rect().location())); - event_window_with_frame = &window; - } else if (window.hit_test(event.position(), false).has_value()) { - // We are hitting the window content - hovered_window = &window; - if (!window.global_cursor_tracking() && !window.blocking_modal_window()) { - auto translated_event = event.translated(-window.position()); - deliver_mouse_event(window, translated_event, true); - received_mouse_event = &window; - if (event.type() == Event::MouseDown) { - m_active_input_tracking_window = window; - } + VERIFY(window.hit_test(event.position()).has_value()); + if (event.type() == Event::MouseDown) { + // We're clicking on something that's blocked by a modal window. + // Flash the modal window to let the user know about it. + if (auto* blocking_modal_window = window.blocking_modal_window()) + blocking_modal_window->frame().start_flash_animation(); + + if (window.type() == WindowType::Normal || window.type() == WindowType::ToolWindow) + move_to_front_and_make_active(window); + else if (window.type() == WindowType::Desktop) + set_active_window(&window); + } + + if (window.frame().hit_test(event.position()).has_value()) { + // We are hitting the frame, pass the event along to WindowFrame. + window.frame().handle_mouse_event(event.translated(-window.frame().rect().location())); + event_window_with_frame = &window; + } else if (window.hit_test(event.position(), false).has_value()) { + // We are hitting the window content + hovered_window = &window; + if (!window.global_cursor_tracking() && !window.blocking_modal_window()) { + auto translated_event = event.translated(-window.position()); + deliver_mouse_event(window, translated_event, true); + received_mouse_event = &window; + if (event.type() == Event::MouseDown) { + m_active_input_tracking_window = window; } } - }; - - if (auto* fullscreen_window = active_fullscreen_window()) { - process_mouse_event_for_window(*fullscreen_window); - } else { - m_window_stack.for_each_visible_window_from_front_to_back([&](Window& window) { - if (!window.hit_test(event.position()).has_value()) - return IterationDecision::Continue; - process_mouse_event_for_window(window); - return IterationDecision::Break; - }); } + }; - // Clicked outside of any window - if (!hovered_window && !event_window_with_frame && event.type() == Event::MouseDown) - set_active_window(nullptr); + if (auto* fullscreen_window = active_fullscreen_window()) { + process_mouse_event_for_window(*fullscreen_window); + } else { + m_window_stack.for_each_visible_window_from_front_to_back([&](Window& window) { + if (!window.hit_test(event.position()).has_value()) + return IterationDecision::Continue; + process_mouse_event_for_window(window); + return IterationDecision::Break; + }); } + // Clicked outside of any window + if (!hovered_window && !event_window_with_frame && event.type() == Event::MouseDown) + set_active_window(nullptr); + auto reverse_iterator = m_window_stack.windows().rbegin(); for (; reverse_iterator != m_window_stack.windows().rend(); ++reverse_iterator) { auto& window = *reverse_iterator; @@ -1620,5 +1625,4 @@ void WindowManager::set_window_with_active_menu(Window* window) else m_window_with_active_menu = nullptr; } - } diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index def645aea2..9ab46fc427 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -239,6 +239,7 @@ private: bool process_ongoing_window_resize(MouseEvent const&, Window*& hovered_window); bool process_ongoing_window_move(MouseEvent&, Window*& hovered_window); bool process_ongoing_drag(MouseEvent&, Window*& hovered_window); + bool process_ongoing_active_input_mouse_event(MouseEvent&, Window*& hovered_window); template<typename Callback> void for_each_window_manager(Callback); |