diff --git a/src/wayland/abstract_data_source.cpp b/src/wayland/abstract_data_source.cpp index a410f56a45..f7e8cea244 100644 --- a/src/wayland/abstract_data_source.cpp +++ b/src/wayland/abstract_data_source.cpp @@ -8,6 +8,6 @@ using namespace KWaylandServer; -AbstractDataSource::AbstractDataSource(Resource::Private *d, QObject *parent) - : Resource(d, parent) +AbstractDataSource::AbstractDataSource(QObject *parent) + : QObject(parent) {} diff --git a/src/wayland/abstract_data_source.h b/src/wayland/abstract_data_source.h index 9762af600e..f58afcc6dd 100644 --- a/src/wayland/abstract_data_source.h +++ b/src/wayland/abstract_data_source.h @@ -27,10 +27,7 @@ namespace KWaylandServer { // Anything related to selections are pure virtual, content relating // to drag and drop has a default implementation - -// TODO ideally this shouldn't inherit from resource as it provides some misleading public methods -// This can be resolved once DataSource is ported to the new system -class KWAYLANDSERVER_EXPORT AbstractDataSource : public Resource +class KWAYLANDSERVER_EXPORT AbstractDataSource : public QObject { Q_OBJECT public: @@ -64,16 +61,18 @@ public: Q_UNUSED(action); }; - virtual wl_client* client() { - return Resource::client()->client(); - } + virtual wl_client* client() const { + return nullptr; + }; Q_SIGNALS: + void aboutToBeDestroyed(); + void mimeTypeOffered(const QString&); void supportedDragAndDropActionsChanged(); protected: - explicit AbstractDataSource(Resource::Private *d, QObject *parent = nullptr); + explicit AbstractDataSource(QObject *parent = nullptr); }; } diff --git a/src/wayland/autotests/client/test_datadevice.cpp b/src/wayland/autotests/client/test_datadevice.cpp index e1e79d451d..a0db9b5b3d 100644 --- a/src/wayland/autotests/client/test_datadevice.cpp +++ b/src/wayland/autotests/client/test_datadevice.cpp @@ -27,6 +27,8 @@ // Wayland #include +#include + class TestDataDevice : public QObject { Q_OBJECT @@ -101,8 +103,6 @@ void TestDataDevice::init() registry.setup(); m_dataDeviceManagerInterface = m_display->createDataDeviceManager(m_display); - m_dataDeviceManagerInterface->create(); - QVERIFY(m_dataDeviceManagerInterface->isValid()); QVERIFY(dataDeviceManagerSpy.wait()); m_dataDeviceManager = registry.createDataDeviceManager(dataDeviceManagerSpy.first().first().value(), @@ -179,8 +179,6 @@ void TestDataDevice::testCreate() QVERIFY(!deviceInterface->origin()); QVERIFY(!deviceInterface->icon()); QVERIFY(!deviceInterface->selection()); - QVERIFY(deviceInterface->parentResource()); - // this will probably fail, we need to make a selection client side QVERIFY(!m_seatInterface->selection()); @@ -433,12 +431,10 @@ void TestDataDevice::testSetSelection() dataDevice->setSelection(2, dataSource.data()); QVERIFY(selectionChangedSpy.wait()); // now unbind the dataDevice - QSignalSpy unboundSpy(deviceInterface, &DataDeviceInterface::unbound); + QSignalSpy unboundSpy(deviceInterface, &QObject::destroyed); QVERIFY(unboundSpy.isValid()); dataDevice.reset(); QVERIFY(unboundSpy.wait()); - // send a selection to the unbound data device - deviceInterface->sendSelection(deviceInterface->selection()); } void TestDataDevice::testSendSelectionOnSeat() @@ -491,7 +487,7 @@ void TestDataDevice::testSendSelectionOnSeat() // now let's try to destroy the data device and set a focused keyboard just while the data device is being destroyedd m_seatInterface->setFocusedKeyboardSurface(nullptr); - QSignalSpy unboundSpy(serverDataDevice, &Resource::unbound); + QSignalSpy unboundSpy(serverDataDevice, &QObject::destroyed); QVERIFY(unboundSpy.isValid()); dataDevice.reset(); QVERIFY(unboundSpy.wait()); @@ -575,6 +571,21 @@ void TestDataDevice::testReplaceSource() dataSource3.reset(); dataDevice2->setSelection(1, dataSource4.data()); QVERIFY(selectionOfferedSpy.wait()); + + auto dataOffer = selectionOfferedSpy.last()[0].value(); + + // try to crash by destroying the data source, then requesting data + dataSource4.reset(); + int pipeFds[2]; + Q_ASSERT(pipe(pipeFds) == 0); + + dataOffer->receive(QStringLiteral("text/plain"), pipeFds[1]); + close(pipeFds[1]); + + //spin the event loop, nothing should explode + QTest::qWait(10); + + close(pipeFds[0]); } void TestDataDevice::testDestroy() diff --git a/src/wayland/autotests/client/test_datasource.cpp b/src/wayland/autotests/client/test_datasource.cpp index 4a8bca3ff7..fde3f2d272 100644 --- a/src/wayland/autotests/client/test_datasource.cpp +++ b/src/wayland/autotests/client/test_datasource.cpp @@ -29,7 +29,6 @@ private Q_SLOTS: void testTargetAccepts_data(); void testTargetAccepts(); void testRequestSend(); - void testRequestSendOnUnbound(); void testCancel(); void testServerGet(); void testDestroy(); @@ -82,8 +81,6 @@ void TestDataSource::init() registry.setup(); m_dataDeviceManagerInterface = m_display->createDataDeviceManager(m_display); - m_dataDeviceManagerInterface->create(); - QVERIFY(m_dataDeviceManagerInterface->isValid()); QVERIFY(dataDeviceManagerSpy.wait()); m_dataDeviceManager = registry.createDataDeviceManager(dataDeviceManagerSpy.first().first().value(), @@ -131,7 +128,6 @@ void TestDataSource::testOffer() QPointer serverDataSource = dataSourceCreatedSpy.first().first().value(); QVERIFY(!serverDataSource.isNull()); QCOMPARE(serverDataSource->mimeTypes().count(), 0); - QVERIFY(serverDataSource->parentResource()); QSignalSpy offeredSpy(serverDataSource.data(), SIGNAL(mimeTypeOffered(QString))); QVERIFY(offeredSpy.isValid()); @@ -161,10 +157,6 @@ void TestDataSource::testOffer() dataSource.reset(); QVERIFY(!serverDataSource.isNull()); wl_display_flush(m_connection->display()); - // after running the event loop the Wayland event should be delivered, but it uses delete later - QCoreApplication::processEvents(); - QVERIFY(!serverDataSource.isNull()); - // so once more event loop QCoreApplication::processEvents(); QVERIFY(serverDataSource.isNull()); } @@ -212,7 +204,6 @@ void TestDataSource::testRequestSend() QScopedPointer dataSource(m_dataDeviceManager->createDataSource()); QVERIFY(dataSource->isValid()); - QSignalSpy sendRequestedSpy(dataSource.data(), SIGNAL(sendDataRequested(QString,qint32))); QVERIFY(sendRequestedSpy.isValid()); @@ -234,28 +225,6 @@ void TestDataSource::testRequestSend() writeFile.close(); } -void TestDataSource::testRequestSendOnUnbound() -{ - // this test verifies that the server doesn't crash when requesting a send on an unbound DataSource - using namespace KWayland::Client; - using namespace KWaylandServer; - QSignalSpy dataSourceCreatedSpy(m_dataDeviceManagerInterface, &DataDeviceManagerInterface::dataSourceCreated); - QVERIFY(dataSourceCreatedSpy.isValid()); - - QScopedPointer dataSource(m_dataDeviceManager->createDataSource()); - QVERIFY(dataSource->isValid()); - QVERIFY(dataSourceCreatedSpy.wait()); - QCOMPARE(dataSourceCreatedSpy.count(), 1); - auto sds = dataSourceCreatedSpy.first().first().value(); - QVERIFY(sds); - - QSignalSpy unboundSpy(sds, &Resource::unbound); - QVERIFY(unboundSpy.isValid()); - dataSource.reset(); - QVERIFY(unboundSpy.wait()); - sds->requestData(QStringLiteral("text/plain"), -1); -} - void TestDataSource::testCancel() { using namespace KWayland::Client; diff --git a/src/wayland/autotests/client/test_drag_drop.cpp b/src/wayland/autotests/client/test_drag_drop.cpp index b67c2a9409..384cac7162 100644 --- a/src/wayland/autotests/client/test_drag_drop.cpp +++ b/src/wayland/autotests/client/test_drag_drop.cpp @@ -84,8 +84,6 @@ void TestDragAndDrop::init() m_seatInterface->create(); QVERIFY(m_seatInterface->isValid()); m_dataDeviceManagerInterface = m_display->createDataDeviceManager(m_display); - m_dataDeviceManagerInterface->create(); - QVERIFY(m_dataDeviceManagerInterface->isValid()); m_display->createShm(); m_thread = new QThread(this); diff --git a/src/wayland/autotests/client/test_selection.cpp b/src/wayland/autotests/client/test_selection.cpp index 8600a890c3..b8804018ba 100644 --- a/src/wayland/autotests/client/test_selection.cpp +++ b/src/wayland/autotests/client/test_selection.cpp @@ -72,7 +72,6 @@ void SelectionTest::init() m_seatInterface->setHasKeyboard(true); m_seatInterface->create(); m_ddmInterface = m_display->createDataDeviceManager(m_display); - m_ddmInterface->create(); // setup connection setupConnection(&m_client1); diff --git a/src/wayland/autotests/client/test_wayland_seat.cpp b/src/wayland/autotests/client/test_wayland_seat.cpp index ed3c61fc44..1fb0abd0bd 100644 --- a/src/wayland/autotests/client/test_wayland_seat.cpp +++ b/src/wayland/autotests/client/test_wayland_seat.cpp @@ -1814,7 +1814,6 @@ void TestWaylandSeat::testSelection() using namespace KWayland::Client; using namespace KWaylandServer; QScopedPointer ddmi(m_display->createDataDeviceManager()); - ddmi->create(); Registry registry; QSignalSpy dataDeviceManagerSpy(®istry, SIGNAL(dataDeviceManagerAnnounced(quint32,quint32))); QVERIFY(dataDeviceManagerSpy.isValid()); @@ -1927,7 +1926,6 @@ void TestWaylandSeat::testDataDeviceForKeyboardSurface() using namespace KWaylandServer; // create the DataDeviceManager QScopedPointer ddmi(m_display->createDataDeviceManager()); - ddmi->create(); QSignalSpy ddiCreatedSpy(ddmi.data(), &DataDeviceManagerInterface::dataDeviceCreated); QVERIFY(ddiCreatedSpy.isValid()); diff --git a/src/wayland/autotests/server/test_datacontrol_interface.cpp b/src/wayland/autotests/server/test_datacontrol_interface.cpp index db1d84bfc3..79bd084071 100644 --- a/src/wayland/autotests/server/test_datacontrol_interface.cpp +++ b/src/wayland/autotests/server/test_datacontrol_interface.cpp @@ -110,7 +110,7 @@ public: AbstractDataSource(nullptr) {} ~TestDataSource() { - emit unbound(); + emit aboutToBeDestroyed(); } void requestData(const QString &mimeType, qint32 fd) override { Q_UNUSED(mimeType); diff --git a/src/wayland/datacontrolsource_v1_interface.cpp b/src/wayland/datacontrolsource_v1_interface.cpp index 05a68c1d2b..2056940edb 100644 --- a/src/wayland/datacontrolsource_v1_interface.cpp +++ b/src/wayland/datacontrolsource_v1_interface.cpp @@ -40,7 +40,7 @@ DataControlSourceV1InterfacePrivate::DataControlSourceV1InterfacePrivate(DataCon void DataControlSourceV1InterfacePrivate::zwlr_data_control_source_v1_destroy_resource(QtWaylandServer::zwlr_data_control_source_v1::Resource *resource) { Q_UNUSED(resource) - emit q->unbound(); + emit q->aboutToBeDestroyed(); delete q; } @@ -56,7 +56,7 @@ void DataControlSourceV1InterfacePrivate::zwlr_data_control_source_v1_destroy(Qt } DataControlSourceV1Interface::DataControlSourceV1Interface(DataControlDeviceManagerV1Interface *parent, ::wl_resource *resource) - : AbstractDataSource(nullptr, parent) + : AbstractDataSource(parent) , d(new DataControlSourceV1InterfacePrivate(this, resource)) { } @@ -79,7 +79,7 @@ QStringList DataControlSourceV1Interface::mimeTypes() const return d->mimeTypes; } -wl_client *DataControlSourceV1Interface::client() +wl_client *DataControlSourceV1Interface::client() const { return d->resource()->client(); } diff --git a/src/wayland/datacontrolsource_v1_interface.h b/src/wayland/datacontrolsource_v1_interface.h index b3c275a932..352d325c02 100644 --- a/src/wayland/datacontrolsource_v1_interface.h +++ b/src/wayland/datacontrolsource_v1_interface.h @@ -33,7 +33,7 @@ public: void cancel() override; QStringList mimeTypes() const override; - wl_client *client() override; + wl_client *client() const override; static DataControlSourceV1Interface *get(wl_resource *native); diff --git a/src/wayland/datadevice_interface.cpp b/src/wayland/datadevice_interface.cpp index 6805709ff0..c3505bd960 100644 --- a/src/wayland/datadevice_interface.cpp +++ b/src/wayland/datadevice_interface.cpp @@ -1,28 +1,28 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "datadevice_interface.h" #include "datadevicemanager_interface.h" -#include "dataoffer_interface_p.h" #include "datasource_interface.h" +#include "dataoffer_interface.h" #include "display.h" #include "resource_p.h" #include "pointer_interface.h" #include "seat_interface.h" +#include "seat_interface_p.h" #include "surface_interface.h" -// Wayland -#include +#include namespace KWaylandServer { -class DataDeviceInterface::Private : public Resource::Private +class DataDeviceInterfacePrivate : public QtWaylandServer::wl_data_device { public: - Private(SeatInterface *seat, DataDeviceInterface *q, DataDeviceManagerInterface *manager, wl_resource *parentResource); - ~Private(); + DataDeviceInterfacePrivate(SeatInterface *seat, DataDeviceInterface *_q, wl_resource *resource); DataOfferInterface *createDataOffer(AbstractDataSource *source); @@ -31,9 +31,7 @@ public: SurfaceInterface *surface = nullptr; SurfaceInterface *icon = nullptr; - DataSourceInterface *selection = nullptr; - QMetaObject::Connection selectionUnboundConnection; - QMetaObject::Connection selectionDestroyedConnection; + QPointer selection; struct Drag { SurfaceInterface *surface = nullptr; @@ -45,47 +43,34 @@ public: }; Drag drag; + DataDeviceInterface *q; + QPointer proxyRemoteSurface; -private: - DataDeviceInterface *q_func() { - return reinterpret_cast(q); - } - void startDrag(DataSourceInterface *dataSource, SurfaceInterface *origin, SurfaceInterface *icon, quint32 serial); - void setSelection(DataSourceInterface *dataSource); - static void startDragCallback(wl_client *client, wl_resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial); - static void setSelectionCallback(wl_client *client, wl_resource *resource, wl_resource *source, uint32_t serial); - - static const struct wl_data_device_interface s_interface; +protected: + void data_device_destroy_resource(Resource *resource) override; + void data_device_start_drag(Resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial) override; + void data_device_set_selection(Resource *resource, wl_resource *source, uint32_t serial) override; + void data_device_release(Resource *resource) override; }; -#ifndef K_DOXYGEN -const struct wl_data_device_interface DataDeviceInterface::Private::s_interface = { - startDragCallback, - setSelectionCallback, - resourceDestroyedCallback -}; -#endif - -DataDeviceInterface::Private::Private(SeatInterface *seat, DataDeviceInterface *q, DataDeviceManagerInterface *manager, wl_resource *parentResource) - : Resource::Private(q, manager, parentResource, &wl_data_device_interface, &s_interface) +DataDeviceInterfacePrivate::DataDeviceInterfacePrivate(SeatInterface *seat, DataDeviceInterface *_q, wl_resource *resource) + : QtWaylandServer::wl_data_device(resource) , seat(seat) + , q(_q) { } -DataDeviceInterface::Private::~Private() = default; - -void DataDeviceInterface::Private::startDragCallback(wl_client *client, wl_resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial) +void DataDeviceInterfacePrivate::data_device_start_drag(Resource *resource, wl_resource *sourceResource, wl_resource *originResource, wl_resource *iconResource, uint32_t serial) { - Q_UNUSED(client) - Q_UNUSED(serial) - // TODO: verify serial - cast(resource)->startDrag(DataSourceInterface::get(source), SurfaceInterface::get(origin), SurfaceInterface::get(icon), serial); -} + Q_UNUSED(resource) + SurfaceInterface *focusSurface = SurfaceInterface::get(originResource); + SurfaceInterface *i = SurfaceInterface::get(iconResource); + DataSourceInterface *dataSource = nullptr; + if (sourceResource) { + dataSource = DataSourceInterface::get(sourceResource); + } -void DataDeviceInterface::Private::startDrag(DataSourceInterface *dataSource, SurfaceInterface *origin, SurfaceInterface *i, quint32 serial) -{ - SurfaceInterface *focusSurface = origin; if (proxyRemoteSurface) { // origin is a proxy surface focusSurface = proxyRemoteSurface.data(); @@ -100,144 +85,123 @@ void DataDeviceInterface::Private::startDrag(DataSourceInterface *dataSource, Su } } // TODO: source is allowed to be null, handled client internally! - Q_Q(DataDeviceInterface); source = dataSource; if (dataSource) { - QObject::connect(dataSource, &Resource::aboutToBeUnbound, q, [this] { source = nullptr; }); + QObject::connect(dataSource, &AbstractDataSource::aboutToBeDestroyed, q, [this] { source = nullptr; }); } - surface = origin; + surface = focusSurface; icon = i; drag.serial = serial; emit q->dragStarted(); } -void DataDeviceInterface::Private::setSelectionCallback(wl_client *client, wl_resource *resource, wl_resource *source, uint32_t serial) +void DataDeviceInterfacePrivate::data_device_set_selection(Resource *resource, wl_resource *source, uint32_t serial) { - Q_UNUSED(client) + Q_UNUSED(resource) Q_UNUSED(serial) - // TODO: verify serial - cast(resource)->setSelection(DataSourceInterface::get(source)); -} + DataSourceInterface *dataSource = DataSourceInterface::get(source); -void DataDeviceInterface::Private::setSelection(DataSourceInterface *dataSource) -{ if (dataSource && dataSource->supportedDragAndDropActions() && wl_resource_get_version(dataSource->resource()) >= WL_DATA_SOURCE_ACTION_SINCE_VERSION) { - wl_resource_post_error(dataSource->resource(), WL_DATA_SOURCE_ERROR_INVALID_SOURCE, "Data source is for drag and drop"); + wl_resource_post_error(dataSource->resource(), QtWaylandServer::wl_data_source::error_invalid_source, "Data source is for drag and drop"); return; } + if (selection == dataSource) { return; } - Q_Q(DataDeviceInterface); - QObject::disconnect(selectionUnboundConnection); - QObject::disconnect(selectionDestroyedConnection); if (selection) { selection->cancel(); } selection = dataSource; if (selection) { - auto clearSelection = [this] { - setSelection(nullptr); - }; - selectionUnboundConnection = QObject::connect(selection, &Resource::unbound, q, clearSelection); - selectionDestroyedConnection = QObject::connect(selection, &QObject::destroyed, q, clearSelection); emit q->selectionChanged(selection); } else { - selectionUnboundConnection = QMetaObject::Connection(); - selectionDestroyedConnection = QMetaObject::Connection(); emit q->selectionCleared(); } } -DataOfferInterface *DataDeviceInterface::Private::createDataOffer(AbstractDataSource *source) +void DataDeviceInterfacePrivate::data_device_release(QtWaylandServer::wl_data_device::Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + + +DataOfferInterface *DataDeviceInterfacePrivate::createDataOffer(AbstractDataSource *source) { - if (!resource) { - return nullptr; - } if (!source) { // a data offer can only exist together with a source return nullptr; } - Q_Q(DataDeviceInterface); - DataOfferInterface *offer = new DataOfferInterface(source, q, resource); - auto c = q->global()->display()->getConnection(wl_resource_get_client(resource)); - offer->create(c, wl_resource_get_version(resource), 0); - if (!offer->resource()) { - // TODO: send error? - delete offer; + + wl_resource *data_offer_resource = wl_resource_create(resource()->client(), &wl_data_offer_interface, resource()->version(), 0); + if (!data_offer_resource) { + wl_resource_post_no_memory(resource()->handle); return nullptr; } - wl_data_device_send_data_offer(resource, offer->resource()); + + DataOfferInterface *offer = new DataOfferInterface(source, data_offer_resource); + send_data_offer(offer->resource()); offer->sendAllOffers(); return offer; } -DataDeviceInterface::DataDeviceInterface(SeatInterface *seat, DataDeviceManagerInterface *parent, wl_resource *parentResource) - : Resource(new Private(seat, this, parent, parentResource)) +void DataDeviceInterfacePrivate::data_device_destroy_resource(QtWaylandServer::wl_data_device::Resource *resource) { + Q_UNUSED(resource) + delete q; +} + +DataDeviceInterface::DataDeviceInterface(SeatInterface *seat, wl_resource *resource) + : QObject(nullptr) + , d(new DataDeviceInterfacePrivate(seat, this, resource)) +{ + seat->d_func()->registerDataDevice(this); } DataDeviceInterface::~DataDeviceInterface() = default; SeatInterface *DataDeviceInterface::seat() const { - Q_D(); return d->seat; } DataSourceInterface *DataDeviceInterface::dragSource() const { - Q_D(); return d->source; } SurfaceInterface *DataDeviceInterface::icon() const { - Q_D(); return d->icon; } SurfaceInterface *DataDeviceInterface::origin() const { - Q_D(); return d->proxyRemoteSurface ? d->proxyRemoteSurface.data() : d->surface; } DataSourceInterface *DataDeviceInterface::selection() const { - Q_D(); return d->selection; } void DataDeviceInterface::sendSelection(AbstractDataSource *other) { - Q_D(); auto r = d->createDataOffer(other); if (!r) { return; } - if (!d->resource) { - return; - } - wl_data_device_send_selection(d->resource, r->resource()); + d->send_selection(r->resource()); } void DataDeviceInterface::sendClearSelection() { - Q_D(); - if (!d->resource) { - return; - } - wl_data_device_send_selection(d->resource, nullptr); + d->send_selection(nullptr); } void DataDeviceInterface::drop() { - Q_D(); - if (!d->resource) { - return; - } - wl_data_device_send_drop(d->resource); + d->send_drop(); if (d->drag.posConnection) { disconnect(d->drag.posConnection); d->drag.posConnection = QMetaObject::Connection(); @@ -245,15 +209,14 @@ void DataDeviceInterface::drop() disconnect(d->drag.destroyConnection); d->drag.destroyConnection = QMetaObject::Connection(); d->drag.surface = nullptr; - client()->flush(); + wl_client_flush(d->resource()->client()); } void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 serial) { - Q_D(); if (d->drag.surface) { - if (d->resource && d->drag.surface->resource()) { - wl_data_device_send_leave(d->resource); + if (d->drag.surface->resource()) { + d->send_leave(); } if (d->drag.posConnection) { disconnect(d->drag.posConnection); @@ -289,48 +252,43 @@ void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 se if (d->seat->isDragPointer()) { d->drag.posConnection = connect(d->seat, &SeatInterface::pointerPosChanged, this, [this] { - Q_D(); const QPointF pos = d->seat->dragSurfaceTransformation().map(d->seat->pointerPos()); - wl_data_device_send_motion(d->resource, d->seat->timestamp(), + d->send_motion(d->seat->timestamp(), wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); - client()->flush(); + wl_client_flush(d->resource()->client()); } ); } else if (d->seat->isDragTouch()) { d->drag.posConnection = connect(d->seat, &SeatInterface::touchMoved, this, [this](qint32 id, quint32 serial, const QPointF &globalPosition) { - Q_D(); Q_UNUSED(id); if (serial != d->drag.serial) { // different touch down has been moved return; } const QPointF pos = d->seat->dragSurfaceTransformation().map(globalPosition); - wl_data_device_send_motion(d->resource, d->seat->timestamp(), - wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); - client()->flush(); + d->send_motion(d->seat->timestamp(), + wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); + wl_client_flush(d->resource()->client()); } ); } d->drag.destroyConnection = connect(d->drag.surface, &QObject::destroyed, this, [this] { - Q_D(); - if (d->resource) { - wl_data_device_send_leave(d->resource); - } + d->send_leave(); if (d->drag.posConnection) { disconnect(d->drag.posConnection); } - d->drag = Private::Drag(); + d->drag = DataDeviceInterfacePrivate::Drag(); } ); // TODO: handle touch position const QPointF pos = d->seat->dragSurfaceTransformation().map(d->seat->pointerPos()); - wl_data_device_send_enter(d->resource, serial, surface->resource(), - wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()), offer ? offer->resource() : nullptr); + 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->d_func()->sendSourceActions(); + offer->sendSourceActions(); auto matchOffers = [source, offer] { DataDeviceManagerInterface::DnDAction action{DataDeviceManagerInterface::DnDAction::None}; if (source->supportedDragAndDropActions().testFlag(offer->preferredDragAndDropAction())) { @@ -353,25 +311,23 @@ void DataDeviceInterface::updateDragTarget(SurfaceInterface *surface, quint32 se d->drag.targetActionConnection = connect(offer, &DataOfferInterface::dragAndDropActionsChanged, source, matchOffers); d->drag.sourceActionConnection = connect(source, &DataSourceInterface::supportedDragAndDropActionsChanged, source, matchOffers); } - d->client->flush(); + wl_client_flush(d->resource()->client()); } quint32 DataDeviceInterface::dragImplicitGrabSerial() const { - Q_D(); return d->drag.serial; } void DataDeviceInterface::updateProxy(SurfaceInterface *remote) { - Q_D(); // TODO: connect destroy signal? d->proxyRemoteSurface = remote; } -DataDeviceInterface::Private *DataDeviceInterface::d_func() const +wl_client *DataDeviceInterface::client() { - return reinterpret_cast(d.data()); + return d->resource()->client(); } } diff --git a/src/wayland/datadevice_interface.h b/src/wayland/datadevice_interface.h index 7c788e67c9..750cba319b 100644 --- a/src/wayland/datadevice_interface.h +++ b/src/wayland/datadevice_interface.h @@ -1,5 +1,6 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -21,6 +22,7 @@ class DataSourceInterface; class AbstractDataSource; class SeatInterface; class SurfaceInterface; +class DataDeviceInterfacePrivate; /** * @brief DataDeviceInterface allows clients to share data by copy-and-paste and drag-and-drop. @@ -33,7 +35,7 @@ class SurfaceInterface; * @see SeatInterface * @see DataSourceInterface **/ -class KWAYLANDSERVER_EXPORT DataDeviceInterface : public Resource +class KWAYLANDSERVER_EXPORT DataDeviceInterface : public QObject { Q_OBJECT public: @@ -78,17 +80,17 @@ public: **/ void updateProxy(SurfaceInterface *remote); + wl_client *client(); + Q_SIGNALS: void dragStarted(); void selectionChanged(KWaylandServer::DataSourceInterface*); void selectionCleared(); private: - friend class DataDeviceManagerInterface; - explicit DataDeviceInterface(SeatInterface *seat, DataDeviceManagerInterface *parent, wl_resource *parentResource); - - class Private; - Private *d_func() const; + friend class DataDeviceManagerInterfacePrivate; + explicit DataDeviceInterface(SeatInterface *seat, wl_resource *resource); + QScopedPointer d; }; } diff --git a/src/wayland/datadevicemanager_interface.cpp b/src/wayland/datadevicemanager_interface.cpp index e094e9a51a..91d6699080 100644 --- a/src/wayland/datadevicemanager_interface.cpp +++ b/src/wayland/datadevicemanager_interface.cpp @@ -1,5 +1,6 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -9,107 +10,66 @@ #include "display.h" #include "seat_interface_p.h" // Wayland -#include +#include namespace KWaylandServer { -class DataDeviceManagerInterface::Private : public Global::Private +static const quint32 s_version = 3; + +class DataDeviceManagerInterfacePrivate : public QtWaylandServer::wl_data_device_manager { public: - Private(DataDeviceManagerInterface *q, Display *d); + DataDeviceManagerInterfacePrivate(DataDeviceManagerInterface *q, Display *d); + DataDeviceManagerInterface *q; private: - void bind(wl_client *client, uint32_t version, uint32_t id) override; void createDataSource(wl_client *client, wl_resource *resource, uint32_t id); void getDataDevice(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat); - static void unbind(wl_resource *resource); - static void createDataSourceCallback(wl_client *client, wl_resource *resource, uint32_t id); - static void getDataDeviceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat); - static Private *cast(wl_resource *r) { - return reinterpret_cast(wl_resource_get_user_data(r)); - } - - DataDeviceManagerInterface *q; - static const struct wl_data_device_manager_interface s_interface; - static const quint32 s_version; - static const qint32 s_dataDeviceVersion; - static const qint32 s_dataSourceVersion; +protected: + void data_device_manager_create_data_source(Resource *resource, uint32_t id) override; + void data_device_manager_get_data_device(Resource *resource, uint32_t id, wl_resource *seat) override; }; -const quint32 DataDeviceManagerInterface::Private::s_version = 3; -const qint32 DataDeviceManagerInterface::Private::s_dataDeviceVersion = 3; -const qint32 DataDeviceManagerInterface::Private::s_dataSourceVersion = 3; -#ifndef K_DOXYGEN -const struct wl_data_device_manager_interface DataDeviceManagerInterface::Private::s_interface = { - createDataSourceCallback, - getDataDeviceCallback -}; -#endif - -DataDeviceManagerInterface::Private::Private(DataDeviceManagerInterface *q, Display *d) - : Global::Private(d, &wl_data_device_manager_interface, s_version) +DataDeviceManagerInterfacePrivate::DataDeviceManagerInterfacePrivate(DataDeviceManagerInterface *q, Display *d) + : QtWaylandServer::wl_data_device_manager(*d, s_version) , q(q) { } -void DataDeviceManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) +void DataDeviceManagerInterfacePrivate::data_device_manager_create_data_source(Resource *resource, uint32_t id) { - auto c = display->getConnection(client); - wl_resource *resource = c->createResource(&wl_data_device_manager_interface, qMin(version, s_version), id); - if (!resource) { - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(resource, &s_interface, this, unbind); - // TODO: should we track? -} - -void DataDeviceManagerInterface::Private::unbind(wl_resource *resource) -{ - Q_UNUSED(resource) -} - -void DataDeviceManagerInterface::Private::createDataSourceCallback(wl_client *client, wl_resource *resource, uint32_t id) -{ - cast(resource)->createDataSource(client, resource, id); -} - -void DataDeviceManagerInterface::Private::createDataSource(wl_client *client, wl_resource *resource, uint32_t id) -{ - DataSourceInterface *dataSource = new DataSourceInterface(q, resource); - dataSource->create(display->getConnection(client), qMin(wl_resource_get_version(resource), s_dataSourceVersion) , id); - if (!dataSource->resource()) { - wl_resource_post_no_memory(resource); - delete dataSource; + wl_resource *data_source_resource = wl_resource_create(resource->client(), &wl_data_source_interface, resource->version(), id); + if (!data_source_resource) { + wl_resource_post_no_memory(resource->handle); return; } + DataSourceInterface *dataSource = new DataSourceInterface(q, data_source_resource); emit q->dataSourceCreated(dataSource); } -void DataDeviceManagerInterface::Private::getDataDeviceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat) -{ - cast(resource)->getDataDevice(client, resource, id, seat); -} - -void DataDeviceManagerInterface::Private::getDataDevice(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat) +void DataDeviceManagerInterfacePrivate::data_device_manager_get_data_device(Resource *resource, uint32_t id, wl_resource *seat) { SeatInterface *s = SeatInterface::get(seat); Q_ASSERT(s); - DataDeviceInterface *dataDevice = new DataDeviceInterface(s, q, resource); - dataDevice->create(display->getConnection(client), qMin(wl_resource_get_version(resource), s_dataDeviceVersion), id); - if (!dataDevice->resource()) { - wl_resource_post_no_memory(resource); + if (!s) { return; } - s->d_func()->registerDataDevice(dataDevice); + + wl_resource *data_device_resource = wl_resource_create(resource->client(), &wl_data_device_interface, resource->version(), id); + if (!data_device_resource) { + wl_resource_post_no_memory(resource->handle); + return; + } + DataDeviceInterface *dataDevice = new DataDeviceInterface(s, data_device_resource); emit q->dataDeviceCreated(dataDevice); } DataDeviceManagerInterface::DataDeviceManagerInterface(Display *display, QObject *parent) - : Global(new Private(this, display), parent) + : QObject(parent) + , d(new DataDeviceManagerInterfacePrivate(this, display)) { } diff --git a/src/wayland/datadevicemanager_interface.h b/src/wayland/datadevicemanager_interface.h index 8029ab65c2..fb707994ea 100644 --- a/src/wayland/datadevicemanager_interface.h +++ b/src/wayland/datadevicemanager_interface.h @@ -1,5 +1,6 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -9,7 +10,6 @@ #include #include -#include "global.h" #include "datadevice_interface.h" namespace KWaylandServer @@ -17,20 +17,20 @@ namespace KWaylandServer class Display; class DataSourceInterface; +class DataDeviceManagerInterfacePrivate; /** * @brief Represents the Global for wl_data_device_manager interface. * **/ -class KWAYLANDSERVER_EXPORT DataDeviceManagerInterface : public Global +class KWAYLANDSERVER_EXPORT DataDeviceManagerInterface : public QObject { Q_OBJECT public: - virtual ~DataDeviceManagerInterface(); + ~DataDeviceManagerInterface() override; /** * Drag and Drop actions supported by the DataSourceInterface. - * @since 5.XX **/ enum class DnDAction { None = 0, @@ -47,7 +47,7 @@ Q_SIGNALS: private: explicit DataDeviceManagerInterface(Display *display, QObject *parent = nullptr); friend class Display; - class Private; + QScopedPointer d; }; } diff --git a/src/wayland/dataoffer_interface.cpp b/src/wayland/dataoffer_interface.cpp index 9b36b93815..4f342bdd6d 100644 --- a/src/wayland/dataoffer_interface.cpp +++ b/src/wayland/dataoffer_interface.cpp @@ -1,159 +1,160 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ -#include "dataoffer_interface_p.h" +#include "dataoffer_interface.h" #include "datadevice_interface.h" #include "datasource_interface.h" + // Qt #include +#include // Wayland -#include +#include // system #include namespace KWaylandServer { -#ifndef K_DOXYGEN -const struct wl_data_offer_interface DataOfferInterface::Private::s_interface = { - acceptCallback, - receiveCallback, - resourceDestroyedCallback, - finishCallback, - setActionsCallback -}; -#endif - -DataOfferInterface::Private::Private(AbstractDataSource *source, DataDeviceInterface *parentInterface, DataOfferInterface *q, wl_resource *parentResource) - : Resource::Private(q, nullptr, parentResource, &wl_data_offer_interface, &s_interface) - , source(source) - , dataDevice(parentInterface) +class DataOfferInterfacePrivate : public QtWaylandServer::wl_data_offer +{ +public: + DataOfferInterfacePrivate(AbstractDataSource *source, DataOfferInterface *q, wl_resource *resource); + DataOfferInterface *q; + QPointer source; + + // defaults are set to sensible values for < version 3 interfaces + DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::Copy | DataDeviceManagerInterface::DnDAction::Move; + DataDeviceManagerInterface::DnDAction preferredDnDAction = DataDeviceManagerInterface::DnDAction::Copy; + +protected: + void data_offer_destroy_resource(Resource *resource) override; + void data_offer_accept(Resource *resource, uint32_t serial, const QString &mime_type) override; + void data_offer_receive(Resource *resource, const QString &mime_type, int32_t fd) override; + void data_offer_destroy(Resource *resource) override; + void data_offer_finish(Resource *resource) override; + void data_offer_set_actions(Resource *resource, uint32_t dnd_actions, uint32_t preferred_action) override; +}; + + +DataOfferInterfacePrivate::DataOfferInterfacePrivate(AbstractDataSource *_source, DataOfferInterface *_q, wl_resource *resource) + : QtWaylandServer::wl_data_offer(resource) + , q(_q) + , source(_source) { - // TODO: connect to new selections } -DataOfferInterface::Private::~Private() = default; - -void DataOfferInterface::Private::acceptCallback(wl_client *client, wl_resource *resource, uint32_t serial, const char *mimeType) +void DataOfferInterfacePrivate::data_offer_accept(Resource *resource, uint32_t serial, const QString &mime_type) { - Q_UNUSED(client) + Q_UNUSED(resource) Q_UNUSED(serial) - auto p = cast(resource); - if (!p->source) { + if (!source) { return; } - p->source->accept(mimeType ? QString::fromUtf8(mimeType) : QString()); + source->accept(mime_type); } -void DataOfferInterface::Private::receiveCallback(wl_client *client, wl_resource *resource, const char *mimeType, int32_t fd) -{ - Q_UNUSED(client) - cast(resource)->receive(QString::fromUtf8(mimeType), fd); -} - -void DataOfferInterface::Private::receive(const QString &mimeType, qint32 fd) +void DataOfferInterfacePrivate::data_offer_receive(Resource *resource, const QString &mime_type, int32_t fd) { + Q_UNUSED(resource) if (!source) { close(fd); return; } - source->requestData(mimeType, fd); + source->requestData(mime_type, fd); } -void DataOfferInterface::Private::finishCallback(wl_client *client, wl_resource *resource) +void DataOfferInterfacePrivate::data_offer_destroy(QtWaylandServer::wl_data_offer::Resource *resource) { - Q_UNUSED(client) - auto p = cast(resource); - if (!p->source) { - return; - } - p->source->dndFinished(); + wl_resource_destroy(resource->handle); +} + +void DataOfferInterfacePrivate::data_offer_finish(Resource *resource) +{ + Q_UNUSED(resource) + source->dndFinished(); // TODO: It is a client error to perform other requests than wl_data_offer.destroy after this one } -void DataOfferInterface::Private::setActionsCallback(wl_client *client, wl_resource *resource, uint32_t dnd_actions, uint32_t preferred_action) +void DataOfferInterfacePrivate::data_offer_set_actions(Resource *resource, uint32_t dnd_actions, uint32_t preferred_action) { // TODO: check it's drag and drop, otherwise send error - Q_UNUSED(client) DataDeviceManagerInterface::DnDActions supportedActions; - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) { + if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_copy) { supportedActions |= DataDeviceManagerInterface::DnDAction::Copy; } - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) { + if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_move) { supportedActions |= DataDeviceManagerInterface::DnDAction::Move; } - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) { + if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_ask) { supportedActions |= DataDeviceManagerInterface::DnDAction::Ask; } // verify that the no other actions are sent - if (dnd_actions & ~(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)) { - wl_resource_post_error(resource, WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK, "Invalid action mask"); + if (dnd_actions & ~(QtWaylandServer::wl_data_device_manager::dnd_action_copy | QtWaylandServer::wl_data_device_manager::dnd_action_move | QtWaylandServer::wl_data_device_manager::dnd_action_ask)) { + wl_resource_post_error(resource->handle, error_invalid_action_mask, "Invalid action mask"); return; } - if (preferred_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY && - preferred_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE && - preferred_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK && - preferred_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE) { - wl_resource_post_error(resource, WL_DATA_OFFER_ERROR_INVALID_ACTION, "Invalid preferred action"); + if (preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_copy && + preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_move && + preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_ask && + preferred_action != QtWaylandServer::wl_data_device_manager::dnd_action_none) { + wl_resource_post_error(resource->handle, error_invalid_action, "Invalid preferred action"); return; } DataDeviceManagerInterface::DnDAction preferredAction = DataDeviceManagerInterface::DnDAction::None; - if (preferred_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) { + if (preferred_action == QtWaylandServer::wl_data_device_manager::dnd_action_copy) { preferredAction = DataDeviceManagerInterface::DnDAction::Copy; - } else if (preferred_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) { + } else if (preferred_action == QtWaylandServer::wl_data_device_manager::dnd_action_move) { preferredAction = DataDeviceManagerInterface::DnDAction::Move; - } else if (preferred_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) { + } else if (preferred_action == QtWaylandServer::wl_data_device_manager::dnd_action_ask) { preferredAction = DataDeviceManagerInterface::DnDAction::Ask; } - auto p = cast(resource); - p->supportedDnDActions = supportedActions; - p->preferredDnDAction = preferredAction; - emit p->q_func()->dragAndDropActionsChanged(); + supportedDnDActions = supportedActions; + preferredDnDAction = preferredAction; + emit q->dragAndDropActionsChanged(); } -void DataOfferInterface::Private::sendSourceActions() +void DataOfferInterface::sendSourceActions() { - if (!source) { + if (!d->source) { return; } - if (wl_resource_get_version(resource) < WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) { + if (d->resource()->version() < WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) { return; } - uint32_t wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; - const auto actions = source->supportedDragAndDropActions(); + uint32_t wlActions = QtWaylandServer::wl_data_device_manager::dnd_action_none; + const auto actions = d->source->supportedDragAndDropActions(); if (actions.testFlag(DataDeviceManagerInterface::DnDAction::Copy)) { - wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + wlActions |= QtWaylandServer::wl_data_device_manager::dnd_action_copy; } if (actions.testFlag(DataDeviceManagerInterface::DnDAction::Move)) { - wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; + wlActions |= QtWaylandServer::wl_data_device_manager::dnd_action_move; } if (actions.testFlag(DataDeviceManagerInterface::DnDAction::Ask)) { - wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; + wlActions |= QtWaylandServer::wl_data_device_manager::dnd_action_ask; } - wl_data_offer_send_source_actions(resource, wlActions); + d->send_source_actions(wlActions); } -DataOfferInterface::DataOfferInterface(AbstractDataSource *source, DataDeviceInterface *parentInterface, wl_resource *parentResource) - : Resource(new Private(source, parentInterface, this, parentResource)) +void DataOfferInterfacePrivate::data_offer_destroy_resource(QtWaylandServer::wl_data_offer::Resource *resource) +{ + Q_UNUSED(resource) + delete q; +} + +DataOfferInterface::DataOfferInterface(AbstractDataSource *source, wl_resource *resource) + : QObject(nullptr) + , d(new DataOfferInterfacePrivate(source, this, resource)) { Q_ASSERT(source); connect(source, &DataSourceInterface::mimeTypeOffered, this, [this](const QString &mimeType) { - Q_D(); - if (!d->resource) { - return; - } - wl_data_offer_send_offer(d->resource, mimeType.toUtf8().constData()); - } - ); - QObject::connect(source, &QObject::destroyed, this, - [this] { - Q_D(); - d->source = nullptr; + d->send_offer(mimeType); } ); } @@ -162,44 +163,40 @@ DataOfferInterface::~DataOfferInterface() = default; void DataOfferInterface::sendAllOffers() { - Q_D(); for (const QString &mimeType : d->source->mimeTypes()) { - wl_data_offer_send_offer(d->resource, mimeType.toUtf8().constData()); + d->send_offer(mimeType); } } -DataOfferInterface::Private *DataOfferInterface::d_func() const +wl_resource *DataOfferInterface::resource() const { - return reinterpret_cast(d.data()); + return d->resource()->handle; } DataDeviceManagerInterface::DnDActions DataOfferInterface::supportedDragAndDropActions() const { - Q_D(); return d->supportedDnDActions; } DataDeviceManagerInterface::DnDAction DataOfferInterface::preferredDragAndDropAction() const { - Q_D(); return d->preferredDnDAction; } void DataOfferInterface::dndAction(DataDeviceManagerInterface::DnDAction action) { - Q_D(); - if (wl_resource_get_version(d->resource) < WL_DATA_OFFER_ACTION_SINCE_VERSION) { + if (d->resource()->version() < WL_DATA_OFFER_ACTION_SINCE_VERSION) { return; } - uint32_t wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + uint32_t wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_none; if (action == DataDeviceManagerInterface::DnDAction::Copy) { - wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_copy; } else if (action == DataDeviceManagerInterface::DnDAction::Move ) { - wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; + wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_move; } else if (action == DataDeviceManagerInterface::DnDAction::Ask) { - wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; + wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_ask; } - wl_data_offer_send_action(d->resource, wlAction); + d->send_action(wlAction); } } diff --git a/src/wayland/dataoffer_interface.h b/src/wayland/dataoffer_interface.h index c06bc97691..9278ce4474 100644 --- a/src/wayland/dataoffer_interface.h +++ b/src/wayland/dataoffer_interface.h @@ -1,5 +1,6 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -18,18 +19,21 @@ namespace KWaylandServer class DataDeviceInterface; class AbstractDataSource; +class DataOfferInterfacePrivate; /** * @brief Represents the Resource for the wl_data_offer interface. * **/ -class KWAYLANDSERVER_EXPORT DataOfferInterface : public Resource +class KWAYLANDSERVER_EXPORT DataOfferInterface : public QObject { Q_OBJECT public: virtual ~DataOfferInterface(); void sendAllOffers(); + void sendSourceActions(); + wl_resource *resource() const; /** * @returns The Drag and Drop actions supported by this DataOfferInterface. @@ -58,11 +62,10 @@ Q_SIGNALS: void dragAndDropActionsChanged(); private: - friend class DataDeviceInterface; - explicit DataOfferInterface(AbstractDataSource *source, DataDeviceInterface *parentInterface, wl_resource *parentResource); + friend class DataDeviceInterfacePrivate; + explicit DataOfferInterface(AbstractDataSource *source, wl_resource *resource); - class Private; - Private *d_func() const; + QScopedPointer d; }; } diff --git a/src/wayland/datasource_interface.cpp b/src/wayland/datasource_interface.cpp index abc090559a..7d325ef31d 100644 --- a/src/wayland/datasource_interface.cpp +++ b/src/wayland/datasource_interface.cpp @@ -1,5 +1,6 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -10,92 +11,91 @@ // Qt #include // Wayland -#include +#include // system #include namespace KWaylandServer { -class DataSourceInterface::Private : public Resource::Private +class DataSourceInterfacePrivate : public QtWaylandServer::wl_data_source { public: - Private(DataSourceInterface *q, DataDeviceManagerInterface *parent, wl_resource *parentResource); - ~Private(); + DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource); + DataSourceInterface *q; QStringList mimeTypes; DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::None; +protected: + void data_source_destroy_resource(Resource *resource) override; + void data_source_offer(Resource *resource, const QString &mime_type) override; + void data_source_destroy(Resource *resource) override; + void data_source_set_actions(Resource *resource, uint32_t dnd_actions) override; + private: - DataSourceInterface *q_func() { - return reinterpret_cast(q); - } void offer(const QString &mimeType); - - static void offerCallback(wl_client *client, wl_resource *resource, const char *mimeType); - static void setActionsCallback(wl_client *client, wl_resource *resource, uint32_t dnd_actions); - - const static struct wl_data_source_interface s_interface; }; -#ifndef K_DOXYGEN -const struct wl_data_source_interface DataSourceInterface::Private::s_interface = { - offerCallback, - resourceDestroyedCallback, - setActionsCallback -}; -#endif - -DataSourceInterface::Private::Private(DataSourceInterface *q, DataDeviceManagerInterface *parent, wl_resource *parentResource) - : Resource::Private(q, parent, parentResource, &wl_data_source_interface, &s_interface) +DataSourceInterfacePrivate::DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource) + : QtWaylandServer::wl_data_source(resource) + , q(_q) { } -DataSourceInterface::Private::~Private() = default; - -void DataSourceInterface::Private::offerCallback(wl_client *client, wl_resource *resource, const char *mimeType) +void DataSourceInterfacePrivate::data_source_destroy_resource(Resource *resource) { - Q_UNUSED(client) - cast(resource)->offer(QString::fromUtf8(mimeType)); + Q_UNUSED(resource) + emit q->aboutToBeDestroyed(); + delete q; } -void DataSourceInterface::Private::offer(const QString &mimeType) +void DataSourceInterfacePrivate::data_source_offer(QtWaylandServer::wl_data_source::Resource *resource, const QString &mime_type) +{ + Q_UNUSED(resource) + mimeTypes << mime_type; + emit q->mimeTypeOffered(mime_type); +} + +void DataSourceInterfacePrivate::data_source_destroy(QtWaylandServer::wl_data_source::Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void DataSourceInterfacePrivate::offer(const QString &mimeType) { mimeTypes << mimeType; - Q_Q(DataSourceInterface); emit q->mimeTypeOffered(mimeType); } -void DataSourceInterface::Private::setActionsCallback(wl_client *client, wl_resource *resource, uint32_t dnd_actions) +void DataSourceInterfacePrivate::data_source_set_actions(Resource *resource, uint32_t dnd_actions) { - Q_UNUSED(client) DataDeviceManagerInterface::DnDActions supportedActions; - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) { + if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_copy) { supportedActions |= DataDeviceManagerInterface::DnDAction::Copy; } - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) { + if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_move) { supportedActions |= DataDeviceManagerInterface::DnDAction::Move; } - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) { + if (dnd_actions & QtWaylandServer::wl_data_device_manager::dnd_action_ask) { supportedActions |= DataDeviceManagerInterface::DnDAction::Ask; } // verify that the no other actions are sent - if (dnd_actions & ~(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)) { - wl_resource_post_error(resource, WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK, "Invalid action mask"); + if (dnd_actions & ~(QtWaylandServer::wl_data_device_manager::dnd_action_copy | QtWaylandServer::wl_data_device_manager::dnd_action_move | QtWaylandServer::wl_data_device_manager::dnd_action_ask)) { + wl_resource_post_error(resource->handle, QtWaylandServer::wl_data_source::error_invalid_action_mask, "Invalid action mask"); return; } - auto p = cast(resource); - if (p->supportedDnDActions!= supportedActions) { - p->supportedDnDActions = supportedActions; - emit p->q_func()->supportedDragAndDropActionsChanged(); + if (supportedDnDActions!= supportedActions) { + supportedDnDActions = supportedActions; + emit q->supportedDragAndDropActionsChanged(); } } -DataSourceInterface::DataSourceInterface(DataDeviceManagerInterface *parent, wl_resource *parentResource) - : AbstractDataSource(new Private(this, parent, parentResource)) +DataSourceInterface::DataSourceInterface(DataDeviceManagerInterface *parent, wl_resource *resource) + : AbstractDataSource(parent) + , d(new DataSourceInterfacePrivate(this, resource)) { - if (wl_resource_get_version(parentResource) < WL_DATA_SOURCE_ACTION_SINCE_VERSION) { - Q_D(); + if (d->resource()->version() < WL_DATA_SOURCE_ACTION_SINCE_VERSION) { d->supportedDnDActions = DataDeviceManagerInterface::DnDAction::Copy; } } @@ -104,86 +104,79 @@ DataSourceInterface::~DataSourceInterface() = default; void DataSourceInterface::accept(const QString &mimeType) { - Q_D(); - // TODO: does this require a sanity check on the possible mimeType? - wl_data_source_send_target(d->resource, mimeType.isEmpty() ? nullptr : mimeType.toUtf8().constData()); + d->send_target(mimeType); } void DataSourceInterface::requestData(const QString &mimeType, qint32 fd) { - Q_D(); - // TODO: does this require a sanity check on the possible mimeType? - if (d->resource) { - wl_data_source_send_send(d->resource, mimeType.toUtf8().constData(), int32_t(fd)); - } + d->send_send(mimeType, int32_t(fd)); close(fd); } void DataSourceInterface::cancel() { - Q_D(); - if (!d->resource) { - return; - } - wl_data_source_send_cancelled(d->resource); - Resource::client()->flush(); + d->send_cancelled(); } QStringList DataSourceInterface::mimeTypes() const { - Q_D(); return d->mimeTypes; } DataSourceInterface *DataSourceInterface::get(wl_resource *native) { - return Private::get(native); -} - -DataSourceInterface::Private *DataSourceInterface::d_func() const -{ - return reinterpret_cast(d.data()); + if (!native) { + return nullptr; + } + auto priv = static_cast(QtWaylandServer::wl_data_source::Resource::fromResource(native)->object()); + return priv->q; } DataDeviceManagerInterface::DnDActions DataSourceInterface::supportedDragAndDropActions() const { - Q_D(); return d->supportedDnDActions; } void DataSourceInterface::dropPerformed() { - Q_D(); - if (wl_resource_get_version(d->resource) < WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { + if (d->resource()->version() < WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { return; } - wl_data_source_send_dnd_drop_performed(d->resource); + d->send_dnd_drop_performed(); } void DataSourceInterface::dndFinished() { - Q_D(); - if (wl_resource_get_version(d->resource) < WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { + if (d->resource()->version() < WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) { return; } - wl_data_source_send_dnd_finished(d->resource); + d->send_dnd_finished(); } void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action) { - Q_D(); - if (wl_resource_get_version(d->resource) < WL_DATA_SOURCE_ACTION_SINCE_VERSION) { + if (d->resource()->version() < WL_DATA_SOURCE_ACTION_SINCE_VERSION) { return; } - uint32_t wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; + uint32_t wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_none; if (action == DataDeviceManagerInterface::DnDAction::Copy) { - wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; + wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_copy; } else if (action == DataDeviceManagerInterface::DnDAction::Move ) { - wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; + wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_move; } else if (action == DataDeviceManagerInterface::DnDAction::Ask) { - wlAction = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK; + wlAction = QtWaylandServer::wl_data_device_manager::dnd_action_ask; } - wl_data_source_send_action(d->resource, wlAction); + d->send_action(wlAction); +} + +wl_resource *DataSourceInterface::resource() const +{ + return d->resource()->handle; +} + +wl_client *DataSourceInterface::client() const +{ + return d->resource()->client(); } } diff --git a/src/wayland/datasource_interface.h b/src/wayland/datasource_interface.h index 21808942f5..cce883d225 100644 --- a/src/wayland/datasource_interface.h +++ b/src/wayland/datasource_interface.h @@ -1,5 +1,6 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 David Edmundson SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -15,6 +16,8 @@ namespace KWaylandServer { +class DataSourceInterfacePrivate; + /** * @brief Represents the Resource for the wl_data_source interface. **/ @@ -42,12 +45,15 @@ public: void dndFinished() override; void dndAction(DataDeviceManagerInterface::DnDAction action) override; + wl_resource *resource() const; + + wl_client *client() const override; + private: - friend class DataDeviceManagerInterface; + friend class DataDeviceManagerInterfacePrivate; explicit DataSourceInterface(DataDeviceManagerInterface *parent, wl_resource *parentResource); - class Private; - Private *d_func() const; + QScopedPointer d; }; } diff --git a/src/wayland/primaryselectionsource_v1_interface.cpp b/src/wayland/primaryselectionsource_v1_interface.cpp index 7c2c520631..4a50fe8fdb 100644 --- a/src/wayland/primaryselectionsource_v1_interface.cpp +++ b/src/wayland/primaryselectionsource_v1_interface.cpp @@ -38,8 +38,7 @@ PrimarySelectionSourceV1InterfacePrivate::PrimarySelectionSourceV1InterfacePriva void PrimarySelectionSourceV1InterfacePrivate::zwp_primary_selection_source_v1_destroy_resource(QtWaylandServer::zwp_primary_selection_source_v1::Resource *resource) { Q_UNUSED(resource) - emit q->aboutToBeUnbound(); - emit q->unbound(); + emit q->aboutToBeDestroyed(); delete q; } @@ -55,7 +54,7 @@ void PrimarySelectionSourceV1InterfacePrivate::zwp_primary_selection_source_v1_d } PrimarySelectionSourceV1Interface::PrimarySelectionSourceV1Interface(PrimarySelectionDeviceManagerV1Interface *parent, ::wl_resource *resource) - : AbstractDataSource(nullptr, parent) + : AbstractDataSource(parent) , d(new PrimarySelectionSourceV1InterfacePrivate(this, resource)) { } @@ -78,7 +77,7 @@ QStringList PrimarySelectionSourceV1Interface::mimeTypes() const return d->mimeTypes; } -wl_client *PrimarySelectionSourceV1Interface::client() +wl_client *PrimarySelectionSourceV1Interface::client() const { return d->resource()->client(); } diff --git a/src/wayland/primaryselectionsource_v1_interface.h b/src/wayland/primaryselectionsource_v1_interface.h index 11bd9f6151..4208e6748d 100644 --- a/src/wayland/primaryselectionsource_v1_interface.h +++ b/src/wayland/primaryselectionsource_v1_interface.h @@ -33,7 +33,7 @@ public: QStringList mimeTypes() const override; static PrimarySelectionSourceV1Interface *get(wl_resource *native); - wl_client *client() override; + wl_client *client() const override; private: friend class PrimarySelectionDeviceManagerV1InterfacePrivate; diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp index e9c0445860..99644eaee2 100644 --- a/src/wayland/seat_interface.cpp +++ b/src/wayland/seat_interface.cpp @@ -247,7 +247,13 @@ QVector SeatInterface::Private::touchsForSurface(SurfaceInterf QVector SeatInterface::Private::dataDevicesForSurface(SurfaceInterface *surface) const { - return interfacesForSurface(surface, dataDevices); + QVector primarySelectionDevices; + for (auto it = dataDevices.constBegin(); it != dataDevices.constEnd(); ++it) { + if ((*it)->client() == *surface->client()) { + primarySelectionDevices << *it; + } + } + return primarySelectionDevices; } void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) @@ -259,7 +265,6 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) keys.focus.selections.removeOne(dataDevice); }; QObject::connect(dataDevice, &QObject::destroyed, q, dataDeviceCleanup); - QObject::connect(dataDevice, &Resource::unbound, q, dataDeviceCleanup); QObject::connect(dataDevice, &DataDeviceInterface::selectionChanged, q, [this, dataDevice] { updateSelection(dataDevice); @@ -303,7 +308,7 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) } ); if (dataDevice->dragSource()) { - drag.dragSourceDestroyConnection = QObject::connect(dataDevice->dragSource(), &Resource::aboutToBeUnbound, q, + drag.dragSourceDestroyConnection = QObject::connect(dataDevice->dragSource(), &AbstractDataSource::aboutToBeDestroyed, q, [this] { const auto serial = display->nextSerial(); if (drag.target) { @@ -324,7 +329,7 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) // is the new DataDevice for the current keyoard focus? if (keys.focus.surface) { // same client? - if (keys.focus.surface->client() == dataDevice->client()) { + if (*keys.focus.surface->client() == dataDevice->client()) { keys.focus.selections.append(dataDevice); if (currentSelection) { dataDevice->sendSelection(currentSelection); @@ -419,7 +424,7 @@ void SeatInterface::Private::endDrag(quint32 serial) void SeatInterface::Private::updateSelection(DataDeviceInterface *dataDevice) { // if the update is from the focussed window we should inform the active client - if (!(keys.focus.surface && (keys.focus.surface->client() == dataDevice->client()))) { + if (!(keys.focus.surface && (*keys.focus.surface->client() == dataDevice->client()))) { return; } q->setSelection(dataDevice->selection()); @@ -1644,8 +1649,7 @@ void SeatInterface::setSelection(AbstractDataSource *selection) auto cleanup = [this]() { setSelection(nullptr); }; - connect(selection, &DataSourceInterface::unbound, this, cleanup); - connect(selection, &QObject::destroyed, this, cleanup); + connect(selection, &DataSourceInterface::aboutToBeDestroyed, this, cleanup); } d->currentSelection = selection; @@ -1684,7 +1688,7 @@ void SeatInterface::setPrimarySelection(AbstractDataSource *selection) auto cleanup = [this]() { setPrimarySelection(nullptr); }; - connect(selection, &DataSourceInterface::unbound, this, cleanup); + connect(selection, &DataSourceInterface::aboutToBeDestroyed, this, cleanup); } d->currentPrimarySelection = selection; diff --git a/src/wayland/seat_interface.h b/src/wayland/seat_interface.h index 51506b4cf9..cc16897dc7 100644 --- a/src/wayland/seat_interface.h +++ b/src/wayland/seat_interface.h @@ -780,8 +780,8 @@ Q_SIGNALS: private: friend class Display; friend class DataControlDeviceV1Interface; + friend class DataDeviceInterface; friend class PrimarySelectionDeviceV1Interface; - friend class DataDeviceManagerInterface; friend class TextInputManagerV2InterfacePrivate; explicit SeatInterface(Display *display, QObject *parent); diff --git a/src/wayland/server/dataoffer_interface_p.h b/src/wayland/server/dataoffer_interface_p.h deleted file mode 100644 index d870419d03..0000000000 --- a/src/wayland/server/dataoffer_interface_p.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - SPDX-FileCopyrightText: 2017 Martin Flöser - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ -#ifndef KWAYLAND_SERVER_DATAOFFERINTERFACE_P_H -#define KWAYLAND_SERVER_DATAOFFERINTERFACE_P_H -#include "dataoffer_interface.h" -#include "datasource_interface.h" -#include "resource_p.h" - -#include - -#include - -namespace KWaylandServer -{ - -class Q_DECL_HIDDEN DataOfferInterface::Private : public Resource::Private -{ -public: - Private(AbstractDataSource *source, DataDeviceInterface *parentInterface, DataOfferInterface *q, wl_resource *parentResource); - ~Private(); - QPointer source; - DataDeviceInterface *dataDevice; - // defaults are set to sensible values for < version 3 interfaces - DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::Copy | DataDeviceManagerInterface::DnDAction::Move; - DataDeviceManagerInterface::DnDAction preferredDnDAction = DataDeviceManagerInterface::DnDAction::Copy; - - void sendSourceActions(); - -private: - DataOfferInterface *q_func() { - return reinterpret_cast(q); - } - void receive(const QString &mimeType, qint32 fd); - static void acceptCallback(wl_client *client, wl_resource *resource, uint32_t serial, const char *mimeType); - static void receiveCallback(wl_client *client, wl_resource *resource, const char *mimeType, int32_t fd); - static void finishCallback(wl_client *client, wl_resource *resource); - static void setActionsCallback(wl_client *client, wl_resource *resource, uint32_t dnd_actions, uint32_t preferred_action); - - static const struct wl_data_offer_interface s_interface; -}; - -} - -#endif diff --git a/src/wayland/tests/renderingservertest.cpp b/src/wayland/tests/renderingservertest.cpp index f016e74a6e..d18369b011 100644 --- a/src/wayland/tests/renderingservertest.cpp +++ b/src/wayland/tests/renderingservertest.cpp @@ -240,7 +240,6 @@ int main(int argc, char **argv) Display display; display.start(); DataDeviceManagerInterface *ddm = display.createDataDeviceManager(); - ddm->create(); display.createCompositor(&display); XdgShellInterface *shell = display.createXdgShell(); display.createShm();