From 3308f359848fc193b3c9d222179bc58136bea834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 15 Jul 2016 16:06:09 +0200 Subject: [PATCH] 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 --- autotests/integration/scene_qpainter_test.cpp | 53 +++++++++++++++++++ composite.cpp | 7 +++ 2 files changed, 60 insertions(+) diff --git a/autotests/integration/scene_qpainter_test.cpp b/autotests/integration/scene_qpainter_test.cpp index ee6cbae5f3..73158b3f2c 100644 --- a/autotests/integration/scene_qpainter_test.cpp +++ b/autotests/integration/scene_qpainter_test.cpp @@ -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("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 s(Test::createSurface()); + QFETCH(Test::ShellSurfaceType, type); + QScopedPointer 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(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" diff --git a/composite.cpp b/composite.cpp index cc43d0bbb4..62775f67cc 100644 --- a/composite.cpp +++ b/composite.cpp @@ -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);