diff --git a/src/wayland/autotests/client/test_wayland_seat.cpp b/src/wayland/autotests/client/test_wayland_seat.cpp index 533aae058f..e1c30a1791 100644 --- a/src/wayland/autotests/client/test_wayland_seat.cpp +++ b/src/wayland/autotests/client/test_wayland_seat.cpp @@ -80,6 +80,7 @@ private Q_SLOTS: void testDestroy(); void testSelection(); void testSelectionNoDataSource(); + void testDataDeviceForKeyboardSurface(); void testTouch(); void testDisconnect(); void testPointerEnterOnUnboundSurface(); @@ -1598,6 +1599,99 @@ void TestWaylandSeat::testSelectionNoDataSource() m_seatInterface->setSelection(ddi); } +void TestWaylandSeat::testDataDeviceForKeyboardSurface() +{ + // this test verifies that the server does not crash when creating a datadevice for the focused keyboard surface + // and the currentSelection does not have a DataSource. + // to properly test the functionality this test requires a second client + using namespace KWayland::Client; + using namespace KWayland::Server; + // create the DataDeviceManager + QScopedPointer ddmi(m_display->createDataDeviceManager()); + ddmi->create(); + QSignalSpy ddiCreatedSpy(ddmi.data(), &DataDeviceManagerInterface::dataDeviceCreated); + QVERIFY(ddiCreatedSpy.isValid()); + + // create a second Wayland client connection to use it for setSelection + auto c = new ConnectionThread; + QSignalSpy connectedSpy(c, &ConnectionThread::connected); + QVERIFY(connectedSpy.isValid()); + c->setSocketName(s_socketName); + + auto thread = new QThread(this); + c->moveToThread(thread); + thread->start(); + + c->initConnection(); + QVERIFY(connectedSpy.wait()); + + QScopedPointer queue(new EventQueue); + queue->setup(c); + + QScopedPointer registry(new Registry); + QSignalSpy interfacesAnnouncedSpy(registry.data(), &Registry::interfacesAnnounced); + QVERIFY(interfacesAnnouncedSpy.isValid()); + registry->setEventQueue(queue.data()); + registry->create(c); + QVERIFY(registry->isValid()); + registry->setup(); + + QVERIFY(interfacesAnnouncedSpy.wait()); + QScopedPointer seat(registry->createSeat(registry->interface(Registry::Interface::Seat).name, + registry->interface(Registry::Interface::Seat).version)); + QVERIFY(seat->isValid()); + QScopedPointer ddm1(registry->createDataDeviceManager(registry->interface(Registry::Interface::DataDeviceManager).name, + registry->interface(Registry::Interface::DataDeviceManager).version)); + QVERIFY(ddm1->isValid()); + + // now create our first datadevice + QScopedPointer dd1(ddm1->getDataDevice(seat.data())); + QVERIFY(ddiCreatedSpy.wait()); + auto ddi = ddiCreatedSpy.first().first().value(); + QVERIFY(ddi); + m_seatInterface->setSelection(ddi); + + // switch to other client + // create a surface and pass it keyboard focus + QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); + QVERIFY(surfaceCreatedSpy.isValid()); + QScopedPointer surface(m_compositor->createSurface()); + QVERIFY(surface->isValid()); + QVERIFY(surfaceCreatedSpy.wait()); + auto serverSurface = surfaceCreatedSpy.first().first().value(); + m_seatInterface->setFocusedKeyboardSurface(serverSurface); + QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface); + + // now create a DataDevice + Registry registry2; + QSignalSpy dataDeviceManagerSpy(®istry2, &Registry::dataDeviceManagerAnnounced); + QVERIFY(dataDeviceManagerSpy.isValid()); + registry2.setEventQueue(m_queue); + registry2.create(m_connection->display()); + QVERIFY(registry2.isValid()); + registry2.setup(); + + QVERIFY(dataDeviceManagerSpy.wait()); + QScopedPointer ddm(registry2.createDataDeviceManager(dataDeviceManagerSpy.first().first().value(), + dataDeviceManagerSpy.first().last().value())); + QVERIFY(ddm->isValid()); + + QScopedPointer dd(ddm->getDataDevice(m_seat)); + QVERIFY(dd->isValid()); + QVERIFY(ddiCreatedSpy.wait()); + + // and delete the connection thread again + dd1.reset(); + ddm1.reset(); + seat.reset(); + registry.reset(); + queue.reset(); + c->deleteLater(); + thread->quit(); + thread->wait(); + delete thread; +} + void TestWaylandSeat::testTouch() { using namespace KWayland::Client; diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp index 28c8618d26..e18c0ecf7a 100644 --- a/src/wayland/seat_interface.cpp +++ b/src/wayland/seat_interface.cpp @@ -292,7 +292,7 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) // same client? if (keys.focus.surface->client() == dataDevice->client()) { keys.focus.selection = dataDevice; - if (currentSelection) { + if (currentSelection && currentSelection->selection()) { dataDevice->sendSelection(currentSelection); } }