diff --git a/Userland/Libraries/LibGUI/CMakeLists.txt b/Userland/Libraries/LibGUI/CMakeLists.txt index a3e3ec78e0..abee81eac0 100644 --- a/Userland/Libraries/LibGUI/CMakeLists.txt +++ b/Userland/Libraries/LibGUI/CMakeLists.txt @@ -66,6 +66,7 @@ set(SOURCES Model.cpp ModelIndex.cpp ModelSelection.cpp + MouseTracker.cpp MultiView.cpp Notification.cpp OpacitySlider.cpp diff --git a/Userland/Libraries/LibGUI/MouseTracker.cpp b/Userland/Libraries/LibGUI/MouseTracker.cpp new file mode 100644 index 0000000000..dd9926400a --- /dev/null +++ b/Userland/Libraries/LibGUI/MouseTracker.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021, Ben Wiederhake + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace GUI { + +MouseTracker::List MouseTracker::s_trackers; + +MouseTracker::MouseTracker() +{ + if (s_trackers.is_empty()) { + WindowServerConnection::the().async_set_global_mouse_tracking(true); + } + s_trackers.append(*this); +} +MouseTracker::~MouseTracker() +{ + m_list_node.remove(); + if (s_trackers.is_empty()) { + WindowServerConnection::the().async_set_global_mouse_tracking(false); + } +} + +void MouseTracker::track_mouse_move(Badge, Gfx::IntPoint const& point) +{ + for (auto& tracker : s_trackers) { + tracker.track_mouse_move(point); + } +} + +} diff --git a/Userland/Libraries/LibGUI/MouseTracker.h b/Userland/Libraries/LibGUI/MouseTracker.h new file mode 100644 index 0000000000..0897106248 --- /dev/null +++ b/Userland/Libraries/LibGUI/MouseTracker.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021, Ben Wiederhake + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace GUI { + +class MouseTracker { +public: + MouseTracker(); + virtual ~MouseTracker(); + + static void track_mouse_move(Badge, Gfx::IntPoint const&); + +protected: + virtual void track_mouse_move(Gfx::IntPoint const&) = 0; + +private: + IntrusiveListNode m_list_node; + using List = IntrusiveList, &MouseTracker::m_list_node>; + static List s_trackers; +}; + +} diff --git a/Userland/Libraries/LibGUI/WindowServerConnection.cpp b/Userland/Libraries/LibGUI/WindowServerConnection.cpp index 4ab7b0e710..fb3a21b1d9 100644 --- a/Userland/Libraries/LibGUI/WindowServerConnection.cpp +++ b/Userland/Libraries/LibGUI/WindowServerConnection.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -370,6 +371,11 @@ void WindowServerConnection::display_link_notification() }); } +void WindowServerConnection::track_mouse_move(Gfx::IntPoint const& mouse_position) +{ + MouseTracker::track_mouse_move({}, mouse_position); +} + void WindowServerConnection::ping() { async_pong(); diff --git a/Userland/Libraries/LibGUI/WindowServerConnection.h b/Userland/Libraries/LibGUI/WindowServerConnection.h index f9d4b92751..68d768e915 100644 --- a/Userland/Libraries/LibGUI/WindowServerConnection.h +++ b/Userland/Libraries/LibGUI/WindowServerConnection.h @@ -55,6 +55,7 @@ private: virtual void update_system_fonts(String const&, String const&) override; virtual void window_state_changed(i32, bool, bool) override; virtual void display_link_notification() override; + virtual void track_mouse_move(Gfx::IntPoint const&) override; virtual void ping() override; bool m_display_link_notification_pending { false }; diff --git a/Userland/Services/WindowServer/ClientConnection.cpp b/Userland/Services/WindowServer/ClientConnection.cpp index 8823fba3c7..b6466ccaeb 100644 --- a/Userland/Services/WindowServer/ClientConnection.cpp +++ b/Userland/Services/WindowServer/ClientConnection.cpp @@ -663,6 +663,11 @@ void ClientConnection::set_global_cursor_tracking(i32 window_id, bool enabled) it->value->set_global_cursor_tracking_enabled(enabled); } +void ClientConnection::set_global_mouse_tracking(bool enabled) +{ + m_does_global_mouse_tracking = enabled; +} + void ClientConnection::set_window_cursor(i32 window_id, i32 cursor_type) { auto it = m_windows.find(window_id); diff --git a/Userland/Services/WindowServer/ClientConnection.h b/Userland/Services/WindowServer/ClientConnection.h index eddfc8bb02..56aca66c31 100644 --- a/Userland/Services/WindowServer/ClientConnection.h +++ b/Userland/Services/WindowServer/ClientConnection.h @@ -38,6 +38,7 @@ public: ~ClientConnection() override; bool is_unresponsive() const { return m_unresponsive; } + bool does_global_mouse_tracking() const { return m_does_global_mouse_tracking; } static ClientConnection* from_client_id(int client_id); static void for_each_client(Function); @@ -113,6 +114,7 @@ private: virtual void invalidate_rect(i32, Vector const&, bool) override; virtual void did_finish_painting(i32, Vector const&) override; virtual void set_global_cursor_tracking(i32, bool) override; + virtual void set_global_mouse_tracking(bool) override; virtual void set_window_opacity(i32, float) override; virtual void set_window_backing_store(i32, i32, i32, IPC::File const&, i32, bool, Gfx::IntSize const&, bool) override; virtual void set_window_has_alpha_channel(i32, bool) override; @@ -179,6 +181,7 @@ private: bool m_has_display_link { false }; bool m_show_screen_number { false }; bool m_unresponsive { false }; + bool m_does_global_mouse_tracking { false }; // Need this to get private client connection stuff friend WMClientConnection; diff --git a/Userland/Services/WindowServer/WindowClient.ipc b/Userland/Services/WindowServer/WindowClient.ipc index 2b8b3c839f..e9a6ac9bf3 100644 --- a/Userland/Services/WindowServer/WindowClient.ipc +++ b/Userland/Services/WindowServer/WindowClient.ipc @@ -44,5 +44,7 @@ endpoint WindowClient display_link_notification() =| + track_mouse_move(Gfx::IntPoint mouse_position) =| + ping() =| } diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index c816377c71..a2388d51ef 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -1200,15 +1200,18 @@ void WindowManager::process_mouse_event(MouseEvent& event) if (process_ongoing_drag(event)) return; - // 2. Send the mouse event to all windows with global cursor tracking enabled. - // The active input tracking window is excluded here because we're sending the event to it - // in the next step. + // 2. Send the mouse event to all clients with global cursor tracking enabled. auto& window_stack = current_window_stack(); for_each_visible_window_from_front_to_back([&](Window& window) { if (window.global_cursor_tracking() && &window != window_stack.active_input_tracking_window()) deliver_mouse_event(window, event, false); return IterationDecision::Continue; }); + ClientConnection::for_each_client([&](ClientConnection& conn) { + if (conn.does_global_mouse_tracking()) { + conn.async_track_mouse_move(event.position()); + } + }); // 3. If there's an active input tracking window, all mouse events go there. // Tracking ends after all mouse buttons have been released. diff --git a/Userland/Services/WindowServer/WindowServer.ipc b/Userland/Services/WindowServer/WindowServer.ipc index 41accd5251..dfa282c36d 100644 --- a/Userland/Services/WindowServer/WindowServer.ipc +++ b/Userland/Services/WindowServer/WindowServer.ipc @@ -75,6 +75,7 @@ endpoint WindowServer did_finish_painting(i32 window_id, Vector rects) =| set_global_cursor_tracking(i32 window_id, bool enabled) =| + set_global_mouse_tracking(bool enabled) =| set_window_opacity(i32 window_id, float opacity) =| set_window_alpha_hit_threshold(i32 window_id, float threshold) =|