diff --git a/src/wayland/autotests/client/test_error.cpp b/src/wayland/autotests/client/test_error.cpp index e57c2efa1c..a4f82cbf15 100644 --- a/src/wayland/autotests/client/test_error.cpp +++ b/src/wayland/autotests/client/test_error.cpp @@ -42,6 +42,8 @@ private Q_SLOTS: void cleanup(); void testMultipleShellSurfacesForSurface(); + void testTransientForSameSurface_data(); + void testTransientForSameSurface(); private: Display *m_display = nullptr; @@ -143,5 +145,27 @@ void ErrorTest::testMultipleShellSurfacesForSurface() QCOMPARE(m_connection->errorCode(), EPROTO); } +void ErrorTest::testTransientForSameSurface_data() +{ + QTest::addColumn("flag"); + + QTest::newRow("transient") << ShellSurface::TransientFlag::Default; + QTest::newRow("transient no focus") << ShellSurface::TransientFlag::NoFocus; +} + +void ErrorTest::testTransientForSameSurface() +{ + // this test verifies that creating a transient shell surface for itself triggers a protocol error + QSignalSpy errorSpy(m_connection, &ConnectionThread::errorOccurred); + QVERIFY(errorSpy.isValid()); + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer shellSurface(m_shell->createSurface(surface.data())); + QFETCH(ShellSurface::TransientFlag, flag); + shellSurface->setTransient(surface.data(), QPoint(), flag); + QVERIFY(errorSpy.wait()); + QVERIFY(m_connection->hasError()); + QCOMPARE(m_connection->errorCode(), EPROTO); +} + QTEST_GUILESS_MAIN(ErrorTest) #include "test_error.moc" diff --git a/src/wayland/server/shell_interface.cpp b/src/wayland/server/shell_interface.cpp index 07725eb50e..37f88f3488 100644 --- a/src/wayland/server/shell_interface.cpp +++ b/src/wayland/server/shell_interface.cpp @@ -147,7 +147,7 @@ void ShellInterface::Private::createSurface(wl_client *client, uint32_t version, } ); if (it != surfaces.constEnd()) { - wl_resource_post_error(surface->resource(), WL_DISPLAY_ERROR_INVALID_OBJECT, "ShellSurface already created"); + wl_resource_post_error(surface->resource(), WL_SHELL_ERROR_ROLE, "ShellSurface already created"); return; } ShellSurfaceInterface *shellSurface = new ShellSurfaceInterface(q, surface, parentResource); @@ -312,7 +312,12 @@ void ShellSurfaceInterface::Private::setTransientCallback(wl_client *client, wl_ Q_UNUSED(flags) auto s = cast(resource); Q_ASSERT(client == *s->client); - s->transientFor = QPointer(SurfaceInterface::get(parent)); + auto surface = SurfaceInterface::get(parent); + if (surface && s->surface == surface) { + wl_resource_post_error(surface->resource(), WL_SHELL_ERROR_ROLE, "Cannot be a transient to itself"); + return; + } + s->transientFor = QPointer(surface); s->transientOffset = QPoint(x, y); emit s->q_func()->transientChanged(!s->transientFor.isNull()); emit s->q_func()->transientOffsetChanged(s->transientOffset);