Commit 076e8ba2 authored by Martin Flöser's avatar Martin Flöser
Browse files

[server] Trigger error if a transient request tries to parent to itself

Summary:
If the surface passed in the transient request is to the surface of the
shell surface, KWin aborts. It's an obvious invalid request, so handle
it properly by sending an error.

Reviewers: #plasma

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D1755
parent b3ccc12b
......@@ -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<ShellSurface::TransientFlag>("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> surface(m_compositor->createSurface());
QScopedPointer<ShellSurface> 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"
......@@ -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<Private>(resource);
Q_ASSERT(client == *s->client);
s->transientFor = QPointer<SurfaceInterface>(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<SurfaceInterface>(surface);
s->transientOffset = QPoint(x, y);
emit s->q_func()->transientChanged(!s->transientFor.isNull());
emit s->q_func()->transientOffsetChanged(s->transientOffset);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment