summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.h1
-rw-r--r--Kernel/ProcessGUI.cpp13
-rw-r--r--Kernel/Syscall.cpp2
-rw-r--r--Kernel/Syscall.h1
-rw-r--r--LibC/gui.cpp6
-rw-r--r--LibC/gui.h1
-rw-r--r--LibGUI/GButton.cpp28
-rw-r--r--LibGUI/GButton.h2
-rw-r--r--LibGUI/GWidget.cpp16
-rw-r--r--LibGUI/GWidget.h3
-rw-r--r--LibGUI/GWindow.cpp15
-rw-r--r--LibGUI/GWindow.h6
-rw-r--r--WindowServer/WSWindow.cpp6
-rw-r--r--WindowServer/WSWindow.h4
-rw-r--r--WindowServer/WSWindowManager.cpp8
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);