diff --git a/src/wayland/autotests/client/test_xdg_foreign.cpp b/src/wayland/autotests/client/test_xdg_foreign.cpp index 8827b66c0e..c042aaf91b 100644 --- a/src/wayland/autotests/client/test_xdg_foreign.cpp +++ b/src/wayland/autotests/client/test_xdg_foreign.cpp @@ -37,6 +37,7 @@ private Q_SLOTS: void testDeleteExported(); void testExportTwoTimes(); void testImportTwoTimes(); + void testImportInvalidToplevel(); private: void doExport(); @@ -353,5 +354,17 @@ void TestForeign::testImportTwoTimes() QCOMPARE(m_foreignInterface->transientFor(childSurface2Interface), m_exportedSurfaceInterface.data()); } +void TestForeign::testImportInvalidToplevel() +{ + // This test verifies that the compositor properly handles the case where a client + // attempts to import a toplevel with an invalid handle. + + KWayland::Client::XdgImported *imported = m_importer->importTopLevel(QStringLiteral("foobar")); + QVERIFY(imported->isValid()); + + QSignalSpy importedDestroySpy(imported, &KWayland::Client::XdgImported::importedDestroyed); + QVERIFY(importedDestroySpy.wait()); +} + QTEST_GUILESS_MAIN(TestForeign) #include "test_xdg_foreign.moc" diff --git a/src/wayland/xdgforeign_v2_interface.cpp b/src/wayland/xdgforeign_v2_interface.cpp index eef5b4674b..eacae5167c 100644 --- a/src/wayland/xdgforeign_v2_interface.cpp +++ b/src/wayland/xdgforeign_v2_interface.cpp @@ -111,12 +111,6 @@ void XdgImporterV2Interface::zxdg_importer_v2_destroy(Resource *resource) void XdgImporterV2Interface::zxdg_importer_v2_import_toplevel(Resource *resource, uint32_t id, const QString &handle) { - XdgExportedV2Interface *exported = m_foreign->d->exporter->exportedSurface(handle); - if (!exported) { - zxdg_imported_v2_send_destroyed(resource->handle); - return; - } - wl_resource *importedResource = wl_resource_create(resource->client(), &zxdg_imported_v2_interface, resource->version(), id); @@ -125,6 +119,15 @@ void XdgImporterV2Interface::zxdg_importer_v2_import_toplevel(Resource *resource return; } + // If there is no exported surface with the specified handle, we must still create an + // inert xdg_imported object and send the destroyed event right afterwards. + XdgExportedV2Interface *exported = m_foreign->d->exporter->exportedSurface(handle); + if (!exported) { + auto imported = new XdgDummyImportedV2Interface(importedResource); + imported->send_destroyed(); + return; + } + XdgImportedV2Interface *imported = new XdgImportedV2Interface(exported, importedResource); connect(imported, &XdgImportedV2Interface::childChanged, this, [this, imported](SurfaceInterface *child) { @@ -196,6 +199,22 @@ void XdgExportedV2Interface::handleSurfaceDestroyed() delete this; } +XdgDummyImportedV2Interface::XdgDummyImportedV2Interface(wl_resource *resource) + : QtWaylandServer::zxdg_imported_v2(resource) +{ +} + +void XdgDummyImportedV2Interface::zxdg_imported_v2_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XdgDummyImportedV2Interface::zxdg_imported_v2_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + XdgImportedV2Interface::XdgImportedV2Interface(XdgExportedV2Interface *exported, wl_resource *resource) : QtWaylandServer::zxdg_imported_v2(resource) , m_exported(exported) diff --git a/src/wayland/xdgforeign_v2_interface_p.h b/src/wayland/xdgforeign_v2_interface_p.h index 0aad4a81ea..f3006e8d5c 100644 --- a/src/wayland/xdgforeign_v2_interface_p.h +++ b/src/wayland/xdgforeign_v2_interface_p.h @@ -87,6 +87,16 @@ private: SurfaceInterface *m_surface; }; +class XdgDummyImportedV2Interface : public QtWaylandServer::zxdg_imported_v2 +{ +public: + explicit XdgDummyImportedV2Interface(wl_resource *resource); + +protected: + void zxdg_imported_v2_destroy(Resource *resource) override; + void zxdg_imported_v2_destroy_resource(Resource *resource) override; +}; + class XdgImportedV2Interface : public QObject, QtWaylandServer::zxdg_imported_v2 { Q_OBJECT