diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 8757623a17..3cd37cfdae 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -1,6 +1,7 @@ set(SERVER_LIB_SRCS buffer_interface.cpp compositor_interface.cpp + datadevice_interface.cpp datadevicemanager_interface.cpp datasource_interface.cpp display.cpp @@ -47,6 +48,7 @@ set_target_properties(KF5WaylandServer PROPERTIES VERSION ${KWAYLAND_VERSION_S # ${CMAKE_CURRENT_BINARY_DIR}/KWayland/Server/kwaylandserver_export.h # buffer_interface.h # compositor_interface.h +# datadevice_interface.h # datadevicemanager_interface.h # datasource_interface.h # display.h diff --git a/src/wayland/autotests/client/CMakeLists.txt b/src/wayland/autotests/client/CMakeLists.txt index b224b51237..c2c1df29cc 100644 --- a/src/wayland/autotests/client/CMakeLists.txt +++ b/src/wayland/autotests/client/CMakeLists.txt @@ -145,3 +145,14 @@ add_executable(testDataSource ${testDataSource_SRCS}) target_link_libraries( testDataSource Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testDataSource testDataSource) ecm_mark_as_test(testDataSource) + +######################################################## +# Test DataDevice +######################################################## +set( testDataDevice_SRCS + test_datadevice.cpp + ) +add_executable(testDataDevice ${testDataDevice_SRCS}) +target_link_libraries( testDataDevice Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) +add_test(kwayland-testDataDevice testDataDevice) +ecm_mark_as_test(testDataDevice) diff --git a/src/wayland/autotests/client/test_datadevice.cpp b/src/wayland/autotests/client/test_datadevice.cpp new file mode 100644 index 0000000000..52b447ce22 --- /dev/null +++ b/src/wayland/autotests/client/test_datadevice.cpp @@ -0,0 +1,379 @@ +/******************************************************************** +Copyright 2014 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +// Qt +#include +// KWayland +#include "../../src/client/connection_thread.h" +#include "../../src/client/event_queue.h" +#include "../../src/client/datadevice.h" +#include "../../src/client/datadevicemanager.h" +#include "../../src/client/datasource.h" +#include "../../src/client/compositor.h" +#include "../../src/client/pointer.h" +#include "../../src/client/registry.h" +#include "../../src/client/seat.h" +#include "../../src/client/surface.h" +#include "../../src/server/display.h" +#include "../../src/server/datadevicemanager_interface.h" +#include "../../src/server/datasource_interface.h" +#include "../../src/server/compositor_interface.h" +#include "../../src/server/seat_interface.h" +#include "../../src/server/surface_interface.h" +// Wayland +#include + +class TestDataDevice : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void init(); + void cleanup(); + + void testCreate(); + void testDrag(); + void testDragInternally(); + void testSetSelection(); + void testDestroy(); + +private: + KWayland::Server::Display *m_display = nullptr; + KWayland::Server::DataDeviceManagerInterface *m_dataDeviceManagerInterface = nullptr; + KWayland::Server::CompositorInterface *m_compositorInterface = nullptr; + KWayland::Server::SeatInterface *m_seatInterface = nullptr; + KWayland::Client::ConnectionThread *m_connection = nullptr; + KWayland::Client::DataDeviceManager *m_dataDeviceManager = nullptr; + KWayland::Client::Compositor *m_compositor = nullptr; + KWayland::Client::Seat *m_seat = nullptr; + KWayland::Client::EventQueue *m_queue = nullptr; + QThread *m_thread = nullptr; +}; + +static const QString s_socketName = QStringLiteral("kwayland-test-wayland-datadevice-0"); + +void TestDataDevice::init() +{ + using namespace KWayland::Server; + delete m_display; + m_display = new Display(this); + m_display->setSocketName(s_socketName); + m_display->start(); + QVERIFY(m_display->isRunning()); + + // setup connection + m_connection = new KWayland::Client::ConnectionThread; + QSignalSpy connectedSpy(m_connection, SIGNAL(connected())); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + + m_queue = new KWayland::Client::EventQueue(this); + QVERIFY(!m_queue->isValid()); + m_queue->setup(m_connection); + QVERIFY(m_queue->isValid()); + + KWayland::Client::Registry registry; + QSignalSpy dataDeviceManagerSpy(®istry, SIGNAL(dataDeviceManagerAnnounced(quint32,quint32))); + QVERIFY(dataDeviceManagerSpy.isValid()); + QSignalSpy seatSpy(®istry, SIGNAL(seatAnnounced(quint32,quint32))); + QVERIFY(seatSpy.isValid()); + QSignalSpy compositorSpy(®istry, SIGNAL(compositorAnnounced(quint32,quint32))); + QVERIFY(compositorSpy.isValid()); + QVERIFY(!registry.eventQueue()); + registry.setEventQueue(m_queue); + QCOMPARE(registry.eventQueue(), m_queue); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + 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(), + dataDeviceManagerSpy.first().last().value(), this); + + m_seatInterface = m_display->createSeat(m_display); + m_seatInterface->setHasPointer(true); + m_seatInterface->create(); + QVERIFY(m_seatInterface->isValid()); + + QVERIFY(seatSpy.wait()); + m_seat = registry.createSeat(seatSpy.first().first().value(), + seatSpy.first().last().value(), this); + QVERIFY(m_seat->isValid()); + QSignalSpy pointerChangedSpy(m_seat, SIGNAL(hasPointerChanged(bool))); + QVERIFY(pointerChangedSpy.isValid()); + QVERIFY(pointerChangedSpy.wait()); + + m_compositorInterface = m_display->createCompositor(m_display); + m_compositorInterface->create(); + QVERIFY(m_compositorInterface->isValid()); + + QVERIFY(compositorSpy.wait()); + m_compositor = registry.createCompositor(compositorSpy.first().first().value(), + compositorSpy.first().last().value(), this); + QVERIFY(m_compositor->isValid()); +} + +void TestDataDevice::cleanup() +{ + if (m_dataDeviceManager) { + delete m_dataDeviceManager; + m_dataDeviceManager = nullptr; + } + if (m_seat) { + delete m_seat; + m_seat = nullptr; + } + if (m_compositor) { + delete m_compositor; + m_compositor = nullptr; + } + if (m_queue) { + delete m_queue; + m_queue = nullptr; + } + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + delete m_connection; + m_connection = nullptr; + + delete m_display; + m_display = nullptr; +} + +void TestDataDevice::testCreate() +{ + using namespace KWayland::Client; + using namespace KWayland::Server; + + QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, SIGNAL(dataDeviceCreated(KWayland::Server::DataDeviceInterface*))); + QVERIFY(dataDeviceCreatedSpy.isValid()); + + QScopedPointer dataDevice(m_dataDeviceManager->getDataDevice(m_seat)); + QVERIFY(dataDevice->isValid()); + + QVERIFY(dataDeviceCreatedSpy.wait()); + QCOMPARE(dataDeviceCreatedSpy.count(), 1); + 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()); +} + +void TestDataDevice::testDrag() +{ + using namespace KWayland::Client; + using namespace KWayland::Server; + QScopedPointer pointer(m_seat->createPointer()); + + QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, SIGNAL(dataDeviceCreated(KWayland::Server::DataDeviceInterface*))); + QVERIFY(dataDeviceCreatedSpy.isValid()); + + QScopedPointer dataDevice(m_dataDeviceManager->getDataDevice(m_seat)); + QVERIFY(dataDevice->isValid()); + + QVERIFY(dataDeviceCreatedSpy.wait()); + QCOMPARE(dataDeviceCreatedSpy.count(), 1); + auto deviceInterface = dataDeviceCreatedSpy.first().first().value(); + QVERIFY(deviceInterface); + + QSignalSpy dataSourceCreatedSpy(m_dataDeviceManagerInterface, SIGNAL(dataSourceCreated(DataSourceInterface*))); + QVERIFY(dataDeviceCreatedSpy.isValid()); + + QScopedPointer dataSource(m_dataDeviceManager->createDataSource()); + QVERIFY(dataSource->isValid()); + + QVERIFY(dataSourceCreatedSpy.wait()); + QCOMPARE(dataSourceCreatedSpy.count(), 1); + auto sourceInterface = dataSourceCreatedSpy.first().first().value(); + QVERIFY(sourceInterface); + + QSignalSpy surfaceCreatedSpy(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); + QVERIFY(surfaceCreatedSpy.isValid()); + + QScopedPointer surface(m_compositor->createSurface()); + QVERIFY(surface->isValid()); + + QVERIFY(surfaceCreatedSpy.wait()); + QCOMPARE(surfaceCreatedSpy.count(), 1); + auto surfaceInterface = surfaceCreatedSpy.first().first().value(); + + // now we have all we need to start a drag operation + QSignalSpy dragStartedSpy(deviceInterface, SIGNAL(dragStarted())); + QVERIFY(dragStartedSpy.isValid()); + + // first we need to fake the pointer enter + m_seatInterface->pointer()->setFocusedSurface(surfaceInterface); + m_seatInterface->pointer()->buttonPressed(1); + + QCoreApplication::processEvents(); + + dataDevice->startDrag(1, dataSource.data(), surface.data()); + QVERIFY(dragStartedSpy.wait()); + QCOMPARE(dragStartedSpy.count(), 1); + QCOMPARE(deviceInterface->dragSource(), sourceInterface); + QCOMPARE(deviceInterface->origin(), surfaceInterface); + QVERIFY(!deviceInterface->icon()); +} + +void TestDataDevice::testDragInternally() +{ + using namespace KWayland::Client; + using namespace KWayland::Server; + QScopedPointer pointer(m_seat->createPointer()); + + QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, SIGNAL(dataDeviceCreated(KWayland::Server::DataDeviceInterface*))); + QVERIFY(dataDeviceCreatedSpy.isValid()); + + QScopedPointer dataDevice(m_dataDeviceManager->getDataDevice(m_seat)); + QVERIFY(dataDevice->isValid()); + + QVERIFY(dataDeviceCreatedSpy.wait()); + QCOMPARE(dataDeviceCreatedSpy.count(), 1); + auto deviceInterface = dataDeviceCreatedSpy.first().first().value(); + QVERIFY(deviceInterface); + + QSignalSpy surfaceCreatedSpy(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); + QVERIFY(surfaceCreatedSpy.isValid()); + + QScopedPointer surface(m_compositor->createSurface()); + QVERIFY(surface->isValid()); + + QVERIFY(surfaceCreatedSpy.wait()); + QCOMPARE(surfaceCreatedSpy.count(), 1); + auto surfaceInterface = surfaceCreatedSpy.first().first().value(); + + QScopedPointer iconSurface(m_compositor->createSurface()); + QVERIFY(iconSurface->isValid()); + + QVERIFY(surfaceCreatedSpy.wait()); + QCOMPARE(surfaceCreatedSpy.count(), 2); + auto iconSurfaceInterface = surfaceCreatedSpy.last().first().value(); + + // now we have all we need to start a drag operation + QSignalSpy dragStartedSpy(deviceInterface, SIGNAL(dragStarted())); + QVERIFY(dragStartedSpy.isValid()); + + // first we need to fake the pointer enter + m_seatInterface->pointer()->setFocusedSurface(surfaceInterface); + m_seatInterface->pointer()->buttonPressed(1); + + QCoreApplication::processEvents(); + + dataDevice->startDragInternally(1, surface.data(), iconSurface.data()); + QVERIFY(dragStartedSpy.wait()); + QCOMPARE(dragStartedSpy.count(), 1); + QVERIFY(!deviceInterface->dragSource()); + QCOMPARE(deviceInterface->origin(), surfaceInterface); + QCOMPARE(deviceInterface->icon(), iconSurfaceInterface); +} + +void TestDataDevice::testSetSelection() +{ + using namespace KWayland::Client; + using namespace KWayland::Server; + QScopedPointer pointer(m_seat->createPointer()); + + QSignalSpy dataDeviceCreatedSpy(m_dataDeviceManagerInterface, SIGNAL(dataDeviceCreated(KWayland::Server::DataDeviceInterface*))); + QVERIFY(dataDeviceCreatedSpy.isValid()); + + QScopedPointer dataDevice(m_dataDeviceManager->getDataDevice(m_seat)); + QVERIFY(dataDevice->isValid()); + + QVERIFY(dataDeviceCreatedSpy.wait()); + QCOMPARE(dataDeviceCreatedSpy.count(), 1); + auto deviceInterface = dataDeviceCreatedSpy.first().first().value(); + QVERIFY(deviceInterface); + + QSignalSpy dataSourceCreatedSpy(m_dataDeviceManagerInterface, SIGNAL(dataSourceCreated(DataSourceInterface*))); + QVERIFY(dataDeviceCreatedSpy.isValid()); + + QScopedPointer dataSource(m_dataDeviceManager->createDataSource()); + QVERIFY(dataSource->isValid()); + + QVERIFY(dataSourceCreatedSpy.wait()); + QCOMPARE(dataSourceCreatedSpy.count(), 1); + auto sourceInterface = dataSourceCreatedSpy.first().first().value(); + QVERIFY(sourceInterface); + + // everything setup, now we can test setting the selection + QSignalSpy selectionChangedSpy(deviceInterface, SIGNAL(selectionChanged(KWayland::Server::DataSourceInterface*))); + QVERIFY(selectionChangedSpy.isValid()); + QSignalSpy selectionClearedSpy(deviceInterface, SIGNAL(selectionCleared())); + QVERIFY(selectionClearedSpy.isValid()); + + QVERIFY(!deviceInterface->selection()); + dataDevice->setSelection(1, dataSource.data()); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 1); + QCOMPARE(selectionClearedSpy.count(), 0); + QCOMPARE(selectionChangedSpy.first().first().value(), sourceInterface); + QCOMPARE(deviceInterface->selection(), sourceInterface); + + // now clear the selection + dataDevice->clearSelection(1); + QVERIFY(selectionClearedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 1); + QCOMPARE(selectionClearedSpy.count(), 1); + QVERIFY(!deviceInterface->selection()); +} + +void TestDataDevice::testDestroy() +{ + using namespace KWayland::Client; + + QScopedPointer dataDevice(m_dataDeviceManager->getDataDevice(m_seat)); + QVERIFY(dataDevice->isValid()); + + connect(m_connection, &ConnectionThread::connectionDied, m_dataDeviceManager, &DataDeviceManager::destroy); + connect(m_connection, &ConnectionThread::connectionDied, m_seat, &Seat::destroy); + connect(m_connection, &ConnectionThread::connectionDied, m_compositor, &Compositor::destroy); + connect(m_connection, &ConnectionThread::connectionDied, dataDevice.data(), &DataDevice::destroy); + connect(m_connection, &ConnectionThread::connectionDied, m_queue, &EventQueue::destroy); + + QSignalSpy connectionDiedSpy(m_connection, SIGNAL(connectionDied())); + QVERIFY(connectionDiedSpy.isValid()); + delete m_display; + m_display = nullptr; + QVERIFY(connectionDiedSpy.wait()); + + // now the data device should be destroyed; + QVERIFY(!dataDevice->isValid()); + + // calling destroy again should not fail + dataDevice->destroy(); +} + +QTEST_GUILESS_MAIN(TestDataDevice) +#include "test_datadevice.moc" diff --git a/src/wayland/datadevice_interface.cpp b/src/wayland/datadevice_interface.cpp new file mode 100644 index 0000000000..f5159a9f6c --- /dev/null +++ b/src/wayland/datadevice_interface.cpp @@ -0,0 +1,181 @@ +/******************************************************************** +Copyright 2014 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#include "datadevice_interface.h" +#include "datasource_interface.h" +#include "seat_interface.h" +#include "surface_interface.h" +// Wayland +#include + +namespace KWayland +{ +namespace Server +{ + +class DataDeviceInterface::Private +{ +public: + Private(SeatInterface *seat, DataDeviceInterface *q); + ~Private(); + + void create(wl_client *client, quint32 version, quint32 id); + + SeatInterface *seat; + wl_resource *device = nullptr; + DataSourceInterface *source = nullptr; + SurfaceInterface *surface = nullptr; + SurfaceInterface *icon = nullptr; + + DataSourceInterface *selection = nullptr; + +private: + void startDrag(DataSourceInterface *dataSource, SurfaceInterface *origin, SurfaceInterface *icon); + 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 void unbind(wl_resource *resource); + static Private *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + + DataDeviceInterface *q; + + static const struct wl_data_device_interface s_interface; +}; + +const struct wl_data_device_interface DataDeviceInterface::Private::s_interface = { + startDragCallback, + setSelectionCallback +}; + +DataDeviceInterface::Private::Private(SeatInterface *seat, DataDeviceInterface *q) + : seat(seat) + , q(q) +{ +} + +DataDeviceInterface::Private::~Private() +{ + if (device) { + wl_resource_destroy(device); + } +} + +void DataDeviceInterface::Private::startDragCallback(wl_client *client, wl_resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial) +{ + Q_UNUSED(client) + Q_UNUSED(serial) + // TODO: verify serial + cast(resource)->startDrag(DataSourceInterface::get(source), SurfaceInterface::get(origin), SurfaceInterface::get(icon)); +} + +void DataDeviceInterface::Private::startDrag(DataSourceInterface *dataSource, SurfaceInterface *origin, SurfaceInterface *i) +{ + if (seat->pointer()->focusedSurface() != origin) { + wl_resource_post_error(device, 0, "Surface doesn't have pointer grab"); + return; + } + source = dataSource; + surface = origin; + icon = i; + emit q->dragStarted(); +} + +void DataDeviceInterface::Private::setSelectionCallback(wl_client *client, wl_resource *resource, wl_resource *source, uint32_t serial) +{ + Q_UNUSED(client) + Q_UNUSED(serial) + // TODO: verify serial + cast(resource)->setSelection(DataSourceInterface::get(source)); +} + +void DataDeviceInterface::Private::setSelection(DataSourceInterface *dataSource) +{ + selection = dataSource; + if (selection) { + emit q->selectionChanged(selection); + } else { + emit q->selectionCleared(); + } +} + +void DataDeviceInterface::Private::unbind(wl_resource *resource) +{ + auto s = cast(resource); + s->device = nullptr; + s->q->deleteLater(); +} + +void DataDeviceInterface::Private::create(wl_client *client, quint32 version, quint32 id) +{ + Q_ASSERT(!device); + device = wl_resource_create(client, &wl_data_device_interface, version, id); + if (!device) { + return; + } + wl_resource_set_implementation(device, &s_interface, this, unbind); +} + + +DataDeviceInterface::DataDeviceInterface(SeatInterface *seat, DataDeviceManagerInterface *parent) + : QObject(/*parent*/) + , d(new Private(seat, this)) +{ +} + +DataDeviceInterface::~DataDeviceInterface() = default; + +void DataDeviceInterface::create(wl_client *client, quint32 version, quint32 id) +{ + d->create(client, version, id); +} + +SeatInterface *DataDeviceInterface::seat() const +{ + return d->seat; +} + +wl_resource *DataDeviceInterface::resource() const +{ + return d->device; +} + +DataSourceInterface *DataDeviceInterface::dragSource() const +{ + return d->source; +} + +SurfaceInterface *DataDeviceInterface::icon() const +{ + return d->icon; +} + +SurfaceInterface *DataDeviceInterface::origin() const +{ + return d->surface; +} + +DataSourceInterface *DataDeviceInterface::selection() const +{ + return d->selection; +} + +} +} diff --git a/src/wayland/datadevice_interface.h b/src/wayland/datadevice_interface.h new file mode 100644 index 0000000000..a89bdcbaf7 --- /dev/null +++ b/src/wayland/datadevice_interface.h @@ -0,0 +1,75 @@ +/******************************************************************** +Copyright 2014 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#ifndef WAYLAND_SERVER_DATA_DEVICE_INTERFACE_H +#define WAYLAND_SERVER_DATA_DEVICE_INTERFACE_H + +#include + +#include + +struct wl_client; +struct wl_resource; + +namespace KWayland +{ +namespace Server +{ + +class DataDeviceManagerInterface; +class DataSourceInterface; +class SeatInterface; +class SurfaceInterface; + +class KWAYLANDSERVER_EXPORT DataDeviceInterface : public QObject +{ + Q_OBJECT +public: + virtual ~DataDeviceInterface(); + + void create(wl_client *client, quint32 version, quint32 id); + + SeatInterface *seat() const; + DataSourceInterface *dragSource() const; + SurfaceInterface *origin() const; + SurfaceInterface *icon() const; + + DataSourceInterface *selection() const; + + wl_resource *resource() const; + +Q_SIGNALS: + void dragStarted(); + void selectionChanged(KWayland::Server::DataSourceInterface*); + void selectionCleared(); + +private: + friend class DataDeviceManagerInterface; + explicit DataDeviceInterface(SeatInterface *seat, DataDeviceManagerInterface *parent); + + class Private; + QScopedPointer d; +}; + +} +} + +Q_DECLARE_METATYPE(KWayland::Server::DataDeviceInterface*) + +#endif diff --git a/src/wayland/datadevicemanager_interface.cpp b/src/wayland/datadevicemanager_interface.cpp index 0328138fc1..fe3a9653cd 100644 --- a/src/wayland/datadevicemanager_interface.cpp +++ b/src/wayland/datadevicemanager_interface.cpp @@ -19,6 +19,7 @@ License along with this library. If not, see . *********************************************************************/ #include "datadevicemanager_interface.h" #include "display.h" +#include "seat_interface.h" // Wayland #include @@ -41,6 +42,7 @@ public: private: void bind(wl_client *client, uint32_t version, uint32_t id); 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 bind(wl_client *client, void *data, uint32_t version, uint32_t id); static void unbind(wl_resource *resource); @@ -109,10 +111,18 @@ void DataDeviceManagerInterface::Private::createDataSource(wl_client *client, wl void DataDeviceManagerInterface::Private::getDataDeviceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat) { - Q_UNUSED(client) - Q_UNUSED(resource) - Q_UNUSED(id) - Q_UNUSED(seat) + cast(resource)->getDataDevice(client, resource, id, seat); +} + +void DataDeviceManagerInterface::Private::getDataDevice(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat) +{ + DataDeviceInterface *dataDevice = new DataDeviceInterface(SeatInterface::get(seat), q); + dataDevice->create(client, wl_resource_get_version(resource), id); + if (!dataDevice->resource()) { + wl_resource_post_no_memory(resource); + return; + } + emit q->dataDeviceCreated(dataDevice); } void DataDeviceManagerInterface::Private::create() diff --git a/src/wayland/datadevicemanager_interface.h b/src/wayland/datadevicemanager_interface.h index 95246af4b8..1b1ab4eb2b 100644 --- a/src/wayland/datadevicemanager_interface.h +++ b/src/wayland/datadevicemanager_interface.h @@ -23,6 +23,7 @@ License along with this library. If not, see . #include #include +#include "datadevice_interface.h" #include "datasource_interface.h" namespace KWayland @@ -31,7 +32,6 @@ namespace Server { class Display; -class DataSourceInterface; class KWAYLANDSERVER_EXPORT DataDeviceManagerInterface : public QObject { @@ -45,6 +45,7 @@ public: Q_SIGNALS: void dataSourceCreated(DataSourceInterface*); + void dataDeviceCreated(KWayland::Server::DataDeviceInterface*); private: explicit DataDeviceManagerInterface(Display *display, QObject *parent = nullptr);