diff options
author | Andreas Kling <kling@serenityos.org> | 2020-02-13 21:43:32 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-02-13 21:43:32 +0100 |
commit | 3ce80bec97551bbcd850ce3e457fca1c06c48439 (patch) | |
tree | 5723f47ec0204e8b891d14ec67f272899fd4558f | |
parent | 7590270e138b38960d6f71f1c120808270bf3794 (diff) | |
download | serenity-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.h | 18 | ||||
-rw-r--r-- | Libraries/LibGUI/Widget.cpp | 12 | ||||
-rw-r--r-- | Libraries/LibGUI/Widget.h | 1 | ||||
-rw-r--r-- | Libraries/LibGUI/Window.cpp | 10 | ||||
-rw-r--r-- | Libraries/LibGUI/WindowServerConnection.cpp | 12 | ||||
-rw-r--r-- | Servers/WindowServer/Event.h | 7 | ||||
-rw-r--r-- | Servers/WindowServer/Window.cpp | 2 | ||||
-rw-r--r-- | Servers/WindowServer/WindowClient.ipc | 2 | ||||
-rw-r--r-- | Servers/WindowServer/WindowManager.cpp | 15 |
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; |