diff --git a/Libraries/LibGUI/GDirectoryModel.cpp b/Libraries/LibGUI/GDirectoryModel.cpp index 480fda225aa..e4a6cda8807 100644 --- a/Libraries/LibGUI/GDirectoryModel.cpp +++ b/Libraries/LibGUI/GDirectoryModel.cpp @@ -247,6 +247,15 @@ GVariant GDirectoryModel::data(const GModelIndex& index, Role role) const ASSERT(index.column() == Column::Name); return entry.full_path(*this); } + if (role == Role::DragData) { + if (index.column() == Column::Name) { + StringBuilder builder; + builder.append("file://"); + builder.append(entry.full_path(*this)); + return builder.to_string(); + } + return {}; + } if (role == Role::Sort) { switch (index.column()) { case Column::Icon: diff --git a/Libraries/LibGUI/GDragOperation.cpp b/Libraries/LibGUI/GDragOperation.cpp index 729e7269f8f..67b94e53a38 100644 --- a/Libraries/LibGUI/GDragOperation.cpp +++ b/Libraries/LibGUI/GDragOperation.cpp @@ -28,7 +28,7 @@ GDragOperation::Outcome GDragOperation::exec() bitmap_size = shared_bitmap->size(); } - auto response = GWindowServerConnection::the().send_sync(m_text, bitmap_id, bitmap_size); + auto response = GWindowServerConnection::the().send_sync(m_text, m_data_type, m_data, bitmap_id, bitmap_size); if (!response->started()) { m_outcome = Outcome::Cancelled; return m_outcome; diff --git a/Libraries/LibGUI/GDragOperation.h b/Libraries/LibGUI/GDragOperation.h index a4f87c15b40..d0cf3266b3f 100644 --- a/Libraries/LibGUI/GDragOperation.h +++ b/Libraries/LibGUI/GDragOperation.h @@ -19,6 +19,11 @@ public: void set_text(const String& text) { m_text = text; } void set_bitmap(const GraphicsBitmap* bitmap) { m_bitmap = bitmap; } + void set_data(const String& data_type, const String& data) + { + m_data_type = data_type; + m_data = data; + } Outcome exec(); Outcome outcome() const { return m_outcome; } @@ -35,5 +40,7 @@ private: OwnPtr m_event_loop; Outcome m_outcome { Outcome::None }; String m_text; + String m_data_type; + String m_data; RefPtr m_bitmap; }; diff --git a/Libraries/LibGUI/GEvent.h b/Libraries/LibGUI/GEvent.h index 66171c0e31f..40f0395e261 100644 --- a/Libraries/LibGUI/GEvent.h +++ b/Libraries/LibGUI/GEvent.h @@ -282,17 +282,23 @@ private: class GDropEvent final : public GEvent { public: - GDropEvent(const Point& position, const String& text) + GDropEvent(const Point& position, const String& text, const String& data_type, const String& data) : GEvent(GEvent::Drop) , m_position(position) , m_text(text) + , m_data_type(data_type) + , m_data(data) { } const Point& position() const { return m_position; } const String& text() const { return m_text; } + const String& data_type() const { return m_data_type; } + const String& data() const { return m_data; } private: Point m_position; String m_text; + String m_data_type; + String m_data; }; diff --git a/Libraries/LibGUI/GItemView.cpp b/Libraries/LibGUI/GItemView.cpp index 599db7e7732..3c880d220ef 100644 --- a/Libraries/LibGUI/GItemView.cpp +++ b/Libraries/LibGUI/GItemView.cpp @@ -115,11 +115,16 @@ void GItemView::mousemove_event(GMouseEvent& event) RefPtr bitmap; - StringBuilder builder; + StringBuilder text_builder; + StringBuilder data_builder; selection().for_each_index([&](auto& index) { - auto data = model()->data(index); - builder.append(data.to_string()); - builder.append(" "); + auto text_data = model()->data(index); + text_builder.append(text_data.to_string()); + text_builder.append(" "); + + auto drag_data = model()->data(index, GModel::Role::DragData); + data_builder.append(drag_data.to_string()); + data_builder.append('\n'); if (!bitmap) { GVariant icon_data = model()->data(index, GModel::Role::Icon); @@ -128,8 +133,9 @@ void GItemView::mousemove_event(GMouseEvent& event) } }); - drag_operation->set_text(builder.to_string()); + drag_operation->set_text(text_builder.to_string()); drag_operation->set_bitmap(bitmap); + drag_operation->set_data("url-list", data_builder.to_string()); auto outcome = drag_operation->exec(); switch (outcome) { case GDragOperation::Outcome::Accepted: diff --git a/Libraries/LibGUI/GModel.h b/Libraries/LibGUI/GModel.h index 2b1ccb24d66..07edaee49cd 100644 --- a/Libraries/LibGUI/GModel.h +++ b/Libraries/LibGUI/GModel.h @@ -36,6 +36,7 @@ public: BackgroundColor, Icon, Font, + DragData, }; virtual ~GModel(); diff --git a/Libraries/LibGUI/GWindow.cpp b/Libraries/LibGUI/GWindow.cpp index 822c877ad69..5f5c69240fc 100644 --- a/Libraries/LibGUI/GWindow.cpp +++ b/Libraries/LibGUI/GWindow.cpp @@ -159,7 +159,7 @@ void GWindow::event(CEvent& event) if (!m_main_widget) return; auto result = m_main_widget->hit_test(drop_event.position()); - auto local_event = make(result.local_position, drop_event.text()); + auto local_event = make(result.local_position, drop_event.text(), drop_event.data_type(), drop_event.data()); ASSERT(result.widget); return result.widget->dispatch_event(*local_event, this); } diff --git a/Libraries/LibGUI/GWindowServerConnection.cpp b/Libraries/LibGUI/GWindowServerConnection.cpp index 4867d84954d..8e2daca6e99 100644 --- a/Libraries/LibGUI/GWindowServerConnection.cpp +++ b/Libraries/LibGUI/GWindowServerConnection.cpp @@ -266,7 +266,7 @@ void GWindowServerConnection::handle(const WindowClient::AsyncSetWallpaperFinish void GWindowServerConnection::handle(const WindowClient::DragDropped& message) { if (auto* window = GWindow::from_window_id(message.window_id())) - CEventLoop::current().post_event(*window, make(message.mouse_position(), message.text())); + CEventLoop::current().post_event(*window, make(message.mouse_position(), message.text(), message.data_type(), message.data())); } void GWindowServerConnection::handle(const WindowClient::DragAccepted&) diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index 8de0727d243..fc507b4613f 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -651,6 +651,6 @@ OwnPtr WSClientConnection::handle(const WindowS bitmap = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *shared_buffer, message.bitmap_size()); } - wm.start_dnd_drag(*this, message.text(), bitmap); + wm.start_dnd_drag(*this, message.text(), bitmap, message.data_type(), message.data()); return make(true); } diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index 99498344a84..812207eefd4 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -649,7 +649,7 @@ bool WSWindowManager::process_ongoing_drag(WSMouseEvent& event, WSWindow*& hover m_dnd_client->post_message(WindowClient::DragAccepted()); if (hovered_window->client()) { auto translated_event = event.translated(-hovered_window->position()); - hovered_window->client()->post_message(WindowClient::DragDropped(hovered_window->window_id(), translated_event.position(), m_dnd_text)); + hovered_window->client()->post_message(WindowClient::DragDropped(hovered_window->window_id(), translated_event.position(), m_dnd_text, m_dnd_data_type, m_dnd_data)); } } else { m_dnd_client->post_message(WindowClient::DragCancelled()); @@ -1190,12 +1190,14 @@ WSMenu* WSWindowManager::find_internal_menu_by_id(int menu_id) return nullptr; } -void WSWindowManager::start_dnd_drag(WSClientConnection& client, const String& text, GraphicsBitmap* bitmap) +void WSWindowManager::start_dnd_drag(WSClientConnection& client, const String& text, GraphicsBitmap* bitmap, const String& data_type, const String& data) { ASSERT(!m_dnd_client); m_dnd_client = client.make_weak_ptr(); m_dnd_text = text; m_dnd_bitmap = bitmap; + m_dnd_data_type = data_type; + m_dnd_data = data; WSCompositor::the().invalidate_cursor(); } diff --git a/Servers/WindowServer/WSWindowManager.h b/Servers/WindowServer/WSWindowManager.h index b7c6531a94f..6faaa6699e4 100644 --- a/Servers/WindowServer/WSWindowManager.h +++ b/Servers/WindowServer/WSWindowManager.h @@ -68,10 +68,12 @@ public: WSClientConnection* dnd_client() { return m_dnd_client.ptr(); } const String& dnd_text() const { return m_dnd_text; } + const String& dnd_data_type() const { return m_dnd_data_type; } + const String& dnd_data() const { return m_dnd_data; } const GraphicsBitmap* dnd_bitmap() const { return m_dnd_bitmap; } Rect dnd_rect() const; - void start_dnd_drag(WSClientConnection&, const String& text, GraphicsBitmap*); + void start_dnd_drag(WSClientConnection&, const String& text, GraphicsBitmap*, const String& data_type, const String& data); void end_dnd_drag(); WSWindow* active_window() { return m_active_window.ptr(); } @@ -283,6 +285,8 @@ private: WeakPtr m_dnd_client; String m_dnd_text; + String m_dnd_data_type; + String m_dnd_data; RefPtr m_dnd_bitmap; }; diff --git a/Servers/WindowServer/WindowClient.ipc b/Servers/WindowServer/WindowClient.ipc index 245af0ba792..8006d3d814c 100644 --- a/Servers/WindowServer/WindowClient.ipc +++ b/Servers/WindowServer/WindowClient.ipc @@ -31,5 +31,5 @@ endpoint WindowClient = 4 DragAccepted() =| DragCancelled() =| - DragDropped(i32 window_id, Point mouse_position, String text) =| + DragDropped(i32 window_id, Point mouse_position, String text, String data_type, String data) =| } diff --git a/Servers/WindowServer/WindowServer.ipc b/Servers/WindowServer/WindowServer.ipc index 58c3da272b6..64988712f8a 100644 --- a/Servers/WindowServer/WindowServer.ipc +++ b/Servers/WindowServer/WindowServer.ipc @@ -67,5 +67,5 @@ endpoint WindowServer = 2 GetWallpaper() => (String path) SetWindowOverrideCursor(i32 window_id, i32 cursor_type) => () - StartDrag(String text, i32 bitmap_id, Size bitmap_size) => (bool started) + StartDrag(String text, String data_type, String data, i32 bitmap_id, Size bitmap_size) => (bool started) }