From 67b91d51a75eb5231584f9ff74524942ec0f38ed Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 9 Jan 2021 11:01:41 +0100 Subject: [PATCH] WindowServer+LibGUI: Pass the set of mime types being dragged to client Previously the client would only learn the mime type of what was being dropped on it once the drop occurred. To enable more sophisticated filtering of drag & drop, we now pass along the list of mime types being dragged to the client with each MouseMove event. (Note that MouseMove is translated to the various Drag* events in LibGUI on the client side.) --- Libraries/LibGUI/Application.cpp | 4 ++-- Libraries/LibGUI/Application.h | 6 +++--- Libraries/LibGUI/Event.h | 8 ++++---- Libraries/LibGUI/FileSystemModel.cpp | 4 ++-- Libraries/LibGUI/FileSystemModel.h | 2 +- Libraries/LibGUI/IconView.cpp | 5 +---- Libraries/LibGUI/Model.cpp | 2 +- Libraries/LibGUI/Model.h | 2 +- Libraries/LibGUI/Widget.cpp | 4 +++- Libraries/LibGUI/Window.cpp | 4 ++-- Libraries/LibGUI/WindowServerConnection.cpp | 2 +- Services/WindowServer/Event.h | 9 +++++++-- Services/WindowServer/Screen.cpp | 2 ++ Services/WindowServer/Window.cpp | 2 +- Services/WindowServer/WindowClient.ipc | 2 +- 15 files changed, 32 insertions(+), 26 deletions(-) diff --git a/Libraries/LibGUI/Application.cpp b/Libraries/LibGUI/Application.cpp index 8aaae7026e3..fbd0c7260d3 100644 --- a/Libraries/LibGUI/Application.cpp +++ b/Libraries/LibGUI/Application.cpp @@ -261,7 +261,7 @@ void Application::set_pending_drop_widget(Widget* widget) m_pending_drop_widget->update(); } -void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoint& position, const String& mime_type) +void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoint& position, Vector mime_types) { if (widget == m_drag_hovered_widget) return; @@ -275,7 +275,7 @@ void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoi m_drag_hovered_widget = widget; if (m_drag_hovered_widget) { - DragEvent enter_event(Event::DragEnter, position, mime_type); + DragEvent enter_event(Event::DragEnter, position, move(mime_types)); enter_event.ignore(); m_drag_hovered_widget->dispatch_event(enter_event, m_drag_hovered_widget->window()); if (enter_event.is_accepted()) diff --git a/Libraries/LibGUI/Application.h b/Libraries/LibGUI/Application.h index ea073c17e87..4114ef631da 100644 --- a/Libraries/LibGUI/Application.h +++ b/Libraries/LibGUI/Application.h @@ -90,9 +90,9 @@ public: Widget* pending_drop_widget() { return m_pending_drop_widget.ptr(); } const Widget* pending_drop_widget() const { return m_pending_drop_widget.ptr(); } - void set_drag_hovered_widget(Badge, Widget* widget, const Gfx::IntPoint& position = {}, const String& mime_type = {}) + void set_drag_hovered_widget(Badge, Widget* widget, const Gfx::IntPoint& position = {}, Vector mime_types = {}) { - set_drag_hovered_widget_impl(widget, position, mime_type); + set_drag_hovered_widget_impl(widget, position, move(mime_types)); } void notify_drag_cancelled(Badge); @@ -102,7 +102,7 @@ private: void tooltip_show_timer_did_fire(); void tooltip_hide_timer_did_fire(); - void set_drag_hovered_widget_impl(Widget*, const Gfx::IntPoint& = {}, const String& = {}); + void set_drag_hovered_widget_impl(Widget*, const Gfx::IntPoint& = {}, Vector = {}); void set_pending_drop_widget(Widget*); OwnPtr m_event_loop; diff --git a/Libraries/LibGUI/Event.h b/Libraries/LibGUI/Event.h index 17ae0c65edc..ce60f00e12f 100644 --- a/Libraries/LibGUI/Event.h +++ b/Libraries/LibGUI/Event.h @@ -347,19 +347,19 @@ private: class DragEvent final : public Event { public: - DragEvent(Type type, const Gfx::IntPoint& position, const String& data_type) + DragEvent(Type type, const Gfx::IntPoint& position, Vector mime_types) : Event(type) , m_position(position) - , m_data_type(data_type) + , m_mime_types(move(mime_types)) { } const Gfx::IntPoint& position() const { return m_position; } - const String& data_type() const { return m_data_type; } + const Vector& mime_types() const { return m_mime_types; } private: Gfx::IntPoint m_position; - String m_data_type; + Vector m_mime_types; }; class DropEvent final : public Event { diff --git a/Libraries/LibGUI/FileSystemModel.cpp b/Libraries/LibGUI/FileSystemModel.cpp index 69b0fcb168d..f5ed18c6377 100644 --- a/Libraries/LibGUI/FileSystemModel.cpp +++ b/Libraries/LibGUI/FileSystemModel.cpp @@ -589,11 +589,11 @@ String FileSystemModel::column_name(int column) const ASSERT_NOT_REACHED(); } -bool FileSystemModel::accepts_drag(const ModelIndex& index, const StringView& data_type) +bool FileSystemModel::accepts_drag(const ModelIndex& index, const Vector& mime_types) { if (!index.is_valid()) return false; - if (data_type != "text/uri-list") + if (!mime_types.contains_slow("text/uri-list")) return false; auto& node = this->node(index); return node.is_directory(); diff --git a/Libraries/LibGUI/FileSystemModel.h b/Libraries/LibGUI/FileSystemModel.h index 203ae3cd98a..f2c0ea4e7be 100644 --- a/Libraries/LibGUI/FileSystemModel.h +++ b/Libraries/LibGUI/FileSystemModel.h @@ -147,7 +147,7 @@ public: virtual ModelIndex parent_index(const ModelIndex&) const override; virtual ModelIndex index(int row, int column = 0, const ModelIndex& parent = ModelIndex()) const override; virtual StringView drag_data_type() const override { return "text/uri-list"; } - virtual bool accepts_drag(const ModelIndex&, const StringView& data_type) override; + virtual bool accepts_drag(const ModelIndex&, const Vector& mime_types) override; virtual bool is_column_sortable(int column_index) const override { return column_index != Column::Icon; } virtual bool is_editable(const ModelIndex&) const override; virtual bool is_searchable() const override { return true; } diff --git a/Libraries/LibGUI/IconView.cpp b/Libraries/LibGUI/IconView.cpp index 340df616fb0..51c3801c0fd 100644 --- a/Libraries/LibGUI/IconView.cpp +++ b/Libraries/LibGUI/IconView.cpp @@ -270,10 +270,7 @@ void IconView::drag_move_event(DragEvent& event) auto index = index_at_event_position(event.position()); ModelIndex new_drop_candidate_index; if (index.is_valid()) { - bool acceptable = model()->accepts_drag(index, event.data_type()); -#ifdef DRAGDROP_DEBUG - dbg() << "Drag of type '" << event.data_type() << "' moving over " << index << ", acceptable: " << acceptable; -#endif + bool acceptable = model()->accepts_drag(index, event.mime_types()); if (acceptable) new_drop_candidate_index = index; } diff --git a/Libraries/LibGUI/Model.cpp b/Libraries/LibGUI/Model.cpp index 6f8b833f7dc..a1e4180a9bd 100644 --- a/Libraries/LibGUI/Model.cpp +++ b/Libraries/LibGUI/Model.cpp @@ -71,7 +71,7 @@ ModelIndex Model::index(int row, int column, const ModelIndex&) const return create_index(row, column); } -bool Model::accepts_drag(const ModelIndex&, const StringView&) +bool Model::accepts_drag(const ModelIndex&, const Vector&) { return false; } diff --git a/Libraries/LibGUI/Model.h b/Libraries/LibGUI/Model.h index de6defbb254..5402edcb312 100644 --- a/Libraries/LibGUI/Model.h +++ b/Libraries/LibGUI/Model.h @@ -82,7 +82,7 @@ public: virtual bool is_searchable() const { return false; } virtual void set_data(const ModelIndex&, const Variant&) { } virtual int tree_column() const { return 0; } - virtual bool accepts_drag(const ModelIndex&, const StringView& data_type); + virtual bool accepts_drag(const ModelIndex&, const Vector& mime_types); virtual Vector matches(const StringView&, unsigned = MatchesFlag::AllMatching, const ModelIndex& = ModelIndex()) { return {}; } virtual bool is_column_sortable([[maybe_unused]] int column_index) const { return true; } diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index 273d048f4a4..04e8249e695 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -510,7 +510,9 @@ void Widget::drag_move_event(DragEvent&) void Widget::drag_enter_event(DragEvent& event) { - dbgln("{} {:p} DRAG ENTER @ {}, {}", class_name(), this, event.position(), event.data_type()); + StringBuilder builder; + builder.join(',', event.mime_types()); + dbgln("{} {:p} DRAG ENTER @ {}, {}", class_name(), this, event.position(), builder.string_view()); } void Widget::drag_leave_event(Event&) diff --git a/Libraries/LibGUI/Window.cpp b/Libraries/LibGUI/Window.cpp index 0094175c848..ac4aa36001b 100644 --- a/Libraries/LibGUI/Window.cpp +++ b/Libraries/LibGUI/Window.cpp @@ -446,14 +446,14 @@ void Window::handle_drag_move_event(DragEvent& event) auto result = m_main_widget->hit_test(event.position()); ASSERT(result.widget); - Application::the()->set_drag_hovered_widget({}, result.widget, result.local_position, event.data_type()); + Application::the()->set_drag_hovered_widget({}, result.widget, result.local_position, event.mime_types()); // NOTE: Setting the drag hovered widget may have executed arbitrary code, so re-check that the widget is still there. if (!result.widget) return; if (result.widget->has_pending_drop()) { - DragEvent drag_move_event(static_cast(event.type()), result.local_position, event.data_type()); + DragEvent drag_move_event(static_cast(event.type()), result.local_position, event.mime_types()); result.widget->dispatch_event(drag_move_event, this); } } diff --git a/Libraries/LibGUI/WindowServerConnection.cpp b/Libraries/LibGUI/WindowServerConnection.cpp index bbd49d702cd..8250f134af5 100644 --- a/Libraries/LibGUI/WindowServerConnection.cpp +++ b/Libraries/LibGUI/WindowServerConnection.cpp @@ -246,7 +246,7 @@ void WindowServerConnection::handle(const Messages::WindowClient::MouseMove& mes { if (auto* window = Window::from_window_id(message.window_id())) { if (message.is_drag()) - Core::EventLoop::current().post_event(*window, make(Event::DragMove, message.mouse_position(), message.drag_data_type())); + Core::EventLoop::current().post_event(*window, make(Event::DragMove, message.mouse_position(), message.mime_types())); else Core::EventLoop::current().post_event(*window, make(Event::MouseMove, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta())); } diff --git a/Services/WindowServer/Event.h b/Services/WindowServer/Event.h index 3e9adf88304..e82df2d4c9f 100644 --- a/Services/WindowServer/Event.h +++ b/Services/WindowServer/Event.h @@ -126,7 +126,13 @@ public: 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; } + + Vector mime_types() const + { + if (!m_mime_data) + return {}; + return m_mime_data->formats(); + } void set_drag(bool b) { m_drag = b; } void set_mime_data(const Core::MimeData& mime_data) { m_mime_data = mime_data; } @@ -140,7 +146,6 @@ private: unsigned m_modifiers { 0 }; int m_wheel_delta { 0 }; bool m_drag { false }; - String m_drag_data_type; RefPtr m_mime_data; }; diff --git a/Services/WindowServer/Screen.cpp b/Services/WindowServer/Screen.cpp index f929586c50a..2d68c4890e3 100644 --- a/Services/WindowServer/Screen.cpp +++ b/Services/WindowServer/Screen.cpp @@ -162,6 +162,8 @@ void Screen::on_receive_mouse_data(const MousePacket& packet) post_mousedown_or_mouseup_if_needed(MouseButton::Forward); if (m_cursor_location != prev_location) { auto message = make(Event::MouseMove, m_cursor_location, buttons, MouseButton::None, m_modifiers); + if (WindowManager::the().dnd_client()) + message->set_mime_data(WindowManager::the().dnd_mime_data()); Core::EventLoop::current().post_event(WindowManager::the(), move(message)); } diff --git a/Services/WindowServer/Window.cpp b/Services/WindowServer/Window.cpp index b79684e79e5..1d0497c1c6c 100644 --- a/Services/WindowServer/Window.cpp +++ b/Services/WindowServer/Window.cpp @@ -182,7 +182,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(), event.is_drag(), event.drag_data_type())); + 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.mime_types())); 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/Services/WindowServer/WindowClient.ipc b/Services/WindowServer/WindowClient.ipc index a1ce1413a39..c6ac17b0220 100644 --- a/Services/WindowServer/WindowClient.ipc +++ b/Services/WindowServer/WindowClient.ipc @@ -1,7 +1,7 @@ endpoint WindowClient = 4 { Paint(i32 window_id, Gfx::IntSize window_size, Vector rects) =| - MouseMove(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, String drag_data_type) =| + MouseMove(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, Vector mime_types) =| MouseDown(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =| MouseDoubleClick(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =| MouseUp(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|