From 0aaed33c662737c5b21d60de3315e1b47a8f1a13 Mon Sep 17 00:00:00 2001 From: David Redondo Date: Fri, 3 Sep 2021 14:27:16 +0200 Subject: [PATCH] Move drag logic to seat and introduce SeatInterface::startDrag A dataDevice has a request to start a drag with multiple parameters. As kwayland's goal is to turn an event-driven API into a property cache API we store this data. This patch moves that storage to the Seat as properties of the active drag, rather than a property of the data device that happened to initialise it. This both helps keep a lot of other logic together, but also allows us to expose a public startDrag method that can be invoked from Kwin's internal surfaces or xwayland. Any properties in DataDevice now relate to data being dropped on the device. --- src/wayland/abstract_data_source.h | 5 + .../autotests/client/test_datadevice.cpp | 17 ++- .../autotests/client/test_drag_drop.cpp | 13 ++- src/wayland/datadevice_interface.cpp | 82 ++++--------- src/wayland/datadevice_interface.h | 19 +-- src/wayland/datadevice_interface_p.h | 4 - src/wayland/datasource_interface.cpp | 4 +- src/wayland/datasource_interface.h | 2 +- src/wayland/seat_interface.cpp | 109 +++++++++--------- src/wayland/seat_interface.h | 11 +- src/wayland/seat_interface_p.h | 11 +- src/wayland/surface_interface.cpp | 10 -- src/wayland/surface_interface.h | 14 --- src/wayland/surface_interface_p.h | 1 - 14 files changed, 119 insertions(+), 183 deletions(-) diff --git a/src/wayland/abstract_data_source.h b/src/wayland/abstract_data_source.h index c90d85780f..aea38acbb8 100644 --- a/src/wayland/abstract_data_source.h +++ b/src/wayland/abstract_data_source.h @@ -29,6 +29,11 @@ class KWAYLANDSERVER_EXPORT AbstractDataSource : public QObject { Q_OBJECT public: + virtual bool isAccepted() const + { + return false; + } + virtual void accept(const QString &mimeType) { Q_UNUSED(mimeType); diff --git a/src/wayland/autotests/client/test_datadevice.cpp b/src/wayland/autotests/client/test_datadevice.cpp index 9d7ee9e2fa..b4c6c3c30d 100644 --- a/src/wayland/autotests/client/test_datadevice.cpp +++ b/src/wayland/autotests/client/test_datadevice.cpp @@ -171,9 +171,6 @@ void TestDataDevice::testCreate() auto deviceInterface = dataDeviceCreatedSpy.first().first().value(); QVERIFY(deviceInterface); QCOMPARE(deviceInterface->seat(), m_seatInterface); - QVERIFY(!deviceInterface->dragSource()); - QVERIFY(!deviceInterface->origin()); - QVERIFY(!deviceInterface->icon()); QVERIFY(!deviceInterface->selection()); // this will probably fail, we need to make a selection client side @@ -269,9 +266,9 @@ void TestDataDevice::testDrag() dataDevice->startDrag(pointerButtonSerial, dataSource.data(), surface.data()); QCOMPARE(dragStartedSpy.wait(500), success); QCOMPARE(!dragStartedSpy.isEmpty(), success); - QCOMPARE(deviceInterface->dragSource(), success ? sourceInterface : nullptr); - QCOMPARE(deviceInterface->origin(), success ? surfaceInterface : nullptr); - QVERIFY(!deviceInterface->icon()); + QCOMPARE(m_seatInterface->dragSource(), success ? sourceInterface : nullptr); + QCOMPARE(m_seatInterface->dragSurface(), success ? surfaceInterface : nullptr); + QVERIFY(!m_seatInterface->dragIcon()); } void TestDataDevice::testDragInternally_data() @@ -350,13 +347,13 @@ void TestDataDevice::testDragInternally() dataDevice->startDragInternally(pointerButtonSerial, surface.data(), iconSurface.data()); QCOMPARE(dragStartedSpy.wait(500), success); QCOMPARE(!dragStartedSpy.isEmpty(), success); - QVERIFY(!deviceInterface->dragSource()); - QCOMPARE(deviceInterface->origin(), success ? surfaceInterface : nullptr); + QVERIFY(!m_seatInterface->dragSource()); + QCOMPARE(m_seatInterface->dragSurface(), success ? surfaceInterface : nullptr); if (success) { - QCOMPARE(deviceInterface->icon()->surface(), iconSurfaceInterface); + QCOMPARE(m_seatInterface->dragIcon()->surface(), iconSurfaceInterface); } else { - QCOMPARE(deviceInterface->icon(), nullptr); + QCOMPARE(m_seatInterface->dragIcon(), nullptr); } } diff --git a/src/wayland/autotests/client/test_drag_drop.cpp b/src/wayland/autotests/client/test_drag_drop.cpp index fbede190e2..d4f7e43edd 100644 --- a/src/wayland/autotests/client/test_drag_drop.cpp +++ b/src/wayland/autotests/client/test_drag_drop.cpp @@ -11,6 +11,7 @@ #include "../../src/server/datasource_interface.h" #include "../../src/server/display.h" #include "../../src/server/seat_interface.h" +#include "../../src/server/seat_interface_p.h" #include "KWayland/Client/compositor.h" #include "KWayland/Client/connection_thread.h" #include "KWayland/Client/datadevice.h" @@ -230,8 +231,8 @@ void TestDragAndDrop::testPointerDragAndDrop() QVERIFY(dragStartedSpy.wait()); QCOMPARE(m_seatInterface->dragSurface(), serverSurface); QCOMPARE(m_seatInterface->dragSurfaceTransformation(), QMatrix4x4()); - QVERIFY(!m_seatInterface->dragSource()->icon()); - QCOMPARE(m_seatInterface->dragSource()->dragImplicitGrabSerial(), buttonPressSpy.first().first().value()); + QVERIFY(!m_seatInterface->dragIcon()); + QCOMPARE(SeatInterfacePrivate::get(m_seatInterface)->drag.dragImplicitGrabSerial, buttonPressSpy.first().first().value()); QVERIFY(dragEnteredSpy.wait()); QCOMPARE(dragEnteredSpy.count(), 1); QCOMPARE(dragEnteredSpy.first().first().value(), m_display->serial()); @@ -333,8 +334,8 @@ void TestDragAndDrop::testTouchDragAndDrop() QVERIFY(dragStartedSpy.wait()); QCOMPARE(m_seatInterface->dragSurface(), serverSurface); QCOMPARE(m_seatInterface->dragSurfaceTransformation(), QMatrix4x4()); - QVERIFY(!m_seatInterface->dragSource()->icon()); - QCOMPARE(m_seatInterface->dragSource()->dragImplicitGrabSerial(), tp->downSerial()); + QVERIFY(!m_seatInterface->dragIcon()); + QCOMPARE(SeatInterfacePrivate::get(m_seatInterface)->drag.dragImplicitGrabSerial, tp->downSerial()); QVERIFY(dragEnteredSpy.wait()); QCOMPARE(dragEnteredSpy.count(), 1); QCOMPARE(dragEnteredSpy.first().first().value(), m_display->serial()); @@ -428,8 +429,8 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource() QVERIFY(dragStartedSpy.wait()); QCOMPARE(m_seatInterface->dragSurface(), serverSurface); QCOMPARE(m_seatInterface->dragSurfaceTransformation(), QMatrix4x4()); - QVERIFY(!m_seatInterface->dragSource()->icon()); - QCOMPARE(m_seatInterface->dragSource()->dragImplicitGrabSerial(), buttonPressSpy.first().first().value()); + QVERIFY(!m_seatInterface->dragIcon()); + QCOMPARE(SeatInterfacePrivate::get(m_seatInterface)->drag.dragImplicitGrabSerial, buttonPressSpy.first().first().value()); QVERIFY(dragEnteredSpy.wait()); QCOMPARE(dragEnteredSpy.count(), 1); QCOMPARE(dragEnteredSpy.first().first().value(), m_display->serial()); diff --git a/src/wayland/datadevice_interface.cpp b/src/wayland/datadevice_interface.cpp index 04f2ba4631..6211f8d013 100644 --- a/src/wayland/datadevice_interface.cpp +++ b/src/wayland/datadevice_interface.cpp @@ -39,8 +39,8 @@ void DragAndDropIconPrivate::commit() position += surface()->offset(); } -DragAndDropIcon::DragAndDropIcon(SurfaceInterface *surface, QObject *parent) - : QObject(parent) +DragAndDropIcon::DragAndDropIcon(SurfaceInterface *surface) + : QObject(surface) , d(new DragAndDropIconPrivate(surface)) { } @@ -71,11 +71,6 @@ DataDeviceInterfacePrivate::DataDeviceInterfacePrivate(SeatInterface *seat, Data { } -void DataDeviceInterfacePrivate::endDrag() -{ - icon.reset(); -} - void DataDeviceInterfacePrivate::data_device_start_drag(Resource *resource, wl_resource *sourceResource, wl_resource *originResource, @@ -109,22 +104,14 @@ void DataDeviceInterfacePrivate::data_device_start_drag(Resource *resource, return; } } - // TODO: source is allowed to be null, handled client internally! - source = dataSource; - if (dataSource) { - QObject::connect(dataSource, &AbstractDataSource::aboutToBeDestroyed, q, [this] { - source = nullptr; - }); - } + + DragAndDropIcon *dragIcon = nullptr; if (iconSurface) { - icon.reset(new DragAndDropIcon(iconSurface)); - QObject::connect(iconSurface, &SurfaceInterface::aboutToBeDestroyed, icon.data(), [this] { - icon.reset(); - }); + // drag icon lifespan is mapped to surface lifespan + dragIcon = new DragAndDropIcon(iconSurface); } - surface = focusSurface; drag.serial = serial; - Q_EMIT q->dragStarted(); + Q_EMIT q->dragStarted(dataSource, focusSurface, serial, dragIcon); } void DataDeviceInterfacePrivate::data_device_set_selection(Resource *resource, wl_resource *source, uint32_t serial) @@ -198,21 +185,6 @@ SeatInterface *DataDeviceInterface::seat() const return d->seat; } -DataSourceInterface *DataDeviceInterface::dragSource() const -{ - return d->source; -} - -DragAndDropIcon *DataDeviceInterface::icon() const -{ - return d->icon.data(); -} - -SurfaceInterface *DataDeviceInterface::origin() const -{ - return d->proxyRemoteSurface ? d->proxyRemoteSurface.data() : d->surface; -} - DataSourceInterface *DataDeviceInterface::selection() const { return d->selection; @@ -267,23 +239,18 @@ void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 se } // don't update serial, we need it } - auto dragSourceDevice = d->seat->dragSource(); - if (!surface || !dragSourceDevice) { - if (auto s = dragSourceDevice->dragSource()) { + auto dragSource = d->seat->dragSource(); + if (!surface || !dragSource) { + if (auto s = dragSource) { s->dndAction(DataDeviceManagerInterface::DnDAction::None); } return; } - if (d->proxyRemoteSurface && d->proxyRemoteSurface == surface) { - // A proxy can not have the remote surface as target. - // TODO: do this for all client's surfaces? - return; + + if (dragSource) { + dragSource->accept(QString()); } - auto *source = dragSourceDevice->dragSource(); - if (source) { - source->setAccepted(false); - } - DataOfferInterface *offer = d->createDataOffer(source); + DataOfferInterface *offer = d->createDataOffer(dragSource); d->drag.surface = surface; if (d->seat->isDragPointer()) { d->drag.posConnection = connect(d->seat, &SeatInterface::pointerPosChanged, this, [this] { @@ -314,35 +281,30 @@ void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 se d->send_enter(serial, surface->resource(), wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()), offer ? offer->resource() : nullptr); if (offer) { offer->sendSourceActions(); - auto matchOffers = [source, offer] { + auto matchOffers = [dragSource, offer] { DataDeviceManagerInterface::DnDAction action{DataDeviceManagerInterface::DnDAction::None}; - if (source->supportedDragAndDropActions().testFlag(offer->preferredDragAndDropAction())) { + if (dragSource->supportedDragAndDropActions().testFlag(offer->preferredDragAndDropAction())) { action = offer->preferredDragAndDropAction(); } else { - if (source->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Copy) + if (dragSource->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Copy) && offer->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Copy)) { action = DataDeviceManagerInterface::DnDAction::Copy; - } else if (source->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Move) + } else if (dragSource->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Move) && offer->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Move)) { action = DataDeviceManagerInterface::DnDAction::Move; - } else if (source->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Ask) + } else if (dragSource->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Ask) && offer->supportedDragAndDropActions().testFlag(DataDeviceManagerInterface::DnDAction::Ask)) { action = DataDeviceManagerInterface::DnDAction::Ask; } } offer->dndAction(action); - source->dndAction(action); + dragSource->dndAction(action); }; - d->drag.targetActionConnection = connect(offer, &DataOfferInterface::dragAndDropActionsChanged, source, matchOffers); - d->drag.sourceActionConnection = connect(source, &DataSourceInterface::supportedDragAndDropActionsChanged, source, matchOffers); + d->drag.targetActionConnection = connect(offer, &DataOfferInterface::dragAndDropActionsChanged, dragSource, matchOffers); + d->drag.sourceActionConnection = connect(dragSource, &AbstractDataSource::supportedDragAndDropActionsChanged, dragSource, matchOffers); } } -quint32 DataDeviceInterface::dragImplicitGrabSerial() const -{ - return d->drag.serial; -} - void DataDeviceInterface::updateProxy(SurfaceInterface *remote) { // TODO: connect destroy signal? diff --git a/src/wayland/datadevice_interface.h b/src/wayland/datadevice_interface.h index d9515f23b8..d57e92e58e 100644 --- a/src/wayland/datadevice_interface.h +++ b/src/wayland/datadevice_interface.h @@ -49,7 +49,7 @@ public: SurfaceInterface *surface() const; private: - explicit DragAndDropIcon(SurfaceInterface *surface, QObject *parent = nullptr); + explicit DragAndDropIcon(SurfaceInterface *surface); friend class DataDeviceInterfacePrivate; QScopedPointer d; }; @@ -72,18 +72,6 @@ public: virtual ~DataDeviceInterface(); SeatInterface *seat() const; - DataSourceInterface *dragSource() const; - SurfaceInterface *origin() const; - /** - * Returns the additional icon attached to the cursor during a drag-and-drop operation. - * This function returns @c null if no drag-and-drop icon has been attached. - */ - DragAndDropIcon *icon() const; - - /** - * @returns the serial of the implicit grab which started the drag - */ - quint32 dragImplicitGrabSerial() const; DataSourceInterface *selection() const; @@ -105,16 +93,13 @@ public: * @param serial The serial to be used for enter/leave */ void updateDragTarget(SurfaceInterface *surface, quint32 serial); - /** - * Mark this DataDeviceInterface as being a proxy device for @p remote. - */ void updateProxy(SurfaceInterface *remote); wl_client *client(); Q_SIGNALS: void aboutToBeDestroyed(); - void dragStarted(); + void dragStarted(AbstractDataSource *source, SurfaceInterface *originSurface, quint32 serial, DragAndDropIcon *dragIcon); void selectionChanged(KWaylandServer::DataSourceInterface *); void selectionCleared(); diff --git a/src/wayland/datadevice_interface_p.h b/src/wayland/datadevice_interface_p.h index e2a4f26395..e70b8f6851 100644 --- a/src/wayland/datadevice_interface_p.h +++ b/src/wayland/datadevice_interface_p.h @@ -29,13 +29,9 @@ public: DataDeviceInterfacePrivate(SeatInterface *seat, DataDeviceInterface *_q, wl_resource *resource); DataOfferInterface *createDataOffer(AbstractDataSource *source); - void endDrag(); SeatInterface *seat; DataDeviceInterface *q; - DataSourceInterface *source = nullptr; - SurfaceInterface *surface = nullptr; - QScopedPointer icon; QPointer selection; QPointer proxyRemoteSurface; diff --git a/src/wayland/datasource_interface.cpp b/src/wayland/datasource_interface.cpp index c7a07ebb6d..417ee7d100 100644 --- a/src/wayland/datasource_interface.cpp +++ b/src/wayland/datasource_interface.cpp @@ -118,7 +118,9 @@ void DataSourceInterface::requestData(const QString &mimeType, qint32 fd) void DataSourceInterface::cancel() { - d->send_cancelled(); + if (wl_resource_get_version(resource()) >= WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { + d->send_cancelled(); + } } QStringList DataSourceInterface::mimeTypes() const diff --git a/src/wayland/datasource_interface.h b/src/wayland/datasource_interface.h index 3ed1de3d54..5db7d45bb1 100644 --- a/src/wayland/datasource_interface.h +++ b/src/wayland/datasource_interface.h @@ -46,7 +46,7 @@ public: wl_client *client() const override; - bool isAccepted() const; + bool isAccepted() const override; void setAccepted(bool accepted); private: diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp index 0ea64f15b1..831e4256fa 100644 --- a/src/wayland/seat_interface.cpp +++ b/src/wayland/seat_interface.cpp @@ -171,42 +171,12 @@ void SeatInterfacePrivate::registerDataDevice(DataDeviceInterface *dataDevice) QObject::connect(dataDevice, &DataDeviceInterface::selectionCleared, q, [this, dataDevice] { updateSelection(dataDevice); }); - QObject::connect(dataDevice, &DataDeviceInterface::dragStarted, q, [this, dataDevice] { - const auto dragSerial = dataDevice->dragImplicitGrabSerial(); - if (q->hasImplicitPointerGrab(dragSerial)) { - drag.mode = Drag::Mode::Pointer; - drag.transformation = globalPointer.focus.transformation; - } else if (q->hasImplicitTouchGrab(dragSerial)) { - drag.mode = Drag::Mode::Touch; - // TODO: touch transformation - } else { - // no implicit grab, abort drag - return; - } - auto *originSurface = dataDevice->origin(); - const bool proxied = originSurface->dataProxy(); - if (!proxied) { - // origin surface - drag.target = dataDevice; - drag.surface = originSurface; - // TODO: transformation needs to be either pointer or touch - drag.transformation = globalPointer.focus.transformation; - } - drag.source = dataDevice; - drag.destroyConnection = QObject::connect(dataDevice, &DataDeviceInterface::aboutToBeDestroyed, q, [this] { - cancelDrag(display->nextSerial()); - }); - if (dataDevice->dragSource()) { - drag.dragSourceDestroyConnection = QObject::connect(dataDevice->dragSource(), &AbstractDataSource::aboutToBeDestroyed, q, [this] { - cancelDrag(display->nextSerial()); - }); - } else { - drag.dragSourceDestroyConnection = QMetaObject::Connection(); - } - dataDevice->updateDragTarget(proxied ? nullptr : originSurface, dataDevice->dragImplicitGrabSerial()); - Q_EMIT q->dragStarted(); - Q_EMIT q->dragSurfaceChanged(); - }); + QObject::connect(dataDevice, + &DataDeviceInterface::dragStarted, + q, + [this](AbstractDataSource *source, SurfaceInterface *origin, quint32 serial, DragAndDropIcon *dragIcon) { + q->startDrag(source, origin, serial, dragIcon); + }); // is the new DataDevice for the current keyoard focus? if (globalKeyboard.focus.surface) { // same client? @@ -303,12 +273,10 @@ void SeatInterfacePrivate::cancelDrag(quint32 serial) void SeatInterfacePrivate::endDrag(quint32 serial) { - QObject::disconnect(drag.destroyConnection); QObject::disconnect(drag.dragSourceDestroyConnection); DataDeviceInterface *dragTargetDevice = drag.target; - DataDeviceInterface *dragSourceDevice = drag.source; - DataSourceInterface *dragSource = dragSourceDevice ? dragSourceDevice->dragSource() : nullptr; + AbstractDataSource *dragSource = drag.source; if (dragSource) { // TODO: Also check the current drag-and-drop action. if (dragTargetDevice && dragSource->isAccepted()) { @@ -316,19 +284,13 @@ void SeatInterfacePrivate::endDrag(quint32 serial) dragTargetDevice->drop(); dragSource->dropPerformed(); } else { - if (wl_resource_get_version(dragSource->resource()) >= WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { - dragSource->cancel(); - } + dragSource->cancel(); } } if (dragTargetDevice) { dragTargetDevice->updateDragTarget(nullptr, serial); } - if (dragSourceDevice) { - auto devicePrivate = DataDeviceInterfacePrivate::get(dragSourceDevice); - devicePrivate->endDrag(); - } drag = Drag(); Q_EMIT q->dragSurfaceChanged(); @@ -486,12 +448,10 @@ void SeatInterface::notifyPointerMotion(const QPointF &pos) return; } if (isDragPointer()) { - const auto *originSurface = dragSource()->origin(); - const bool proxyRemoteFocused = originSurface->dataProxy() && originSurface == focusedSurface; - if (!proxyRemoteFocused) { - // handled by DataDevice + // data device will handle it directly + // for xwayland cases we still want to send pointer events + if (!d->dataDevicesForSurface(focusedSurface).isEmpty()) return; - } } if (focusedSurface->lockedPointer() && focusedSurface->lockedPointer()->isLocked()) { return; @@ -743,7 +703,7 @@ void SeatInterface::notifyPointerButton(quint32 button, PointerButtonState state d->updatePointerButtonSerial(button, serial); d->updatePointerButtonState(button, SeatInterfacePrivate::Pointer::State::Released); if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) { - if (d->drag.source->dragImplicitGrabSerial() != currentButtonSerial) { + if (d->drag.dragImplicitGrabSerial != currentButtonSerial) { // not our drag button - ignore return; } @@ -1100,7 +1060,7 @@ void SeatInterface::notifyTouchUp(qint32 id) } Q_ASSERT(d->globalTouch.ids.contains(id)); const qint32 serial = d->display->nextSerial(); - if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->drag.source->dragImplicitGrabSerial() == d->globalTouch.ids.value(id)) { + if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->drag.dragImplicitGrabSerial == d->globalTouch.ids.value(id)) { // the implicitly grabbing touch point has been upped d->endDrag(serial); } @@ -1174,7 +1134,7 @@ SurfaceInterface *SeatInterface::dragSurface() const return d->drag.surface; } -DataDeviceInterface *SeatInterface::dragSource() const +AbstractDataSource *SeatInterface::dragSource() const { return d->drag.source; } @@ -1305,4 +1265,45 @@ void SeatInterface::setPrimarySelection(AbstractDataSource *selection) Q_EMIT primarySelectionChanged(selection); } +void SeatInterface::startDrag(AbstractDataSource *dragSource, SurfaceInterface *originSurface, int dragSerial, DragAndDropIcon *dragIcon) +{ + if (hasImplicitPointerGrab(dragSerial)) { + d->drag.mode = SeatInterfacePrivate::Drag::Mode::Pointer; + d->drag.transformation = d->globalPointer.focus.transformation; + } else if (hasImplicitTouchGrab(dragSerial)) { + d->drag.mode = SeatInterfacePrivate::Drag::Mode::Touch; + // TODO: touch transformation + } else { + // no implicit grab, abort drag + return; + } + d->drag.dragImplicitGrabSerial = dragSerial; + + // set initial drag target to ourself + d->drag.surface = originSurface; + // TODO: transformation needs to be either pointer or touch + d->drag.transformation = d->globalPointer.focus.transformation; + + d->drag.source = dragSource; + if (dragSource) { + d->drag.dragSourceDestroyConnection = QObject::connect(dragSource, &AbstractDataSource::aboutToBeDestroyed, this, [this] { + d->cancelDrag(d->display->nextSerial()); + }); + } + d->drag.dragIcon = dragIcon; + + if (!d->dataDevicesForSurface(originSurface).isEmpty()) { + d->drag.target = d->dataDevicesForSurface(originSurface)[0]; + } + if (d->drag.target) { + d->drag.target->updateDragTarget(originSurface, dragSerial); + } + Q_EMIT dragStarted(); + Q_EMIT dragSurfaceChanged(); +} + +DragAndDropIcon *SeatInterface::dragIcon() const +{ + return d->drag.dragIcon; +} } diff --git a/src/wayland/seat_interface.h b/src/wayland/seat_interface.h index b1fe83ddcc..62da215f41 100644 --- a/src/wayland/seat_interface.h +++ b/src/wayland/seat_interface.h @@ -18,6 +18,7 @@ struct wl_resource; namespace KWaylandServer { class AbstractDataSource; +class DragAndDropIcon; class DataDeviceInterface; class Display; class KeyboardInterface; @@ -208,7 +209,7 @@ public: * @returns The DataDeviceInterface which started the drag and drop operation. * @see isDrag */ - DataDeviceInterface *dragSource() const; + KWaylandServer::AbstractDataSource *dragSource() const; /** * Sets the current drag target to @p surface. * @@ -618,6 +619,14 @@ public: KWaylandServer::AbstractDataSource *primarySelection() const; void setPrimarySelection(AbstractDataSource *selection); + void startDrag(AbstractDataSource *source, SurfaceInterface *sourceSurface, int dragSerial = -1, DragAndDropIcon *dragIcon = nullptr); + + /** + * Returns the additional icon attached to the cursor during a drag-and-drop operation. + * This function returns @c null if no drag-and-drop is active or no icon has been attached. + */ + DragAndDropIcon *dragIcon() const; + static SeatInterface *get(wl_resource *native); Q_SIGNALS: diff --git a/src/wayland/seat_interface_p.h b/src/wayland/seat_interface_p.h index 924f0c4af8..78992968f4 100644 --- a/src/wayland/seat_interface_p.h +++ b/src/wayland/seat_interface_p.h @@ -25,11 +25,13 @@ class DataControlDeviceV1Interface; class TextInputV2Interface; class TextInputV3Interface; class PrimarySelectionDeviceV1Interface; +class DragAndDropIcon; class SeatInterfacePrivate : public QtWaylandServer::wl_seat { public: - static SeatInterfacePrivate *get(SeatInterface *seat); + // exported for unit tests + KWAYLANDSERVER_EXPORT static SeatInterfacePrivate *get(SeatInterface *seat); SeatInterfacePrivate(SeatInterface *q, Display *display); void sendCapabilities(); @@ -119,11 +121,12 @@ public: Touch, }; Mode mode = Mode::None; - DataDeviceInterface *source = nullptr; + AbstractDataSource *source = nullptr; + QPointer surface; QPointer target; - SurfaceInterface *surface = nullptr; + QPointer dragIcon; QMatrix4x4 transformation; - QMetaObject::Connection destroyConnection; + quint32 dragImplicitGrabSerial = -1; QMetaObject::Connection dragSourceDestroyConnection; }; Drag drag; diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp index 1bc3ca350d..74a6929a68 100644 --- a/src/wayland/surface_interface.cpp +++ b/src/wayland/surface_interface.cpp @@ -936,16 +936,6 @@ bool SurfaceInterface::inhibitsIdle() const return !d->idleInhibitors.isEmpty(); } -void SurfaceInterface::setDataProxy(SurfaceInterface *surface) -{ - d->dataProxy = surface; -} - -SurfaceInterface *SurfaceInterface::dataProxy() const -{ - return d->dataProxy; -} - QPointF SurfaceInterface::mapToBuffer(const QPointF &point) const { return d->surfaceToBufferMatrix.map(point); diff --git a/src/wayland/surface_interface.h b/src/wayland/surface_interface.h index 7b0302d2d2..6479f948e9 100644 --- a/src/wayland/surface_interface.h +++ b/src/wayland/surface_interface.h @@ -310,20 +310,6 @@ public: */ static SurfaceInterface *get(quint32 id, const ClientConnection *client); - /** - * Set @p surface as a data proxy for this SurfaceInterface. This enables - * the proxy to conduct drags on the surface's client behalf. - * - * Setting a data proxy is only allowed when the client owning this surface - * has not created a data device itself. - */ - void setDataProxy(SurfaceInterface *surface); - /** - * Returns the data proxy of this SurfaceInterface or null if there - * is none set. - */ - SurfaceInterface *dataProxy() const; - Q_SIGNALS: /** * This signal is emitted when the underlying wl_surface resource is about to be freed. diff --git a/src/wayland/surface_interface_p.h b/src/wayland/surface_interface_p.h index 4f27529de9..a3c1ff59ca 100644 --- a/src/wayland/surface_interface_p.h +++ b/src/wayland/surface_interface_p.h @@ -119,7 +119,6 @@ public: QVector idleInhibitors; ViewportInterface *viewportExtension = nullptr; - SurfaceInterface *dataProxy = nullptr; ClientConnection *client = nullptr; protected: