Blame SOURCES/0039-Client-Implement-DataDeviceV3.patch

f8c1a9
From 2044603ebb5ae70c785d50968ac620b842c2b14e Mon Sep 17 00:00:00 2001
f8c1a9
From: David Edmundson <davidedmundson@kde.org>
f8c1a9
Date: Tue, 16 Feb 2021 09:51:47 +0000
f8c1a9
Subject: [PATCH 39/41] Client: Implement DataDeviceV3
f8c1a9
f8c1a9
DataDeviceV2 fixes a leak of DataDevice resources.
f8c1a9
f8c1a9
DataDeviceV3 brings multiple improvements:
f8c1a9
f8c1a9
Action negotiation. The source announces which actions are supported,
f8c1a9
the target then announces which subset of those action the target
f8c1a9
supports and a preferred action. After negotiation both the source and
f8c1a9
target are notified of which action is to be performed.
f8c1a9
f8c1a9
Drag sources are now notified when contents are dropped and when a
f8c1a9
client has finished with the drag and drop operation.
f8c1a9
f8c1a9
A good test is the draggableicons example in QtBase.
f8c1a9
f8c1a9
Change-Id: I55e9759ca5a2e4218d02d863144a64ade53ef764
f8c1a9
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
f8c1a9
(cherry picked from commit 283a2d61d03315495a52d82f356e7cb5292f4bb4)
f8c1a9
---
f8c1a9
 src/client/qwaylanddatadevice.cpp             | 84 ++++++++++++++-----
f8c1a9
 src/client/qwaylanddatadevice_p.h             |  8 +-
f8c1a9
 src/client/qwaylanddatadevicemanager.cpp      |  4 +-
f8c1a9
 src/client/qwaylanddatadevicemanager_p.h      |  2 +-
f8c1a9
 src/client/qwaylanddataoffer.cpp              | 25 ++++++
f8c1a9
 src/client/qwaylanddataoffer_p.h              |  4 +
f8c1a9
 src/client/qwaylanddatasource.cpp             | 27 +++++-
f8c1a9
 src/client/qwaylanddatasource_p.h             | 10 ++-
f8c1a9
 src/client/qwaylanddisplay.cpp                |  2 +-
f8c1a9
 src/client/qwaylanddnd.cpp                    | 24 +++---
f8c1a9
 src/client/qwaylanddnd_p.h                    |  7 +-
f8c1a9
 .../client/datadevicev1/tst_datadevicev1.cpp  |  2 +-
f8c1a9
 12 files changed, 153 insertions(+), 46 deletions(-)
f8c1a9
f8c1a9
diff --git a/src/client/qwaylanddatadevice.cpp b/src/client/qwaylanddatadevice.cpp
f8c1a9
index bbd2d568..fbb5aa91 100644
f8c1a9
--- a/src/client/qwaylanddatadevice.cpp
f8c1a9
+++ b/src/client/qwaylanddatadevice.cpp
f8c1a9
@@ -72,6 +72,8 @@ QWaylandDataDevice::QWaylandDataDevice(QWaylandDataDeviceManager *manager, QWayl
f8c1a9
 
f8c1a9
 QWaylandDataDevice::~QWaylandDataDevice()
f8c1a9
 {
f8c1a9
+    if (wl_data_device_get_version(object()) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION)
f8c1a9
+        release();
f8c1a9
 }
f8c1a9
 
f8c1a9
 QWaylandDataOffer *QWaylandDataDevice::selectionOffer() const
f8c1a9
@@ -110,7 +112,7 @@ QWaylandDataOffer *QWaylandDataDevice::dragOffer() const
f8c1a9
     return m_dragOffer.data();
f8c1a9
 }
f8c1a9
 
f8c1a9
-bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
f8c1a9
+bool QWaylandDataDevice::startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon)
f8c1a9
 {
f8c1a9
     auto *seat = m_display->currentInputDevice();
f8c1a9
     auto *origin = seat->pointerFocus();
f8c1a9
@@ -123,8 +125,28 @@ bool QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
f8c1a9
     }
f8c1a9
 
f8c1a9
     m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
f8c1a9
+
f8c1a9
+    if (wl_data_device_get_version(object()) >= 3)
f8c1a9
+        m_dragSource->set_actions(dropActionsToWl(supportedActions));
f8c1a9
+
f8c1a9
     connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
f8c1a9
-    connect(m_dragSource.data(), &QWaylandDataSource::targetChanged, this, &QWaylandDataDevice::dragSourceTargetChanged);
f8c1a9
+    connect(m_dragSource.data(), &QWaylandDataSource::dndResponseUpdated, this, [this](bool accepted, Qt::DropAction action) {
f8c1a9
+            auto drag = static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
f8c1a9
+            // in old versions drop action is not set, so we guess
f8c1a9
+            if (wl_data_source_get_version(m_dragSource->object()) < 3) {
f8c1a9
+                drag->setResponse(accepted);
f8c1a9
+            } else {
f8c1a9
+                QPlatformDropQtResponse response(accepted, action);
f8c1a9
+                drag->setResponse(response);
f8c1a9
+            }
f8c1a9
+    });
f8c1a9
+    connect(m_dragSource.data(), &QWaylandDataSource::dndDropped, this, [](bool accepted, Qt::DropAction action) {
f8c1a9
+        QPlatformDropQtResponse response(accepted, action);
f8c1a9
+        static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setDropResponse(response);
f8c1a9
+    });
f8c1a9
+    connect(m_dragSource.data(), &QWaylandDataSource::finished, this, []() {
f8c1a9
+        static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag();
f8c1a9
+    });
f8c1a9
 
f8c1a9
     start_drag(m_dragSource->object(), origin->wlSurface(), icon->wlSurface(), m_display->currentInputDevice()->serial());
f8c1a9
     return true;
f8c1a9
@@ -153,7 +175,7 @@ void QWaylandDataDevice::data_device_drop()
f8c1a9
         supportedActions = drag->supportedActions();
f8c1a9
     } else if (m_dragOffer) {
f8c1a9
         dragData = m_dragOffer->mimeData();
f8c1a9
-        supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
f8c1a9
+        supportedActions = m_dragOffer->supportedActions();
f8c1a9
     } else {
f8c1a9
         return;
f8c1a9
     }
f8c1a9
@@ -163,7 +185,11 @@ void QWaylandDataDevice::data_device_drop()
f8c1a9
                                                                           QGuiApplication::keyboardModifiers());
f8c1a9
 
f8c1a9
     if (drag) {
f8c1a9
-        static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->finishDrag(response);
f8c1a9
+        auto drag =  static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
f8c1a9
+        drag->setDropResponse(response);
f8c1a9
+        drag->finishDrag();
f8c1a9
+    } else if (m_dragOffer) {
f8c1a9
+        m_dragOffer->finish();
f8c1a9
     }
f8c1a9
 }
f8c1a9
 
f8c1a9
@@ -187,7 +213,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
f8c1a9
         supportedActions = drag->supportedActions();
f8c1a9
     } else if (m_dragOffer) {
f8c1a9
         dragData = m_dragOffer->mimeData();
f8c1a9
-        supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
f8c1a9
+        supportedActions = m_dragOffer->supportedActions();
f8c1a9
     }
f8c1a9
 
f8c1a9
     const QPlatformDragQtResponse &response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
f8c1a9
@@ -198,11 +224,7 @@ void QWaylandDataDevice::data_device_enter(uint32_t serial, wl_surface *surface,
f8c1a9
         static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
f8c1a9
     }
f8c1a9
 
f8c1a9
-    if (response.isAccepted()) {
f8c1a9
-        wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
f8c1a9
-    } else {
f8c1a9
-        wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
f8c1a9
-    }
f8c1a9
+    sendResponse(supportedActions, response);
f8c1a9
 }
f8c1a9
 
f8c1a9
 void QWaylandDataDevice::data_device_leave()
f8c1a9
@@ -236,10 +258,10 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
f8c1a9
         supportedActions = drag->supportedActions();
f8c1a9
     } else {
f8c1a9
         dragData = m_dragOffer->mimeData();
f8c1a9
-        supportedActions = Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
f8c1a9
+        supportedActions = m_dragOffer->supportedActions();
f8c1a9
     }
f8c1a9
 
f8c1a9
-    QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
f8c1a9
+    const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_dragWindow, dragData, m_dragPoint, supportedActions,
f8c1a9
                                                                           QGuiApplication::mouseButtons(),
f8c1a9
                                                                           QGuiApplication::keyboardModifiers());
f8c1a9
 
f8c1a9
@@ -247,11 +269,7 @@ void QWaylandDataDevice::data_device_motion(uint32_t time, wl_fixed_t x, wl_fixe
f8c1a9
         static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->setResponse(response);
f8c1a9
     }
f8c1a9
 
f8c1a9
-    if (response.isAccepted()) {
f8c1a9
-        wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, m_dragOffer->firstFormat().toUtf8().constData());
f8c1a9
-    } else {
f8c1a9
-        wl_data_offer_accept(m_dragOffer->object(), m_enterSerial, nullptr);
f8c1a9
-    }
f8c1a9
+    sendResponse(supportedActions, response);
f8c1a9
 }
f8c1a9
 #endif // QT_CONFIG(draganddrop)
f8c1a9
 
f8c1a9
@@ -281,11 +299,6 @@ void QWaylandDataDevice::dragSourceCancelled()
f8c1a9
     m_dragSource.reset();
f8c1a9
 }
f8c1a9
 
f8c1a9
-void QWaylandDataDevice::dragSourceTargetChanged(const QString &mimeType)
f8c1a9
-{
f8c1a9
-    static_cast<QWaylandDrag *>(QGuiApplicationPrivate::platformIntegration()->drag())->updateTarget(mimeType);
f8c1a9
-}
f8c1a9
-
f8c1a9
 QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) const
f8c1a9
 {
f8c1a9
     QPoint pnt(wl_fixed_to_int(x), wl_fixed_to_int(y));
f8c1a9
@@ -298,6 +311,33 @@ QPoint QWaylandDataDevice::calculateDragPosition(int x, int y, QWindow *wnd) con
f8c1a9
     }
f8c1a9
     return pnt;
f8c1a9
 }
f8c1a9
+
f8c1a9
+void QWaylandDataDevice::sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response)
f8c1a9
+{
f8c1a9
+    if (response.isAccepted()) {
f8c1a9
+        if (wl_data_device_get_version(object()) >= 3)
f8c1a9
+            m_dragOffer->set_actions(dropActionsToWl(supportedActions), dropActionsToWl(response.acceptedAction()));
f8c1a9
+
f8c1a9
+        m_dragOffer->accept(m_enterSerial, m_dragOffer->firstFormat());
f8c1a9
+    } else {
f8c1a9
+        m_dragOffer->accept(m_enterSerial, QString());
f8c1a9
+    }
f8c1a9
+}
f8c1a9
+
f8c1a9
+int QWaylandDataDevice::dropActionsToWl(Qt::DropActions actions)
f8c1a9
+{
f8c1a9
+
f8c1a9
+    int wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
f8c1a9
+    if (actions & Qt::CopyAction)
f8c1a9
+        wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
f8c1a9
+    if (actions & (Qt::MoveAction | Qt::TargetMoveAction))
f8c1a9
+        wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
f8c1a9
+
f8c1a9
+    // wayland does not support LinkAction at the time of writing
f8c1a9
+    return wlActions;
f8c1a9
+}
f8c1a9
+
f8c1a9
+
f8c1a9
 #endif // QT_CONFIG(draganddrop)
f8c1a9
 
f8c1a9
 }
f8c1a9
diff --git a/src/client/qwaylanddatadevice_p.h b/src/client/qwaylanddatadevice_p.h
f8c1a9
index 16c3ad28..801dcc2c 100644
f8c1a9
--- a/src/client/qwaylanddatadevice_p.h
f8c1a9
+++ b/src/client/qwaylanddatadevice_p.h
f8c1a9
@@ -64,6 +64,7 @@ QT_REQUIRE_CONFIG(wayland_datadevice);
f8c1a9
 QT_BEGIN_NAMESPACE
f8c1a9
 
f8c1a9
 class QMimeData;
f8c1a9
+class QPlatformDragQtResponse;
f8c1a9
 class QWindow;
f8c1a9
 
f8c1a9
 namespace QtWaylandClient {
f8c1a9
@@ -89,7 +90,7 @@ public:
f8c1a9
 
f8c1a9
 #if QT_CONFIG(draganddrop)
f8c1a9
     QWaylandDataOffer *dragOffer() const;
f8c1a9
-    bool startDrag(QMimeData *mimeData, QWaylandWindow *icon);
f8c1a9
+    bool startDrag(QMimeData *mimeData, Qt::DropActions supportedActions, QWaylandWindow *icon);
f8c1a9
     void cancelDrag();
f8c1a9
 #endif
f8c1a9
 
f8c1a9
@@ -109,13 +110,16 @@ private Q_SLOTS:
f8c1a9
 
f8c1a9
 #if QT_CONFIG(draganddrop)
f8c1a9
     void dragSourceCancelled();
f8c1a9
-    void dragSourceTargetChanged(const QString &mimeType);
f8c1a9
 #endif
f8c1a9
 
f8c1a9
 private:
f8c1a9
 #if QT_CONFIG(draganddrop)
f8c1a9
     QPoint calculateDragPosition(int x, int y, QWindow *wnd) const;
f8c1a9
 #endif
f8c1a9
+    void sendResponse(Qt::DropActions supportedActions, const QPlatformDragQtResponse &response);
f8c1a9
+
f8c1a9
+    static int dropActionsToWl(Qt::DropActions dropActions);
f8c1a9
+
f8c1a9
 
f8c1a9
     QWaylandDisplay *m_display = nullptr;
f8c1a9
     QWaylandInputDevice *m_inputDevice = nullptr;
f8c1a9
diff --git a/src/client/qwaylanddatadevicemanager.cpp b/src/client/qwaylanddatadevicemanager.cpp
f8c1a9
index 35d67307..6dc4f77f 100644
f8c1a9
--- a/src/client/qwaylanddatadevicemanager.cpp
f8c1a9
+++ b/src/client/qwaylanddatadevicemanager.cpp
f8c1a9
@@ -50,8 +50,8 @@ QT_BEGIN_NAMESPACE
f8c1a9
 
f8c1a9
 namespace QtWaylandClient {
f8c1a9
 
f8c1a9
-QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id)
f8c1a9
-    : wl_data_device_manager(display->wl_registry(), id, 1)
f8c1a9
+QWaylandDataDeviceManager::QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id)
f8c1a9
+    : wl_data_device_manager(display->wl_registry(), id, qMin(version, 3))
f8c1a9
     , m_display(display)
f8c1a9
 {
f8c1a9
     // Create transfer devices for all input devices.
f8c1a9
diff --git a/src/client/qwaylanddatadevicemanager_p.h b/src/client/qwaylanddatadevicemanager_p.h
f8c1a9
index bd05c0fb..510d9be4 100644
f8c1a9
--- a/src/client/qwaylanddatadevicemanager_p.h
f8c1a9
+++ b/src/client/qwaylanddatadevicemanager_p.h
f8c1a9
@@ -68,7 +68,7 @@ class QWaylandInputDevice;
f8c1a9
 class Q_WAYLAND_CLIENT_EXPORT QWaylandDataDeviceManager : public QtWayland::wl_data_device_manager
f8c1a9
 {
f8c1a9
 public:
f8c1a9
-    QWaylandDataDeviceManager(QWaylandDisplay *display, uint32_t id);
f8c1a9
+    QWaylandDataDeviceManager(QWaylandDisplay *display, int version, uint32_t id);
f8c1a9
     ~QWaylandDataDeviceManager() override;
f8c1a9
 
f8c1a9
     QWaylandDataDevice *getDataDevice(QWaylandInputDevice *inputDevice);
f8c1a9
diff --git a/src/client/qwaylanddataoffer.cpp b/src/client/qwaylanddataoffer.cpp
f8c1a9
index 2297e8a1..c9e158cc 100644
f8c1a9
--- a/src/client/qwaylanddataoffer.cpp
f8c1a9
+++ b/src/client/qwaylanddataoffer.cpp
f8c1a9
@@ -82,6 +82,15 @@ QMimeData *QWaylandDataOffer::mimeData()
f8c1a9
     return m_mimeData.data();
f8c1a9
 }
f8c1a9
 
f8c1a9
+Qt::DropActions QWaylandDataOffer::supportedActions() const
f8c1a9
+{
f8c1a9
+    if (wl_data_offer_get_version(const_cast<::wl_data_offer*>(object())) < 3) {
f8c1a9
+        return Qt::MoveAction | Qt::CopyAction;
f8c1a9
+    }
f8c1a9
+
f8c1a9
+    return m_supportedActions;
f8c1a9
+}
f8c1a9
+
f8c1a9
 void QWaylandDataOffer::startReceiving(const QString &mimeType, int fd)
f8c1a9
 {
f8c1a9
     receive(mimeType, fd);
f8c1a9
@@ -93,6 +102,22 @@ void QWaylandDataOffer::data_offer_offer(const QString &mime_type)
f8c1a9
     m_mimeData->appendFormat(mime_type);
f8c1a9
 }
f8c1a9
 
f8c1a9
+void QWaylandDataOffer::data_offer_action(uint32_t dnd_action)
f8c1a9
+{
f8c1a9
+    Q_UNUSED(dnd_action);
f8c1a9
+    // This is the compositor telling the drag target what action it should perform
f8c1a9
+    // It does not map nicely into Qt final drop semantics, other than pretending there is only one supported action?
f8c1a9
+}
f8c1a9
+
f8c1a9
+void QWaylandDataOffer::data_offer_source_actions(uint32_t source_actions)
f8c1a9
+{
f8c1a9
+    m_supportedActions = Qt::DropActions();
f8c1a9
+    if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
f8c1a9
+        m_supportedActions |= Qt::MoveAction;
f8c1a9
+    if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
f8c1a9
+        m_supportedActions |= Qt::CopyAction;
f8c1a9
+}
f8c1a9
+
f8c1a9
 QWaylandMimeData::QWaylandMimeData(QWaylandAbstractDataOffer *dataOffer)
f8c1a9
     : m_dataOffer(dataOffer)
f8c1a9
 {
f8c1a9
diff --git a/src/client/qwaylanddataoffer_p.h b/src/client/qwaylanddataoffer_p.h
f8c1a9
index 9cf1483c..6f667398 100644
f8c1a9
--- a/src/client/qwaylanddataoffer_p.h
f8c1a9
+++ b/src/client/qwaylanddataoffer_p.h
f8c1a9
@@ -82,6 +82,7 @@ public:
f8c1a9
     explicit QWaylandDataOffer(QWaylandDisplay *display, struct ::wl_data_offer *offer);
f8c1a9
     ~QWaylandDataOffer() override;
f8c1a9
     QMimeData *mimeData() override;
f8c1a9
+    Qt::DropActions supportedActions() const;
f8c1a9
 
f8c1a9
     QString firstFormat() const;
f8c1a9
 
f8c1a9
@@ -89,10 +90,13 @@ public:
f8c1a9
 
f8c1a9
 protected:
f8c1a9
     void data_offer_offer(const QString &mime_type) override;
f8c1a9
+    void data_offer_source_actions(uint32_t source_actions) override;
f8c1a9
+    void data_offer_action(uint32_t dnd_action) override;
f8c1a9
 
f8c1a9
 private:
f8c1a9
     QWaylandDisplay *m_display = nullptr;
f8c1a9
     QScopedPointer<QWaylandMimeData> m_mimeData;
f8c1a9
+    Qt::DropActions m_supportedActions;
f8c1a9
 };
f8c1a9
 
f8c1a9
 
f8c1a9
diff --git a/src/client/qwaylanddatasource.cpp b/src/client/qwaylanddatasource.cpp
f8c1a9
index f45122fb..5599cbd4 100644
f8c1a9
--- a/src/client/qwaylanddatasource.cpp
f8c1a9
+++ b/src/client/qwaylanddatasource.cpp
f8c1a9
@@ -101,7 +101,32 @@ void QWaylandDataSource::data_source_send(const QString &mime_type, int32_t fd)
f8c1a9
 
f8c1a9
 void QWaylandDataSource::data_source_target(const QString &mime_type)
f8c1a9
 {
f8c1a9
-    Q_EMIT targetChanged(mime_type);
f8c1a9
+    m_accepted = !mime_type.isEmpty();
f8c1a9
+    Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
f8c1a9
+}
f8c1a9
+
f8c1a9
+void QWaylandDataSource::data_source_action(uint32_t action)
f8c1a9
+{
f8c1a9
+    Qt::DropAction qtAction = Qt::IgnoreAction;
f8c1a9
+
f8c1a9
+    if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
f8c1a9
+        qtAction = Qt::MoveAction;
f8c1a9
+    else if (action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
f8c1a9
+        qtAction = Qt::CopyAction;
f8c1a9
+
f8c1a9
+    m_dropAction = qtAction;
f8c1a9
+    Q_EMIT dndResponseUpdated(m_accepted, m_dropAction);
f8c1a9
+}
f8c1a9
+
f8c1a9
+void QWaylandDataSource::data_source_dnd_finished()
f8c1a9
+{
f8c1a9
+    Q_EMIT finished();
f8c1a9
+}
f8c1a9
+
f8c1a9
+void QWaylandDataSource::data_source_dnd_drop_performed()
f8c1a9
+{
f8c1a9
+
f8c1a9
+    Q_EMIT dndDropped(m_accepted, m_dropAction);
f8c1a9
 }
f8c1a9
 
f8c1a9
 }
f8c1a9
diff --git a/src/client/qwaylanddatasource_p.h b/src/client/qwaylanddatasource_p.h
f8c1a9
index 25afff79..96f07bc3 100644
f8c1a9
--- a/src/client/qwaylanddatasource_p.h
f8c1a9
+++ b/src/client/qwaylanddatasource_p.h
f8c1a9
@@ -77,17 +77,25 @@ public:
f8c1a9
     QMimeData *mimeData() const;
f8c1a9
 
f8c1a9
 Q_SIGNALS:
f8c1a9
-    void targetChanged(const QString &mime_type);
f8c1a9
     void cancelled();
f8c1a9
+    void finished();
f8c1a9
+
f8c1a9
+    void dndResponseUpdated(bool accepted, Qt::DropAction action);
f8c1a9
+    void dndDropped(bool accepted, Qt::DropAction action);
f8c1a9
 
f8c1a9
 protected:
f8c1a9
     void data_source_cancelled() override;
f8c1a9
     void data_source_send(const QString &mime_type, int32_t fd) override;
f8c1a9
     void data_source_target(const QString &mime_type) override;
f8c1a9
+    void data_source_dnd_drop_performed() override;
f8c1a9
+    void data_source_dnd_finished() override;
f8c1a9
+    void data_source_action(uint32_t action) override;
f8c1a9
 
f8c1a9
 private:
f8c1a9
     QWaylandDisplay *m_display = nullptr;
f8c1a9
     QMimeData *m_mime_data = nullptr;
f8c1a9
+    bool m_accepted = false;
f8c1a9
+    Qt::DropAction m_dropAction = Qt::IgnoreAction;
f8c1a9
 };
f8c1a9
 
f8c1a9
 }
f8c1a9
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
f8c1a9
index 9f595af3..ea344c61 100644
f8c1a9
--- a/src/client/qwaylanddisplay.cpp
f8c1a9
+++ b/src/client/qwaylanddisplay.cpp
f8c1a9
@@ -354,7 +354,7 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin
f8c1a9
         mInputDevices.append(inputDevice);
f8c1a9
 #if QT_CONFIG(wayland_datadevice)
f8c1a9
     } else if (interface == QStringLiteral("wl_data_device_manager")) {
f8c1a9
-        mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id));
f8c1a9
+        mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, version, id));
f8c1a9
 #endif
f8c1a9
     } else if (interface == QStringLiteral("qt_surface_extension")) {
f8c1a9
         mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1));
f8c1a9
diff --git a/src/client/qwaylanddnd.cpp b/src/client/qwaylanddnd.cpp
f8c1a9
index 6535aa16..97ee5b2e 100644
f8c1a9
--- a/src/client/qwaylanddnd.cpp
f8c1a9
+++ b/src/client/qwaylanddnd.cpp
f8c1a9
@@ -66,7 +66,7 @@ void QWaylandDrag::startDrag()
f8c1a9
 {
f8c1a9
     QBasicDrag::startDrag();
f8c1a9
     QWaylandWindow *icon = static_cast<QWaylandWindow *>(shapedPixmapWindow()->handle());
f8c1a9
-    if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), icon)) {
f8c1a9
+    if (m_display->currentInputDevice()->dataDevice()->startDrag(drag()->mimeData(), drag()->supportedActions(), icon)) {
f8c1a9
         icon->addAttachOffset(-drag()->hotSpot());
f8c1a9
     } else {
f8c1a9
         // Cancelling immediately does not work, since the event loop for QDrag::exec is started
f8c1a9
@@ -103,31 +103,31 @@ void QWaylandDrag::endDrag()
f8c1a9
     m_display->currentInputDevice()->handleEndDrag();
f8c1a9
 }
f8c1a9
 
f8c1a9
-void QWaylandDrag::updateTarget(const QString &mimeType)
f8c1a9
+void QWaylandDrag::setResponse(bool accepted)
f8c1a9
 {
f8c1a9
-    setCanDrop(!mimeType.isEmpty());
f8c1a9
-
f8c1a9
-    if (canDrop()) {
f8c1a9
-        updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
f8c1a9
-    } else {
f8c1a9
-        updateCursor(Qt::IgnoreAction);
f8c1a9
-    }
f8c1a9
+    // This method is used for old DataDevices where the drag action is not communicated
f8c1a9
+    Qt::DropAction action = defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers());
f8c1a9
+    setResponse(QPlatformDropQtResponse(accepted, action));
f8c1a9
 }
f8c1a9
 
f8c1a9
-void QWaylandDrag::setResponse(const QPlatformDragQtResponse &response)
f8c1a9
+void QWaylandDrag::setResponse(const QPlatformDropQtResponse &response)
f8c1a9
 {
f8c1a9
     setCanDrop(response.isAccepted());
f8c1a9
 
f8c1a9
     if (canDrop()) {
f8c1a9
-        updateCursor(defaultAction(drag()->supportedActions(), m_display->currentInputDevice()->modifiers()));
f8c1a9
+        updateCursor(response.acceptedAction());
f8c1a9
     } else {
f8c1a9
         updateCursor(Qt::IgnoreAction);
f8c1a9
     }
f8c1a9
 }
f8c1a9
 
f8c1a9
-void QWaylandDrag::finishDrag(const QPlatformDropQtResponse &response)
f8c1a9
+void QWaylandDrag::setDropResponse(const QPlatformDropQtResponse &response)
f8c1a9
 {
f8c1a9
     setExecutedDropAction(response.acceptedAction());
f8c1a9
+}
f8c1a9
+
f8c1a9
+void QWaylandDrag::finishDrag()
f8c1a9
+{
f8c1a9
     QKeyEvent event(QEvent::KeyPress, Qt::Key_Escape, Qt::NoModifier);
f8c1a9
     eventFilter(shapedPixmapWindow(), &event);
f8c1a9
 }
f8c1a9
diff --git a/src/client/qwaylanddnd_p.h b/src/client/qwaylanddnd_p.h
f8c1a9
index 474fe2ab..747f0190 100644
f8c1a9
--- a/src/client/qwaylanddnd_p.h
f8c1a9
+++ b/src/client/qwaylanddnd_p.h
f8c1a9
@@ -71,9 +71,10 @@ public:
f8c1a9
     QWaylandDrag(QWaylandDisplay *display);
f8c1a9
     ~QWaylandDrag() override;
f8c1a9
 
f8c1a9
-    void updateTarget(const QString &mimeType);
f8c1a9
-    void setResponse(const QPlatformDragQtResponse &response);
f8c1a9
-    void finishDrag(const QPlatformDropQtResponse &response);
f8c1a9
+    void setResponse(bool accepted);
f8c1a9
+    void setResponse(const QPlatformDropQtResponse &response);
f8c1a9
+    void setDropResponse(const QPlatformDropQtResponse &response);
f8c1a9
+    void finishDrag();
f8c1a9
 
f8c1a9
 protected:
f8c1a9
     void startDrag() override;
f8c1a9
diff --git a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
f8c1a9
index 1568b3b9..067410d0 100644
f8c1a9
--- a/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
f8c1a9
+++ b/tests/auto/client/datadevicev1/tst_datadevicev1.cpp
f8c1a9
@@ -35,7 +35,7 @@
f8c1a9
 
f8c1a9
 using namespace MockCompositor;
f8c1a9
 
f8c1a9
-constexpr int dataDeviceVersion = 1;
f8c1a9
+constexpr int dataDeviceVersion = 3;
f8c1a9
 
f8c1a9
 class DataDeviceCompositor : public DefaultCompositor {
f8c1a9
 public:
f8c1a9
-- 
f8c1a9
2.34.1
f8c1a9