Bläddra i källkod

LibGUI+WindowServer: Allow specifying an optional drag bitmap

This bitmap is displayed alongside the dragged text underneath the
mouse cursor while dragging.

This will be a perfect fit for dragging e.g files around. :^)
Andreas Kling 5 år sedan
förälder
incheckning
f5dfb29607

+ 12 - 1
Libraries/LibGUI/GDragOperation.cpp

@@ -1,3 +1,4 @@
+#include <LibDraw/GraphicsBitmap.h>
 #include <LibGUI/GDragOperation.h>
 #include <LibGUI/GWindowServerConnection.h>
 
@@ -17,7 +18,17 @@ GDragOperation::Outcome GDragOperation::exec()
     ASSERT(!s_current_drag_operation);
     ASSERT(!m_event_loop);
 
-    auto response = GWindowServerConnection::the().send_sync<WindowServer::StartDrag>(m_text, -1, Size());
+    int bitmap_id = -1;
+    Size bitmap_size;
+    RefPtr<GraphicsBitmap> shared_bitmap;
+    if (m_bitmap) {
+        shared_bitmap = m_bitmap->to_shareable_bitmap();
+        shared_bitmap->shared_buffer()->share_with(GWindowServerConnection::the().server_pid());
+        bitmap_id = shared_bitmap->shared_buffer_id();
+        bitmap_size = shared_bitmap->size();
+    }
+
+    auto response = GWindowServerConnection::the().send_sync<WindowServer::StartDrag>(m_text, bitmap_id, bitmap_size);
     if (!response->started()) {
         m_outcome = Outcome::Cancelled;
         return m_outcome;

+ 3 - 0
Libraries/LibGUI/GDragOperation.h

@@ -3,6 +3,7 @@
 #include <LibCore/CEventLoop.h>
 #include <LibCore/CObject.h>
 
+class GraphicsBitmap;
 class GWindowServerConnection;
 
 class GDragOperation : public CObject {
@@ -17,6 +18,7 @@ public:
     virtual ~GDragOperation() override;
 
     void set_text(const String& text) { m_text = text; }
+    void set_bitmap(const GraphicsBitmap* bitmap) { m_bitmap = bitmap; }
 
     Outcome exec();
     Outcome outcome() const { return m_outcome; }
@@ -33,4 +35,5 @@ private:
     OwnPtr<CEventLoop> m_event_loop;
     Outcome m_outcome { Outcome::None };
     String m_text;
+    RefPtr<GraphicsBitmap> m_bitmap;
 };

+ 9 - 0
Libraries/LibGUI/GItemView.cpp

@@ -113,14 +113,23 @@ void GItemView::mousemove_event(GMouseEvent& event)
             dbg() << "Initiate drag!";
             auto drag_operation = GDragOperation::construct();
 
+            RefPtr<GraphicsBitmap> bitmap;
+
             StringBuilder builder;
             selection().for_each_index([&](auto& index) {
                 auto data = model()->data(index);
                 builder.append(data.to_string());
                 builder.append(" ");
+
+                if (!bitmap) {
+                    GVariant icon_data = model()->data(index, GModel::Role::Icon);
+                    if (icon_data.is_icon())
+                        bitmap = icon_data.as_icon().bitmap_for_size(32);
+                }
             });
 
             drag_operation->set_text(builder.to_string());
+            drag_operation->set_bitmap(bitmap);
             auto outcome = drag_operation->exec();
             switch (outcome) {
             case GDragOperation::Outcome::Accepted:

+ 8 - 3
Servers/WindowServer/WSCompositor.cpp

@@ -424,11 +424,16 @@ void WSCompositor::draw_cursor()
 
     if (wm.dnd_client()) {
         auto dnd_rect = wm.dnd_rect();
+        m_back_painter->fill_rect(dnd_rect, Color(110, 34, 9, 200));
         if (!wm.dnd_text().is_empty()) {
-            m_back_painter->fill_rect(dnd_rect, Color(110, 34, 9, 200));
-            m_back_painter->draw_text(dnd_rect, wm.dnd_text(), TextAlignment::Center, Color::White);
+            auto text_rect = dnd_rect;
+            if (wm.dnd_bitmap())
+                text_rect.move_by(wm.dnd_bitmap()->width(), 0);
+            m_back_painter->draw_text(text_rect, wm.dnd_text(), TextAlignment::CenterLeft, Color::White);
+        }
+        if (wm.dnd_bitmap()) {
+            m_back_painter->blit(dnd_rect.top_left(), *wm.dnd_bitmap(), wm.dnd_bitmap()->rect());
         }
-        // FIXME: Also do the drag_bitmap if present
         m_last_dnd_rect = dnd_rect;
     } else {
         m_last_dnd_rect = {};

+ 4 - 2
Servers/WindowServer/WSWindowManager.cpp

@@ -1199,8 +1199,10 @@ void WSWindowManager::end_dnd_drag()
 
 Rect WSWindowManager::dnd_rect() const
 {
-    int width = font().width(m_dnd_text);
-    int height = font().glyph_height();
+    int bitmap_width = m_dnd_bitmap ? m_dnd_bitmap->width() : 0;
+    int bitmap_height = m_dnd_bitmap ? m_dnd_bitmap->width() : 0;
+    int width = font().width(m_dnd_text) + bitmap_width;
+    int height = max((int)font().glyph_height(), bitmap_height);
     auto location = WSCompositor::the().current_cursor_rect().center().translated(8, 8);
     return Rect(location, { width, height }).inflated(4, 4);
 }