diff options
-rw-r--r-- | Kernel/Process.h | 1 | ||||
-rw-r--r-- | Kernel/ProcessGUI.cpp | 13 | ||||
-rw-r--r-- | Kernel/Syscall.cpp | 2 | ||||
-rw-r--r-- | Kernel/Syscall.h | 1 | ||||
-rw-r--r-- | LibC/gui.cpp | 6 | ||||
-rw-r--r-- | LibC/gui.h | 1 | ||||
-rw-r--r-- | LibGUI/GButton.cpp | 28 | ||||
-rw-r--r-- | LibGUI/GButton.h | 2 | ||||
-rw-r--r-- | LibGUI/GWidget.cpp | 16 | ||||
-rw-r--r-- | LibGUI/GWidget.h | 3 | ||||
-rw-r--r-- | LibGUI/GWindow.cpp | 15 | ||||
-rw-r--r-- | LibGUI/GWindow.h | 6 | ||||
-rw-r--r-- | WindowServer/WSWindow.cpp | 6 | ||||
-rw-r--r-- | WindowServer/WSWindow.h | 4 | ||||
-rw-r--r-- | WindowServer/WSWindowManager.cpp | 8 |
15 files changed, 105 insertions, 7 deletions
diff --git a/Kernel/Process.h b/Kernel/Process.h index 2d42952bcc..0cd58475b6 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -206,6 +206,7 @@ public: int gui$set_window_title(int window_id, const char* title, size_t size); int gui$get_window_rect(int window_id, GUI_Rect*); int gui$set_window_rect(int window_id, const GUI_Rect*); + int gui$set_global_cursor_tracking_enabled(int window_id, bool enabled); DisplayInfo get_display_info(); diff --git a/Kernel/ProcessGUI.cpp b/Kernel/ProcessGUI.cpp index adb74b06fb..f5aee91423 100644 --- a/Kernel/ProcessGUI.cpp +++ b/Kernel/ProcessGUI.cpp @@ -244,3 +244,16 @@ int Process::gui$set_window_rect(int window_id, const GUI_Rect* rect) WSMessageLoop::the().server_process().request_wakeup(); return 0; } + +int Process::gui$set_global_cursor_tracking_enabled(int window_id, bool enabled) +{ + if (window_id < 0) + return -EINVAL; + auto it = m_windows.find(window_id); + if (it == m_windows.end()) + return -EBADWINDOW; + auto& window = *(*it).value; + WSWindowLocker locker(window); + window.set_global_cursor_tracking_enabled(enabled); + return 0; +} diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index abb350603c..3850117bd3 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -217,6 +217,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, return current->sys$read_tsc((dword*)arg1, (dword*)arg2); case Syscall::SC_gui_notify_paint_finished: return current->gui$notify_paint_finished((int)arg1, (const GUI_Rect*)arg2); + case Syscall::SC_gui_set_global_cursor_tracking_enabled: + return current->gui$set_global_cursor_tracking_enabled((int)arg1, (bool)arg2); default: kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 08c051a1b6..1ef6138015 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -81,6 +81,7 @@ __ENUMERATE_SYSCALL(gui_get_window_rect) \ __ENUMERATE_SYSCALL(gui_set_window_rect) \ __ENUMERATE_SYSCALL(gui_notify_paint_finished) \ + __ENUMERATE_SYSCALL(gui_set_global_cursor_tracking_enabled) \ #ifdef SERENITY diff --git a/LibC/gui.cpp b/LibC/gui.cpp index 641ec3ffdc..6b0516b252 100644 --- a/LibC/gui.cpp +++ b/LibC/gui.cpp @@ -56,3 +56,9 @@ int gui_notify_paint_finished(int window_id, const GUI_Rect* rect) int rc = syscall(SC_gui_notify_paint_finished, window_id, rect); __RETURN_WITH_ERRNO(rc, rc, -1); } + +int gui_set_global_cursor_tracking_enabled(int window_id, bool enabled) +{ + int rc = syscall(SC_gui_set_global_cursor_tracking_enabled, window_id, enabled); + __RETURN_WITH_ERRNO(rc, rc, -1); +} diff --git a/LibC/gui.h b/LibC/gui.h index de4e62f7c9..c486adcd99 100644 --- a/LibC/gui.h +++ b/LibC/gui.h @@ -14,6 +14,7 @@ int gui_get_window_title(int window_id, char*, size_t); int gui_set_window_title(int window_id, const char*, size_t); int gui_get_window_rect(int window_id, GUI_Rect*); int gui_set_window_rect(int window_id, const GUI_Rect*); +int gui_set_global_cursor_tracking_enabled(int window_id, bool); __END_DECLS diff --git a/LibGUI/GButton.cpp b/LibGUI/GButton.cpp index cee19019d0..3fd616da0f 100644 --- a/LibGUI/GButton.cpp +++ b/LibGUI/GButton.cpp @@ -65,12 +65,24 @@ void GButton::paint_event(GPaintEvent&) } } +void GButton::mousemove_event(GMouseEvent& event) +{ + if (m_tracking_cursor) { + bool being_pressed = rect().contains(event.position()); + if (being_pressed != m_being_pressed) { + m_being_pressed = being_pressed; + update(); + } + } + GWidget::mousemove_event(event); +} + void GButton::mousedown_event(GMouseEvent& event) { dbgprintf("Button::mouseDownEvent: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button()); - m_being_pressed = true; - + m_tracking_cursor = true; + set_global_cursor_tracking(true); update(); GWidget::mousedown_event(event); } @@ -78,13 +90,15 @@ void GButton::mousedown_event(GMouseEvent& event) void GButton::mouseup_event(GMouseEvent& event) { dbgprintf("Button::mouseUpEvent: x=%d, y=%d, button=%u\n", event.x(), event.y(), (unsigned)event.button()); - + bool was_being_pressed = m_being_pressed; m_being_pressed = false; - + m_tracking_cursor = false; + set_global_cursor_tracking(false); update(); GWidget::mouseup_event(event); - - if (on_click) - on_click(*this); + if (was_being_pressed) { + if (on_click) + on_click(*this); + } } diff --git a/LibGUI/GButton.h b/LibGUI/GButton.h index 606311aac0..b5164ca26e 100644 --- a/LibGUI/GButton.h +++ b/LibGUI/GButton.h @@ -18,10 +18,12 @@ private: virtual void paint_event(GPaintEvent&) override; virtual void mousedown_event(GMouseEvent&) override; virtual void mouseup_event(GMouseEvent&) override; + virtual void mousemove_event(GMouseEvent&) override; virtual const char* class_name() const override { return "GButton"; } String m_caption; bool m_being_pressed { false }; + bool m_tracking_cursor { false }; }; diff --git a/LibGUI/GWidget.cpp b/LibGUI/GWidget.cpp index e2b77e33ec..8695fcda74 100644 --- a/LibGUI/GWidget.cpp +++ b/LibGUI/GWidget.cpp @@ -170,3 +170,19 @@ void GWidget::set_font(RetainPtr<Font>&& font) else m_font = move(font); } + +void GWidget::set_global_cursor_tracking(bool enabled) +{ + auto* win = window(); + if (!win) + return; + win->set_global_cursor_tracking_widget(enabled ? this : nullptr); +} + +bool GWidget::global_cursor_tracking() const +{ + auto* win = window(); + if (!win) + return false; + return win->global_cursor_tracking_widget() == this; +} diff --git a/LibGUI/GWidget.h b/LibGUI/GWidget.h index 15f3e1556c..afa10c370b 100644 --- a/LibGUI/GWidget.h +++ b/LibGUI/GWidget.h @@ -88,6 +88,9 @@ public: const Font& font() const { return *m_font; } void set_font(RetainPtr<Font>&&); + void set_global_cursor_tracking(bool); + bool global_cursor_tracking() const; + private: GWindow* m_window { nullptr }; diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index b6de4a7511..9aff94b40a 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -72,6 +72,13 @@ void GWindow::set_rect(const Rect& a_rect) void GWindow::event(GEvent& event) { if (event.is_mouse_event()) { + if (m_global_cursor_tracking_widget) { + // FIXME: This won't work for widgets-within-widgets. + auto& mouse_event = static_cast<GMouseEvent&>(event); + Point local_point { mouse_event.x() - m_global_cursor_tracking_widget->relative_rect().x(), mouse_event.y() - m_global_cursor_tracking_widget->relative_rect().y() }; + auto local_event = make<GMouseEvent>(event.type(), local_point, mouse_event.buttons(), mouse_event.button()); + m_global_cursor_tracking_widget->event(*local_event); + } if (!m_main_widget) return; auto& mouse_event = static_cast<GMouseEvent&>(event); @@ -158,3 +165,11 @@ void GWindow::set_focused_widget(GWidget* widget) m_focused_widget->update(); } } + +void GWindow::set_global_cursor_tracking_widget(GWidget* widget) +{ + if (widget == m_global_cursor_tracking_widget.ptr()) + return; + m_global_cursor_tracking_widget = widget ? widget->makeWeakPtr() : nullptr; + gui_set_global_cursor_tracking_enabled(m_window_id, widget != nullptr); +} diff --git a/LibGUI/GWindow.h b/LibGUI/GWindow.h index a958207f08..7a53e8a8db 100644 --- a/LibGUI/GWindow.h +++ b/LibGUI/GWindow.h @@ -4,6 +4,7 @@ #include <SharedGraphics/Rect.h> #include <SharedGraphics/GraphicsBitmap.h> #include <AK/AKString.h> +#include <AK/WeakPtr.h> class GWidget; @@ -48,11 +49,16 @@ public: void update(const Rect& = Rect()); + void set_global_cursor_tracking_widget(GWidget*); + 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(); } + private: RetainPtr<GraphicsBitmap> m_backing; int m_window_id { -1 }; bool m_is_active { false }; GWidget* m_main_widget { nullptr }; GWidget* m_focused_widget { nullptr }; + WeakPtr<GWidget> m_global_cursor_tracking_widget; }; diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp index ff2432def0..81a24ef20e 100644 --- a/WindowServer/WSWindow.cpp +++ b/WindowServer/WSWindow.cpp @@ -123,3 +123,9 @@ void WSWindow::on_message(WSMessage& message) m_process.gui_events().append(move(gui_event)); } } + +void WSWindow::set_global_cursor_tracking_enabled(bool enabled) +{ + dbgprintf("WSWindow{%p} global_cursor_tracking <- %u\n", enabled); + m_global_cursor_tracking_enabled = enabled; +} diff --git a/WindowServer/WSWindow.h b/WindowServer/WSWindow.h index e91845f02b..12a30da4b7 100644 --- a/WindowServer/WSWindow.h +++ b/WindowServer/WSWindow.h @@ -42,6 +42,9 @@ public: pid_t pid() const { return m_pid; } + void set_global_cursor_tracking_enabled(bool); + bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; } + // For InlineLinkedList. // FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that. WSWindow* m_next { nullptr }; @@ -52,6 +55,7 @@ private: String m_title; Rect m_rect; bool m_is_being_dragged { false }; + bool m_global_cursor_tracking_enabled { false }; RetainPtr<GraphicsBitmap> m_backing; Process& m_process; diff --git a/WindowServer/WSWindowManager.cpp b/WindowServer/WSWindowManager.cpp index bd9a69236e..4679b9afe9 100644 --- a/WindowServer/WSWindowManager.cpp +++ b/WindowServer/WSWindowManager.cpp @@ -288,6 +288,14 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event) } for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) { + if (!window->global_cursor_tracking()) + continue; + Point position { event.x() - window->rect().x(), event.y() - window->rect().y() }; + auto local_event = make<WSMouseEvent>(event.type(), position, event.buttons(), event.button()); + window->on_message(*local_event); + } + + for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) { if (title_bar_rect(window->rect()).contains(event.position())) { if (event.type() == WSMessage::MouseDown) { move_to_front(*window); |