diff --git a/LibGUI/GButton.cpp b/LibGUI/GButton.cpp index 62cda2255e1..fe7ccc65bf6 100644 --- a/LibGUI/GButton.cpp +++ b/LibGUI/GButton.cpp @@ -46,7 +46,7 @@ void GButton::paint_event(GPaintEvent& event) void GButton::mousemove_event(GMouseEvent& event) { - if (m_tracking_cursor) { + if (event.buttons() == GMouseButton::Left) { bool being_pressed = rect().contains(event.position()); if (being_pressed != m_being_pressed) { m_being_pressed = being_pressed; @@ -63,8 +63,6 @@ void GButton::mousedown_event(GMouseEvent& event) #endif if (event.button() == GMouseButton::Left) { m_being_pressed = true; - m_tracking_cursor = true; - set_global_cursor_tracking(true); update(); } GWidget::mousedown_event(event); @@ -84,8 +82,6 @@ void GButton::mouseup_event(GMouseEvent& event) if (event.button() == GMouseButton::Left) { bool was_being_pressed = m_being_pressed; m_being_pressed = false; - m_tracking_cursor = false; - set_global_cursor_tracking(false); update(); if (was_being_pressed) click(); diff --git a/LibGUI/GButton.h b/LibGUI/GButton.h index 4edb2c719e8..1a5ed4b905d 100644 --- a/LibGUI/GButton.h +++ b/LibGUI/GButton.h @@ -39,7 +39,6 @@ private: RetainPtr m_icon; GButtonStyle m_button_style { GButtonStyle::Normal }; bool m_being_pressed { false }; - bool m_tracking_cursor { false }; bool m_hovered { false }; }; diff --git a/LibGUI/GCheckBox.cpp b/LibGUI/GCheckBox.cpp index 3627e0b5cfe..101ca327072 100644 --- a/LibGUI/GCheckBox.cpp +++ b/LibGUI/GCheckBox.cpp @@ -90,10 +90,10 @@ void GCheckBox::paint_event(GPaintEvent& event) void GCheckBox::mousemove_event(GMouseEvent& event) { - if (m_tracking_cursor) { - bool being_pressed = rect().contains(event.position()); - if (being_pressed != m_being_modified) { - m_being_modified = being_pressed; + if (event.buttons() == GMouseButton::Left) { + bool being_modified = rect().contains(event.position()); + if (being_modified != m_being_modified) { + m_being_modified = being_modified; update(); } } @@ -107,8 +107,6 @@ void GCheckBox::mousedown_event(GMouseEvent& event) #endif if (event.button() == GMouseButton::Left) { m_being_modified = true; - m_tracking_cursor = true; - set_global_cursor_tracking(true); update(); } GWidget::mousedown_event(event); @@ -122,11 +120,8 @@ void GCheckBox::mouseup_event(GMouseEvent& event) if (event.button() == GMouseButton::Left) { bool was_being_pressed = m_being_modified; m_being_modified = false; - m_tracking_cursor = false; - set_global_cursor_tracking(false); - if (was_being_pressed) { + if (was_being_pressed) set_checked(!is_checked()); - } update(); } GWidget::mouseup_event(event); @@ -134,7 +129,7 @@ void GCheckBox::mouseup_event(GMouseEvent& event) void GCheckBox::keydown_event(GKeyEvent& event) { - if (!m_tracking_cursor && event.key() == KeyCode::Key_Space) { + if (event.key() == KeyCode::Key_Space) { set_checked(!is_checked()); update(); } diff --git a/LibGUI/GCheckBox.h b/LibGUI/GCheckBox.h index c31549d67ba..2a85642a5f4 100644 --- a/LibGUI/GCheckBox.h +++ b/LibGUI/GCheckBox.h @@ -30,6 +30,5 @@ private: String m_caption; bool m_checked { false }; bool m_being_modified { false }; - bool m_tracking_cursor { false }; }; diff --git a/LibGUI/GScrollBar.cpp b/LibGUI/GScrollBar.cpp index 7db74c4e70e..6b942f21c51 100644 --- a/LibGUI/GScrollBar.cpp +++ b/LibGUI/GScrollBar.cpp @@ -222,7 +222,6 @@ void GScrollBar::mousedown_event(GMouseEvent& event) m_scrubbing = true; m_scrub_start_value = value(); m_scrub_origin = event.position(); - set_global_cursor_tracking(true); update(); return; } @@ -235,7 +234,6 @@ void GScrollBar::mouseup_event(GMouseEvent& event) if (!m_scrubbing) return; m_scrubbing = false; - set_global_cursor_tracking(false); update(); } diff --git a/LibGUI/GTextEditor.cpp b/LibGUI/GTextEditor.cpp index e6bb0603189..f3d877eb261 100644 --- a/LibGUI/GTextEditor.cpp +++ b/LibGUI/GTextEditor.cpp @@ -88,7 +88,6 @@ void GTextEditor::mousedown_event(GMouseEvent& event) } m_in_drag_select = true; - set_global_cursor_tracking(true); set_cursor(text_position_at(event.position())); @@ -111,7 +110,6 @@ void GTextEditor::mouseup_event(GMouseEvent& event) if (event.button() == GMouseButton::Left) { if (m_in_drag_select) { m_in_drag_select = false; - set_global_cursor_tracking(false); } return; } diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index 0001766406f..610e15fe8c1 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -143,21 +143,34 @@ void GWindow::set_rect(const Rect& a_rect) void GWindow::event(GEvent& event) { if (event.is_mouse_event()) { + auto& mouse_event = static_cast(event); if (m_global_cursor_tracking_widget) { - auto& mouse_event = static_cast(event); auto window_relative_rect = m_global_cursor_tracking_widget->window_relative_rect(); Point local_point { mouse_event.x() - window_relative_rect.x(), mouse_event.y() - window_relative_rect.y() }; auto local_event = make(event.type(), local_point, mouse_event.buttons(), mouse_event.button(), mouse_event.modifiers()); m_global_cursor_tracking_widget->event(*local_event); + return; + } + if (m_automatic_cursor_tracking_widget) { + auto window_relative_rect = m_automatic_cursor_tracking_widget->window_relative_rect(); + Point local_point { mouse_event.x() - window_relative_rect.x(), mouse_event.y() - window_relative_rect.y() }; + auto local_event = make(event.type(), local_point, mouse_event.buttons(), mouse_event.button(), mouse_event.modifiers()); + m_automatic_cursor_tracking_widget->event(*local_event); + if (mouse_event.buttons() == 0) { + m_automatic_cursor_tracking_widget = nullptr; + return; + } + return; } if (!m_main_widget) return; - auto& mouse_event = static_cast(event); if (m_main_widget) { auto result = m_main_widget->hit_test(mouse_event.x(), mouse_event.y()); auto local_event = make(event.type(), Point { result.localX, result.localY }, mouse_event.buttons(), mouse_event.button(), mouse_event.modifiers()); ASSERT(result.widget); set_hovered_widget(result.widget); + if (mouse_event.buttons() != 0 && !m_automatic_cursor_tracking_widget) + m_automatic_cursor_tracking_widget = result.widget->make_weak_ptr(); if (result.widget != m_global_cursor_tracking_widget.ptr()) return result.widget->event(*local_event); } @@ -298,18 +311,16 @@ void GWindow::set_focused_widget(GWidget* widget) void GWindow::set_global_cursor_tracking_widget(GWidget* widget) { - ASSERT(m_window_id); if (widget == m_global_cursor_tracking_widget.ptr()) return; m_global_cursor_tracking_widget = widget ? widget->make_weak_ptr() : nullptr; +} - WSAPI_ClientMessage request; - request.type = WSAPI_ClientMessage::Type::SetGlobalCursorTracking; - request.window_id = m_window_id; - request.value = widget != nullptr; - // FIXME: What if the cursor moves out of our interest range before the server can handle this? - // Maybe there could be a response that includes the current cursor location as of enabling. - GEventLoop::current().post_message_to_server(request); +void GWindow::set_automatic_cursor_tracking_widget(GWidget* widget) +{ + if (widget == m_automatic_cursor_tracking_widget.ptr()) + return; + m_automatic_cursor_tracking_widget = widget ? widget->make_weak_ptr() : nullptr; } void GWindow::set_has_alpha_channel(bool value) diff --git a/LibGUI/GWindow.h b/LibGUI/GWindow.h index 720de5b408b..27b6d3e68bd 100644 --- a/LibGUI/GWindow.h +++ b/LibGUI/GWindow.h @@ -65,6 +65,10 @@ public: GWidget* global_cursor_tracking_widget() { return m_global_cursor_tracking_widget.ptr(); } const GWidget* global_cursor_tracking_widget() const { return m_global_cursor_tracking_widget.ptr(); } + void set_automatic_cursor_tracking_widget(GWidget*); + GWidget* automatic_cursor_tracking_widget() { return m_automatic_cursor_tracking_widget.ptr(); } + const GWidget* automatic_cursor_tracking_widget() const { return m_automatic_cursor_tracking_widget.ptr(); } + bool should_exit_event_loop_on_close() const { return m_should_exit_app_on_close; } void set_should_exit_event_loop_on_close(bool b) { m_should_exit_app_on_close = b; } @@ -96,6 +100,7 @@ private: GWidget* m_main_widget { nullptr }; GWidget* m_focused_widget { nullptr }; WeakPtr m_global_cursor_tracking_widget; + WeakPtr m_automatic_cursor_tracking_widget; WeakPtr m_hovered_widget; Rect m_rect_when_windowless; String m_title_when_windowless; diff --git a/Servers/WindowServer/WSWindow.cpp b/Servers/WindowServer/WSWindow.cpp index 385ff24d1ff..bde22c0109e 100644 --- a/Servers/WindowServer/WSWindow.cpp +++ b/Servers/WindowServer/WSWindow.cpp @@ -69,6 +69,28 @@ static WSAPI_MouseButton to_api(MouseButton button) ASSERT_NOT_REACHED(); } +void WSWindow::handle_mouse_event(const WSMouseEvent& event) +{ + set_automatic_cursor_tracking_enabled(event.buttons() != 0); + + WSAPI_ServerMessage server_message; + server_message.window_id = window_id(); + + switch (event.type()) { + case WSMessage::MouseMove: server_message.type = WSAPI_ServerMessage::Type::MouseMove; break; + case WSMessage::MouseDown: server_message.type = WSAPI_ServerMessage::Type::MouseDown; break; + case WSMessage::MouseUp: server_message.type = WSAPI_ServerMessage::Type::MouseUp; break; + default: ASSERT_NOT_REACHED(); + } + + server_message.mouse.position = event.position(); + server_message.mouse.button = to_api(event.button()); + server_message.mouse.buttons = event.buttons(); + server_message.mouse.modifiers = event.modifiers(); + + m_client->post_message(server_message); +} + void WSWindow::on_message(WSMessage& message) { if (m_internal_owner) @@ -80,28 +102,10 @@ void WSWindow::on_message(WSMessage& message) WSAPI_ServerMessage server_message; server_message.window_id = window_id(); + if (message.is_mouse_event()) + return handle_mouse_event(static_cast(message)); + switch (message.type()) { - case WSMessage::MouseMove: - server_message.type = WSAPI_ServerMessage::Type::MouseMove; - server_message.mouse.position = static_cast(message).position(); - server_message.mouse.button = WSAPI_MouseButton::NoButton; - server_message.mouse.buttons = static_cast(message).buttons(); - server_message.mouse.modifiers = static_cast(message).modifiers(); - break; - case WSMessage::MouseDown: - server_message.type = WSAPI_ServerMessage::Type::MouseDown; - server_message.mouse.position = static_cast(message).position(); - server_message.mouse.button = to_api(static_cast(message).button()); - server_message.mouse.buttons = static_cast(message).buttons(); - server_message.mouse.modifiers = static_cast(message).modifiers(); - break; - case WSMessage::MouseUp: - server_message.type = WSAPI_ServerMessage::Type::MouseUp; - server_message.mouse.position = static_cast(message).position(); - server_message.mouse.button = to_api(static_cast(message).button()); - server_message.mouse.buttons = static_cast(message).buttons(); - server_message.mouse.modifiers = static_cast(message).modifiers(); - break; case WSMessage::WindowEntered: server_message.type = WSAPI_ServerMessage::Type::WindowEntered; break; diff --git a/Servers/WindowServer/WSWindow.h b/Servers/WindowServer/WSWindow.h index ff6ef6b5c84..68a02f4f715 100644 --- a/Servers/WindowServer/WSWindow.h +++ b/Servers/WindowServer/WSWindow.h @@ -9,6 +9,7 @@ class WSClientConnection; class WSMenu; +class WSMouseEvent; class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode { public: @@ -78,7 +79,8 @@ public: GraphicsBitmap* last_backing_store() { return m_last_backing_store.ptr(); } void set_global_cursor_tracking_enabled(bool); - bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; } + void set_automatic_cursor_tracking_enabled(bool enabled) { m_automatic_cursor_tracking_enabled = enabled; } + bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled || m_automatic_cursor_tracking_enabled; } bool has_alpha_channel() const { return m_has_alpha_channel; } void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; } @@ -104,12 +106,15 @@ public: WSWindow* m_prev { nullptr }; private: + void handle_mouse_event(const WSMouseEvent&); + WSClientConnection* m_client { nullptr }; WSMessageReceiver* m_internal_owner { nullptr }; String m_title; Rect m_rect; WSWindowType m_type { WSWindowType::Normal }; bool m_global_cursor_tracking_enabled { false }; + bool m_automatic_cursor_tracking_enabled { false }; bool m_visible { true }; bool m_has_alpha_channel { false }; bool m_has_painted_since_last_resize { false }; diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index 8a68f967bcb..f27e241c61b 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -660,7 +660,7 @@ void WSWindowManager::start_window_resize(WSWindow& window, WSMouseEvent& event) invalidate(window); } -bool WSWindowManager::process_ongoing_window_drag(WSMouseEvent& event, WSWindow*& event_window) +bool WSWindowManager::process_ongoing_window_drag(WSMouseEvent& event, WSWindow*&) { if (!m_drag_window) return false; @@ -687,7 +687,7 @@ bool WSWindowManager::process_ongoing_window_drag(WSMouseEvent& event, WSWindow* return false; } -bool WSWindowManager::process_ongoing_window_resize(WSMouseEvent& event, WSWindow*& event_window) +bool WSWindowManager::process_ongoing_window_resize(WSMouseEvent& event, WSWindow*&) { if (!m_resize_window) return false;