Fix handling of the case where specified surface can't imported

An xdg_imported resource must be created no matter whether there is an
exported surface with the specified handle.

This change fixes handling of that case in kwaylandserver by introducing
a dummy imported object.

If there is no exported surface with the given handle, the compositor
should create an xdg_imported resource and immediately send the
destroyed event.

A dummy imported object is needed because generated code sets resource
implementation; otherwise we would set an implementation without any
user data to mark the resource as inert.
This commit is contained in:
Vlad Zahorodnii 2021-03-22 19:21:05 +02:00
parent d4901d16fa
commit a3ab80677c
3 changed files with 48 additions and 6 deletions

View file

@ -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"

View file

@ -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)

View file

@ -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