[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
This commit is contained in:
Martin Gräßlin 2016-06-03 12:42:59 +02:00
parent b3ccc12b75
commit 076e8ba253
2 changed files with 31 additions and 2 deletions

View file

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

View file

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