Handle restart of Compositor Scene correctly for Wayland client

Summary:
This change ensures that KWin doesn't crash in the QPainter scene if
the compositor gets restarted and if there are Wayland clients.

BUG: 365471

Test Plan:
Test case added to scene qpainter which triggers a restart
of the Compositor with a window being shown. Verifies that rendering
is correct afterwards.

Reviewers: #kwin, #plasma_on_wayland

Subscribers: plasma-devel, kwin

Tags: #plasma_on_wayland, #kwin

Differential Revision: https://phabricator.kde.org/D2185
This commit is contained in:
Martin Gräßlin 2016-07-15 16:06:09 +02:00
parent 904b18a421
commit 3308f35984
2 changed files with 60 additions and 0 deletions

View file

@ -49,6 +49,8 @@ private Q_SLOTS:
void testCursorMoving();
void testWindow_data();
void testWindow();
void testCompositorRestart_data();
void testCompositorRestart();
};
void SceneQPainterTest::cleanup()
@ -188,5 +190,56 @@ void SceneQPainterTest::testWindow()
QCOMPARE(referenceImage, *scene->backend()->buffer());
}
void SceneQPainterTest::testCompositorRestart_data()
{
QTest::addColumn<Test::ShellSurfaceType>("type");
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
}
void SceneQPainterTest::testCompositorRestart()
{
// this test verifies that the compositor/SceneQPainter survive a restart of the compositor and still render correctly
KWin::Cursor::setPos(400, 400);
// first create a window
using namespace KWayland::Client;
QVERIFY(Test::setupWaylandConnection(s_socketName));
QScopedPointer<Surface> s(Test::createSurface());
QFETCH(Test::ShellSurfaceType, type);
QScopedPointer<QObject> ss(Test::createShellSurface(type, s.data()));
QVERIFY(Test::renderAndWaitForShown(s.data(), QSize(200, 300), Qt::blue));
// now let's try to reinitialize the compositing scene
auto oldScene = KWin::Compositor::self()->scene();
QVERIFY(oldScene);
QSignalSpy sceneCreatedSpy(KWin::Compositor::self(), &KWin::Compositor::sceneCreated);
QVERIFY(sceneCreatedSpy.isValid());
KWin::Compositor::self()->slotReinitialize();
if (sceneCreatedSpy.isEmpty()) {
QVERIFY(sceneCreatedSpy.wait());
}
QCOMPARE(sceneCreatedSpy.count(), 1);
auto scene = qobject_cast<SceneQPainter*>(KWin::Compositor::self()->scene());
QVERIFY(scene);
// this should directly trigger a frame
KWin::Compositor::self()->addRepaintFull();
QSignalSpy frameRenderedSpy(scene, &Scene::frameRendered);
QVERIFY(frameRenderedSpy.isValid());
QVERIFY(frameRenderedSpy.wait());
// render reference image
QImage referenceImage(QSize(1280, 1024), QImage::Format_RGB32);
referenceImage.fill(Qt::black);
QPainter painter(&referenceImage);
painter.fillRect(0, 0, 200, 300, Qt::blue);
const QImage cursorImage = kwinApp()->platform()->softwareCursor();
QVERIFY(!cursorImage.isNull());
painter.drawImage(QPoint(400, 400) - kwinApp()->platform()->softwareCursorHotspot(), cursorImage);
QCOMPARE(referenceImage, *scene->backend()->buffer());
}
WAYLANDTEST_MAIN(SceneQPainterTest)
#include "scene_qpainter_test.moc"

View file

@ -324,6 +324,13 @@ void Compositor::startupWithWorkspace()
c->setupCompositing();
c->getShadow();
}
if (auto w = waylandServer()) {
const auto clients = w->clients();
for (auto c : clients) {
c->setupCompositing();
c->getShadow();
}
}
emit compositingToggled(true);