Sfoglia il codice sorgente

LibGUI+WindowServer: Make DragOperation hold a MimeData instance

...instead of maybe bitmap + a single mime type and its corresponding data.
This allows drag&drop operations to hold multiple different kinds of
data, and the views/applications to choose between those.
For instance, Spreadsheet can keep the structure of the dragged cells,
and still provide text-only data to be passed to different unrelated editors.
AnotherTest 4 anni fa
parent
commit
6d1e47e7dd

+ 6 - 0
Libraries/LibCore/MimeData.h

@@ -55,8 +55,14 @@ public:
     Vector<URL> urls() const;
     Vector<URL> urls() const;
     void set_urls(const Vector<URL>&);
     void set_urls(const Vector<URL>&);
 
 
+    const HashMap<String, ByteBuffer>& all_data() const { return m_data; }
+
 private:
 private:
     MimeData() { }
     MimeData() { }
+    explicit MimeData(const HashMap<String, ByteBuffer>& data)
+        : m_data(data)
+    {
+    }
 
 
     HashMap<String, ByteBuffer> m_data;
     HashMap<String, ByteBuffer> m_data;
 };
 };

+ 1 - 27
Libraries/LibGUI/AbstractView.cpp

@@ -291,33 +291,7 @@ void AbstractView::mousemove_event(MouseEvent& event)
     dbg() << "Initiate drag!";
     dbg() << "Initiate drag!";
     auto drag_operation = DragOperation::construct();
     auto drag_operation = DragOperation::construct();
 
 
-    RefPtr<Gfx::Bitmap> bitmap;
-
-    StringBuilder text_builder;
-    StringBuilder data_builder;
-    bool first = true;
-    m_selection.for_each_index([&](auto& index) {
-        auto text_data = index.data();
-        if (!first)
-            text_builder.append(", ");
-        text_builder.append(text_data.to_string());
-
-        auto drag_data = index.data(ModelRole::DragData);
-        data_builder.append(drag_data.to_string());
-        data_builder.append('\n');
-
-        first = false;
-
-        if (!bitmap) {
-            Variant icon_data = index.data(ModelRole::Icon);
-            if (icon_data.is_icon())
-                bitmap = icon_data.as_icon().bitmap_for_size(32);
-        }
-    });
-
-    drag_operation->set_text(text_builder.to_string());
-    drag_operation->set_bitmap(bitmap);
-    drag_operation->set_data(data_type, data_builder.to_string());
+    drag_operation->set_mime_data(m_model->mime_data(m_selection));
 
 
     auto outcome = drag_operation->exec();
     auto outcome = drag_operation->exec();
 
 

+ 31 - 3
Libraries/LibGUI/DragOperation.cpp

@@ -27,6 +27,7 @@
 #include <AK/Badge.h>
 #include <AK/Badge.h>
 #include <AK/SharedBuffer.h>
 #include <AK/SharedBuffer.h>
 #include <LibCore/EventLoop.h>
 #include <LibCore/EventLoop.h>
+#include <LibCore/MimeData.h>
 #include <LibGUI/DragOperation.h>
 #include <LibGUI/DragOperation.h>
 #include <LibGUI/WindowServerConnection.h>
 #include <LibGUI/WindowServerConnection.h>
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/Bitmap.h>
@@ -48,18 +49,25 @@ DragOperation::Outcome DragOperation::exec()
 {
 {
     ASSERT(!s_current_drag_operation);
     ASSERT(!s_current_drag_operation);
     ASSERT(!m_event_loop);
     ASSERT(!m_event_loop);
+    ASSERT(m_mime_data);
 
 
     int bitmap_id = -1;
     int bitmap_id = -1;
     Gfx::IntSize bitmap_size;
     Gfx::IntSize bitmap_size;
     RefPtr<Gfx::Bitmap> shared_bitmap;
     RefPtr<Gfx::Bitmap> shared_bitmap;
-    if (m_bitmap) {
-        shared_bitmap = m_bitmap->to_bitmap_backed_by_shared_buffer();
+    if (m_mime_data->has_format("image/x-raw-bitmap")) {
+        auto data = m_mime_data->data("image/x-raw-bitmap");
+        auto bitmap = Gfx::Bitmap::create_from_serialized_byte_buffer(move(data));
+        shared_bitmap = bitmap->to_bitmap_backed_by_shared_buffer();
         shared_bitmap->shared_buffer()->share_with(WindowServerConnection::the().server_pid());
         shared_bitmap->shared_buffer()->share_with(WindowServerConnection::the().server_pid());
         bitmap_id = shared_bitmap->shbuf_id();
         bitmap_id = shared_bitmap->shbuf_id();
         bitmap_size = shared_bitmap->size();
         bitmap_size = shared_bitmap->size();
     }
     }
 
 
-    auto response = WindowServerConnection::the().send_sync<Messages::WindowServer::StartDrag>(m_text, m_data_type, m_data, bitmap_id, bitmap_size);
+    auto response = WindowServerConnection::the().send_sync<Messages::WindowServer::StartDrag>(
+        m_mime_data->text(),
+        m_mime_data->all_data(),
+        bitmap_id, bitmap_size);
+
     if (!response->started()) {
     if (!response->started()) {
         m_outcome = Outcome::Cancelled;
         m_outcome = Outcome::Cancelled;
         return m_outcome;
         return m_outcome;
@@ -94,4 +102,24 @@ void DragOperation::notify_cancelled(Badge<WindowServerConnection>)
     s_current_drag_operation->done(Outcome::Cancelled);
     s_current_drag_operation->done(Outcome::Cancelled);
 }
 }
 
 
+void DragOperation::set_text(const String& text)
+{
+    if (!m_mime_data)
+        m_mime_data = Core::MimeData::construct();
+    m_mime_data->set_text(text);
+}
+void DragOperation::set_bitmap(const Gfx::Bitmap* bitmap)
+{
+    if (!m_mime_data)
+        m_mime_data = Core::MimeData::construct();
+    if (bitmap)
+        m_mime_data->set_data("image/x-raw-bitmap", bitmap->serialize_to_byte_buffer());
+}
+void DragOperation::set_data(const String& data_type, const String& data)
+{
+    if (!m_mime_data)
+        m_mime_data = Core::MimeData::construct();
+    m_mime_data->set_data(data_type, data.to_byte_buffer());
+}
+
 }
 }

+ 5 - 11
Libraries/LibGUI/DragOperation.h

@@ -44,13 +44,10 @@ public:
 
 
     virtual ~DragOperation() override;
     virtual ~DragOperation() override;
 
 
-    void set_text(const String& text) { m_text = text; }
-    void set_bitmap(const Gfx::Bitmap* bitmap) { m_bitmap = bitmap; }
-    void set_data(const String& data_type, const String& data)
-    {
-        m_data_type = data_type;
-        m_data = data;
-    }
+    void set_mime_data(RefPtr<Core::MimeData> mime_data) { m_mime_data = move(mime_data); }
+    void set_text(const String& text);
+    void set_bitmap(const Gfx::Bitmap* bitmap);
+    void set_data(const String& data_type, const String& data);
 
 
     Outcome exec();
     Outcome exec();
     Outcome outcome() const { return m_outcome; }
     Outcome outcome() const { return m_outcome; }
@@ -66,10 +63,7 @@ private:
 
 
     OwnPtr<Core::EventLoop> m_event_loop;
     OwnPtr<Core::EventLoop> m_event_loop;
     Outcome m_outcome { Outcome::None };
     Outcome m_outcome { Outcome::None };
-    String m_text;
-    String m_data_type;
-    String m_data;
-    RefPtr<Gfx::Bitmap> m_bitmap;
+    RefPtr<Core::MimeData> m_mime_data;
 };
 };
 
 
 }
 }

+ 1 - 1
Libraries/LibGUI/FileSystemModel.cpp

@@ -403,7 +403,7 @@ Variant FileSystemModel::data(const ModelIndex& index, ModelRole role) const
         return node.full_path();
         return node.full_path();
     }
     }
 
 
-    if (role == ModelRole::DragData) {
+    if (role == ModelRole::MimeData) {
         if (index.column() == Column::Name) {
         if (index.column() == Column::Name) {
             StringBuilder builder;
             StringBuilder builder;
             builder.append("file://");
             builder.append("file://");

+ 36 - 0
Libraries/LibGUI/Model.cpp

@@ -88,4 +88,40 @@ void Model::unregister_client(ModelClient& client)
     m_clients.remove(&client);
     m_clients.remove(&client);
 }
 }
 
 
+RefPtr<Core::MimeData> Model::mime_data(const ModelSelection& selection) const
+{
+    auto mime_data = Core::MimeData::construct();
+    RefPtr<Gfx::Bitmap> bitmap;
+
+    StringBuilder text_builder;
+    StringBuilder data_builder;
+    bool first = true;
+    selection.for_each_index([&](auto& index) {
+        auto text_data = index.data();
+        if (!first)
+            text_builder.append(", ");
+        text_builder.append(text_data.to_string());
+
+        if (!first)
+            data_builder.append('\n');
+        auto data = index.data(ModelRole::MimeData);
+        data_builder.append(data.to_string());
+
+        first = false;
+
+        if (!bitmap) {
+            Variant icon_data = index.data(ModelRole::Icon);
+            if (icon_data.is_icon())
+                bitmap = icon_data.as_icon().bitmap_for_size(32);
+        }
+    });
+
+    mime_data->set_data(drag_data_type(), data_builder.to_byte_buffer());
+    mime_data->set_text(text_builder.to_string());
+    if (bitmap)
+        mime_data->set_data("image/x-raw-bitmap", bitmap->serialize_to_byte_buffer());
+
+    return mime_data;
+}
+
 }
 }

+ 3 - 0
Libraries/LibGUI/Model.h

@@ -31,8 +31,10 @@
 #include <AK/HashTable.h>
 #include <AK/HashTable.h>
 #include <AK/RefCounted.h>
 #include <AK/RefCounted.h>
 #include <AK/String.h>
 #include <AK/String.h>
+#include <LibCore/MimeData.h>
 #include <LibGUI/ModelIndex.h>
 #include <LibGUI/ModelIndex.h>
 #include <LibGUI/ModelRole.h>
 #include <LibGUI/ModelRole.h>
+#include <LibGUI/ModelSelection.h>
 #include <LibGUI/Variant.h>
 #include <LibGUI/Variant.h>
 #include <LibGfx/Forward.h>
 #include <LibGfx/Forward.h>
 #include <LibGfx/TextAlignment.h>
 #include <LibGfx/TextAlignment.h>
@@ -93,6 +95,7 @@ public:
     }
     }
 
 
     virtual StringView drag_data_type() const { return {}; }
     virtual StringView drag_data_type() const { return {}; }
+    virtual RefPtr<Core::MimeData> mime_data(const ModelSelection&) const;
 
 
     void register_view(Badge<AbstractView>, AbstractView&);
     void register_view(Badge<AbstractView>, AbstractView&);
     void unregister_view(Badge<AbstractView>, AbstractView&);
     void unregister_view(Badge<AbstractView>, AbstractView&);

+ 1 - 1
Libraries/LibGUI/ModelRole.h

@@ -35,7 +35,7 @@ enum class ModelRole {
     BackgroundColor,
     BackgroundColor,
     Icon,
     Icon,
     Font,
     Font,
-    DragData,
+    MimeData,
     TextAlignment,
     TextAlignment,
     Search,
     Search,
     Custom = 0x100, // Applications are free to use roles above this number as they please
     Custom = 0x100, // Applications are free to use roles above this number as they please

+ 1 - 2
Libraries/LibGUI/WindowServerConnection.cpp

@@ -307,8 +307,7 @@ void WindowServerConnection::handle(const Messages::WindowClient::AsyncSetWallpa
 void WindowServerConnection::handle(const Messages::WindowClient::DragDropped& message)
 void WindowServerConnection::handle(const Messages::WindowClient::DragDropped& message)
 {
 {
     if (auto* window = Window::from_window_id(message.window_id())) {
     if (auto* window = Window::from_window_id(message.window_id())) {
-        auto mime_data = Core::MimeData::construct();
-        mime_data->set_data(message.data_type(), message.data().to_byte_buffer());
+        auto mime_data = Core::MimeData::construct(message.mime_data());
         Core::EventLoop::current().post_event(*window, make<DropEvent>(message.mouse_position(), message.text(), mime_data));
         Core::EventLoop::current().post_event(*window, make<DropEvent>(message.mouse_position(), message.text(), mime_data));
     }
     }
 }
 }

+ 1 - 1
Services/WindowServer/ClientConnection.cpp

@@ -755,7 +755,7 @@ OwnPtr<Messages::WindowServer::StartDragResponse> ClientConnection::handle(const
         bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *shared_buffer, message.bitmap_size());
         bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *shared_buffer, message.bitmap_size());
     }
     }
 
 
-    wm.start_dnd_drag(*this, message.text(), bitmap, message.data_type(), message.data());
+    wm.start_dnd_drag(*this, message.text(), bitmap, Core::MimeData::construct(message.mime_data()));
     return make<Messages::WindowServer::StartDragResponse>(true);
     return make<Messages::WindowServer::StartDragResponse>(true);
 }
 }
 
 

+ 3 - 1
Services/WindowServer/Event.h

@@ -29,6 +29,7 @@
 #include <AK/String.h>
 #include <AK/String.h>
 #include <Kernel/API/KeyCode.h>
 #include <Kernel/API/KeyCode.h>
 #include <LibCore/Event.h>
 #include <LibCore/Event.h>
+#include <LibCore/MimeData.h>
 #include <LibGfx/Rect.h>
 #include <LibGfx/Rect.h>
 #include <WindowServer/Cursor.h>
 #include <WindowServer/Cursor.h>
 #include <WindowServer/WindowType.h>
 #include <WindowServer/WindowType.h>
@@ -128,7 +129,7 @@ public:
     const String& drag_data_type() const { return m_drag_data_type; }
     const String& drag_data_type() const { return m_drag_data_type; }
 
 
     void set_drag(bool b) { m_drag = b; }
     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; }
+    void set_mime_data(const Core::MimeData& mime_data) { m_mime_data = mime_data; }
 
 
     MouseEvent translated(const Gfx::IntPoint& delta) const { return MouseEvent((Type)type(), m_position.translated(delta), m_buttons, m_button, m_modifiers, m_wheel_delta); }
     MouseEvent translated(const Gfx::IntPoint& delta) const { return MouseEvent((Type)type(), m_position.translated(delta), m_buttons, m_button, m_modifiers, m_wheel_delta); }
 
 
@@ -140,6 +141,7 @@ private:
     int m_wheel_delta { 0 };
     int m_wheel_delta { 0 };
     bool m_drag { false };
     bool m_drag { false };
     String m_drag_data_type;
     String m_drag_data_type;
+    RefPtr<const Core::MimeData> m_mime_data;
 };
 };
 
 
 class ResizeEvent final : public Event {
 class ResizeEvent final : public Event {

+ 1 - 1
Services/WindowServer/WindowClient.ipc

@@ -32,7 +32,7 @@ endpoint WindowClient = 4
     DragAccepted() =|
     DragAccepted() =|
     DragCancelled() =|
     DragCancelled() =|
 
 
-    DragDropped(i32 window_id, Gfx::IntPoint mouse_position, [UTF8] String text, String data_type, String data) =|
+    DragDropped(i32 window_id, Gfx::IntPoint mouse_position, [UTF8] String text, HashMap<String,ByteBuffer> mime_data) =|
 
 
     UpdateSystemTheme(i32 system_theme_buffer_id) =|
     UpdateSystemTheme(i32 system_theme_buffer_id) =|
 
 

+ 4 - 5
Services/WindowServer/WindowManager.cpp

@@ -705,7 +705,7 @@ bool WindowManager::process_ongoing_drag(MouseEvent& event, Window*& hovered_win
             hovered_window = &window;
             hovered_window = &window;
             auto translated_event = event.translated(-window.position());
             auto translated_event = event.translated(-window.position());
             translated_event.set_drag(true);
             translated_event.set_drag(true);
-            translated_event.set_drag_data_type(m_dnd_data_type);
+            translated_event.set_mime_data(*m_dnd_mime_data);
             deliver_mouse_event(window, translated_event);
             deliver_mouse_event(window, translated_event);
             return IterationDecision::Break;
             return IterationDecision::Break;
         });
         });
@@ -727,7 +727,7 @@ bool WindowManager::process_ongoing_drag(MouseEvent& event, Window*& hovered_win
         m_dnd_client->post_message(Messages::WindowClient::DragAccepted());
         m_dnd_client->post_message(Messages::WindowClient::DragAccepted());
         if (hovered_window->client()) {
         if (hovered_window->client()) {
             auto translated_event = event.translated(-hovered_window->position());
             auto translated_event = event.translated(-hovered_window->position());
-            hovered_window->client()->post_message(Messages::WindowClient::DragDropped(hovered_window->window_id(), translated_event.position(), m_dnd_text, m_dnd_data_type, m_dnd_data));
+            hovered_window->client()->post_message(Messages::WindowClient::DragDropped(hovered_window->window_id(), translated_event.position(), m_dnd_text, m_dnd_mime_data->all_data()));
         }
         }
     } else {
     } else {
         m_dnd_client->post_message(Messages::WindowClient::DragCancelled());
         m_dnd_client->post_message(Messages::WindowClient::DragCancelled());
@@ -1355,14 +1355,13 @@ Gfx::IntRect WindowManager::maximized_window_rect(const Window& window) const
     return rect;
     return rect;
 }
 }
 
 
-void WindowManager::start_dnd_drag(ClientConnection& client, const String& text, Gfx::Bitmap* bitmap, const String& data_type, const String& data)
+void WindowManager::start_dnd_drag(ClientConnection& client, const String& text, Gfx::Bitmap* bitmap, const Core::MimeData& mime_data)
 {
 {
     ASSERT(!m_dnd_client);
     ASSERT(!m_dnd_client);
     m_dnd_client = client.make_weak_ptr();
     m_dnd_client = client.make_weak_ptr();
     m_dnd_text = text;
     m_dnd_text = text;
     m_dnd_bitmap = bitmap;
     m_dnd_bitmap = bitmap;
-    m_dnd_data_type = data_type;
-    m_dnd_data = data;
+    m_dnd_mime_data = mime_data;
     Compositor::the().invalidate_cursor();
     Compositor::the().invalidate_cursor();
     m_active_input_tracking_window = nullptr;
     m_active_input_tracking_window = nullptr;
 }
 }

+ 3 - 5
Services/WindowServer/WindowManager.h

@@ -100,12 +100,11 @@ public:
 
 
     const ClientConnection* dnd_client() const { return m_dnd_client.ptr(); }
     const ClientConnection* dnd_client() const { return m_dnd_client.ptr(); }
     const String& dnd_text() const { return m_dnd_text; }
     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 Core::MimeData& dnd_mime_data() const { return *m_dnd_mime_data; }
     const Gfx::Bitmap* dnd_bitmap() const { return m_dnd_bitmap; }
     const Gfx::Bitmap* dnd_bitmap() const { return m_dnd_bitmap; }
     Gfx::IntRect dnd_rect() const;
     Gfx::IntRect dnd_rect() const;
 
 
-    void start_dnd_drag(ClientConnection&, const String& text, Gfx::Bitmap*, const String& data_type, const String& data);
+    void start_dnd_drag(ClientConnection&, const String& text, Gfx::Bitmap*, const Core::MimeData&);
     void end_dnd_drag();
     void end_dnd_drag();
 
 
     Window* active_window() { return m_active_window.ptr(); }
     Window* active_window() { return m_active_window.ptr(); }
@@ -331,8 +330,7 @@ private:
 
 
     WeakPtr<ClientConnection> m_dnd_client;
     WeakPtr<ClientConnection> m_dnd_client;
     String m_dnd_text;
     String m_dnd_text;
-    String m_dnd_data_type;
-    String m_dnd_data;
+    RefPtr<Core::MimeData> m_dnd_mime_data;
     RefPtr<Gfx::Bitmap> m_dnd_bitmap;
     RefPtr<Gfx::Bitmap> m_dnd_bitmap;
 };
 };
 
 

+ 1 - 1
Services/WindowServer/WindowServer.ipc

@@ -94,7 +94,7 @@ endpoint WindowServer = 2
     SetWindowCursor(i32 window_id, i32 cursor_type) => ()
     SetWindowCursor(i32 window_id, i32 cursor_type) => ()
     SetWindowCustomCursor(i32 window_id, Gfx::ShareableBitmap cursor) => ()
     SetWindowCustomCursor(i32 window_id, Gfx::ShareableBitmap cursor) => ()
 
 
-    StartDrag([UTF8] String text, String data_type, String data, i32 bitmap_id, Gfx::IntSize bitmap_size) => (bool started)
+    StartDrag([UTF8] String text, HashMap<String,ByteBuffer> mime_data, i32 bitmap_id, Gfx::IntSize bitmap_size) => (bool started)
 
 
     SetSystemTheme(String theme_path, [UTF8] String theme_name) => (bool success)
     SetSystemTheme(String theme_path, [UTF8] String theme_name) => (bool success)
     GetSystemTheme() => ([UTF8] String theme_name)
     GetSystemTheme() => ([UTF8] String theme_name)