summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-02-13 21:43:32 +0100
committerAndreas Kling <kling@serenityos.org>2020-02-13 21:43:32 +0100
commit3ce80bec97551bbcd850ce3e457fca1c06c48439 (patch)
tree5723f47ec0204e8b891d14ec67f272899fd4558f
parent7590270e138b38960d6f71f1c120808270bf3794 (diff)
downloadserenity-3ce80bec97551bbcd850ce3e457fca1c06c48439.zip
WindowServer+LibGUI: Add a "drag move" event
This allows windows/widgets to learn when something is being dragged over them. They can then repaint themselves somehow to indicate that they are willing to accept a drop. Currently this is piggybacking somewhat on the mouse event mechanism in WindowServer. I'm not sure that's the best design but it seemed easier to do it this way right now.
-rw-r--r--Libraries/LibGUI/Event.h18
-rw-r--r--Libraries/LibGUI/Widget.cpp12
-rw-r--r--Libraries/LibGUI/Widget.h1
-rw-r--r--Libraries/LibGUI/Window.cpp10
-rw-r--r--Libraries/LibGUI/WindowServerConnection.cpp12
-rw-r--r--Servers/WindowServer/Event.h7
-rw-r--r--Servers/WindowServer/Window.cpp2
-rw-r--r--Servers/WindowServer/WindowClient.ipc2
-rw-r--r--Servers/WindowServer/WindowManager.cpp15
9 files changed, 71 insertions, 8 deletions
diff --git a/Libraries/LibGUI/Event.h b/Libraries/LibGUI/Event.h
index 7b6b472176..c518a694a1 100644
--- a/Libraries/LibGUI/Event.h
+++ b/Libraries/LibGUI/Event.h
@@ -60,6 +60,7 @@ public:
WindowCloseRequest,
ContextMenu,
EnabledChange,
+ DragMove,
Drop,
__Begin_WM_Events,
@@ -306,6 +307,23 @@ private:
int m_wheel_delta { 0 };
};
+class DragEvent final : public Event {
+public:
+ DragEvent(Type type, const Gfx::Point& position, const String& data_type)
+ : Event(type)
+ , m_position(position)
+ , m_data_type(data_type)
+ {
+ }
+
+ const Gfx::Point& position() const { return m_position; }
+ const String& data_type() const { return m_data_type; }
+
+private:
+ Gfx::Point m_position;
+ String m_data_type;
+};
+
class DropEvent final : public Event {
public:
DropEvent(const Gfx::Point& position, const String& text, const String& data_type, const String& data)
diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp
index b4b2ccc084..0997b52773 100644
--- a/Libraries/LibGUI/Widget.cpp
+++ b/Libraries/LibGUI/Widget.cpp
@@ -26,8 +26,6 @@
#include <AK/Assertions.h>
#include <AK/JsonObject.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Palette.h>
#include <LibGUI/Action.h>
#include <LibGUI/Application.h>
#include <LibGUI/Button.h>
@@ -46,6 +44,8 @@
#include <LibGUI/Widget.h>
#include <LibGUI/Window.h>
#include <LibGUI/WindowServerConnection.h>
+#include <LibGfx/Bitmap.h>
+#include <LibGfx/Palette.h>
#include <unistd.h>
namespace GUI {
@@ -182,6 +182,8 @@ void Widget::event(Core::Event& event)
return handle_mouseup_event(static_cast<MouseEvent&>(event));
case Event::MouseWheel:
return mousewheel_event(static_cast<MouseEvent&>(event));
+ case Event::DragMove:
+ return drag_move_event(static_cast<DragEvent&>(event));
case Event::Drop:
return drop_event(static_cast<DropEvent&>(event));
case Event::Enter:
@@ -379,6 +381,12 @@ void Widget::change_event(Event&)
{
}
+void Widget::drag_move_event(DragEvent& event)
+{
+ dbg() << class_name() << "{" << this << "} DRAG MOVE position: " << event.position() << ", data_type: '" << event.data_type() << "'";
+ event.ignore();
+}
+
void Widget::drop_event(DropEvent& event)
{
dbg() << class_name() << "{" << this << "} DROP position: " << event.position() << ", text: '" << event.text() << "'";
diff --git a/Libraries/LibGUI/Widget.h b/Libraries/LibGUI/Widget.h
index 9ecb8fe8c1..d294673dca 100644
--- a/Libraries/LibGUI/Widget.h
+++ b/Libraries/LibGUI/Widget.h
@@ -303,6 +303,7 @@ protected:
virtual void leave_event(Core::Event&);
virtual void child_event(Core::ChildEvent&) override;
virtual void change_event(Event&);
+ virtual void drag_move_event(DragEvent&);
virtual void drop_event(DropEvent&);
private:
diff --git a/Libraries/LibGUI/Window.cpp b/Libraries/LibGUI/Window.cpp
index c93e9d00e8..a0b5dc87c2 100644
--- a/Libraries/LibGUI/Window.cpp
+++ b/Libraries/LibGUI/Window.cpp
@@ -319,6 +319,16 @@ void Window::event(Core::Event& event)
if (event.type() > Event::__Begin_WM_Events && event.type() < Event::__End_WM_Events)
return wm_event(static_cast<WMEvent&>(event));
+ if (event.type() == Event::DragMove) {
+ if (!m_main_widget)
+ return;
+ auto& drag_event = static_cast<DragEvent&>(event);
+ auto result = m_main_widget->hit_test(drag_event.position());
+ auto local_event = make<DragEvent>(static_cast<Event::Type>(drag_event.type()), result.local_position, drag_event.data_type());
+ ASSERT(result.widget);
+ return result.widget->dispatch_event(*local_event, this);
+ }
+
Core::Object::event(event);
}
diff --git a/Libraries/LibGUI/WindowServerConnection.cpp b/Libraries/LibGUI/WindowServerConnection.cpp
index 3ea6a6a572..bfcc000f2e 100644
--- a/Libraries/LibGUI/WindowServerConnection.cpp
+++ b/Libraries/LibGUI/WindowServerConnection.cpp
@@ -24,8 +24,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <LibGfx/Palette.h>
-#include <LibGfx/SystemTheme.h>
#include <LibGUI/Action.h>
#include <LibGUI/Application.h>
#include <LibGUI/Clipboard.h>
@@ -36,6 +34,8 @@
#include <LibGUI/Widget.h>
#include <LibGUI/Window.h>
#include <LibGUI/WindowServerConnection.h>
+#include <LibGfx/Palette.h>
+#include <LibGfx/SystemTheme.h>
//#define GEVENTLOOP_DEBUG
@@ -217,8 +217,12 @@ void WindowServerConnection::handle(const Messages::WindowClient::MouseMove& mes
dbgprintf("WID=%d MouseMove %d,%d,%d\n", message.window_id(), message.mouse_position().x(), message.mouse_position().y(), message.wheel_delta();
#endif
- if (auto* window = Window::from_window_id(message.window_id()))
- Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseMove, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta()));
+ if (auto* window = Window::from_window_id(message.window_id())) {
+ if (message.is_drag())
+ Core::EventLoop::current().post_event(*window, make<DragEvent>(Event::DragMove, message.mouse_position(), message.drag_data_type()));
+ else
+ Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseMove, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta()));
+ }
}
void WindowServerConnection::handle(const Messages::WindowClient::MouseDoubleClick& message)
diff --git a/Servers/WindowServer/Event.h b/Servers/WindowServer/Event.h
index 8b7bd97d13..781f2df903 100644
--- a/Servers/WindowServer/Event.h
+++ b/Servers/WindowServer/Event.h
@@ -117,6 +117,11 @@ public:
unsigned buttons() const { return m_buttons; }
unsigned modifiers() const { return m_modifiers; }
int wheel_delta() const { return m_wheel_delta; }
+ bool is_drag() const { return m_drag; }
+ const String& drag_data_type() const { return m_drag_data_type; }
+
+ void set_drag(bool b) { m_drag = b; }
+ void set_drag_data_type(const String& drag_data_type) { m_drag_data_type = drag_data_type; }
MouseEvent translated(const Gfx::Point& delta) const { return MouseEvent((Type)type(), m_position.translated(delta), m_buttons, m_button, m_modifiers, m_wheel_delta); }
@@ -126,6 +131,8 @@ private:
MouseButton m_button { MouseButton::None };
unsigned m_modifiers { 0 };
int m_wheel_delta { 0 };
+ bool m_drag { false };
+ String m_drag_data_type;
};
class ResizeEvent final : public Event {
diff --git a/Servers/WindowServer/Window.cpp b/Servers/WindowServer/Window.cpp
index a25cc5aa0c..a322d72cdd 100644
--- a/Servers/WindowServer/Window.cpp
+++ b/Servers/WindowServer/Window.cpp
@@ -114,7 +114,7 @@ void Window::handle_mouse_event(const MouseEvent& event)
switch (event.type()) {
case Event::MouseMove:
- m_client->post_message(Messages::WindowClient::MouseMove(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
+ m_client->post_message(Messages::WindowClient::MouseMove(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta(), event.is_drag(), event.drag_data_type()));
break;
case Event::MouseDown:
m_client->post_message(Messages::WindowClient::MouseDown(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
diff --git a/Servers/WindowServer/WindowClient.ipc b/Servers/WindowServer/WindowClient.ipc
index e1b8e8398a..4e3c077a7d 100644
--- a/Servers/WindowServer/WindowClient.ipc
+++ b/Servers/WindowServer/WindowClient.ipc
@@ -1,7 +1,7 @@
endpoint WindowClient = 4
{
Paint(i32 window_id, Gfx::Size window_size, Vector<Gfx::Rect> rects) =|
- MouseMove(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
+ MouseMove(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, String drag_data_type) =|
MouseDown(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
MouseDoubleClick(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
MouseUp(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
diff --git a/Servers/WindowServer/WindowManager.cpp b/Servers/WindowServer/WindowManager.cpp
index 2a7d7383b1..689cb5734c 100644
--- a/Servers/WindowServer/WindowManager.cpp
+++ b/Servers/WindowServer/WindowManager.cpp
@@ -594,6 +594,21 @@ bool WindowManager::process_ongoing_drag(MouseEvent& event, Window*& hovered_win
{
if (!m_dnd_client)
return false;
+
+ if (event.type() == Event::MouseMove) {
+ // We didn't let go of the drag yet, see if we should send some drag move events..
+ for_each_visible_window_from_front_to_back([&](Window& window) {
+ if (!window.rect().contains(event.position()))
+ return IterationDecision::Continue;
+ hovered_window = &window;
+ auto translated_event = event.translated(-window.position());
+ translated_event.set_drag(true);
+ translated_event.set_drag_data_type(m_dnd_data_type);
+ deliver_mouse_event(window, translated_event);
+ return IterationDecision::Break;
+ });
+ }
+
if (!(event.type() == Event::MouseUp && event.button() == MouseButton::Left))
return true;