* Upstream fix to prevent kwin from crashing when opening systemsettings (kde#389231) OBS-URL: https://build.opensuse.org/package/show/KDE:Frameworks5/kwayland?expand=0&rev=137
134 lines
5.6 KiB
Diff
134 lines
5.6 KiB
Diff
From abfd8c2f896bf38c703755952bb3c955ff83a8f1 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= <mgraesslin@kde.org>
|
|
Date: Tue, 6 Feb 2018 16:57:59 +0100
|
|
Subject: [PATCH] [server] Don't crash when a subsurface gets commited whose
|
|
parent surface got destroyed
|
|
|
|
Summary:
|
|
Qt seems to damage and commit child subsurfaces although their parent
|
|
got destroyed. This actually doesn't make any sense as without a parent
|
|
surface they cannot be shown. But nevertheless we should not crash in
|
|
such a situation.
|
|
|
|
This change guards the places in the commit handling code where the
|
|
parent gets accessed.
|
|
|
|
BUG: 389231
|
|
|
|
Test Plan: New test case which exposes the problem
|
|
|
|
Reviewers: #frameworks, #kwin, #plasma, davidedmundson
|
|
|
|
Reviewed By: #plasma, davidedmundson
|
|
|
|
Subscribers: plasma-devel
|
|
|
|
Tags: #frameworks, #plasma_on_wayland
|
|
|
|
Differential Revision: https://phabricator.kde.org/D10300
|
|
---
|
|
autotests/client/test_wayland_subsurface.cpp | 47 ++++++++++++++++++++++++++++
|
|
src/server/subcompositor_interface.cpp | 3 ++
|
|
src/server/surface_interface.cpp | 7 +++--
|
|
3 files changed, 55 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/autotests/client/test_wayland_subsurface.cpp b/autotests/client/test_wayland_subsurface.cpp
|
|
index 42c326a..dc53a1b 100644
|
|
--- a/autotests/client/test_wayland_subsurface.cpp
|
|
+++ b/autotests/client/test_wayland_subsurface.cpp
|
|
@@ -59,6 +59,7 @@ private Q_SLOTS:
|
|
void testMappingOfSurfaceTree();
|
|
void testSurfaceAt();
|
|
void testDestroyAttachedBuffer();
|
|
+ void testDestroyParentSurface();
|
|
|
|
private:
|
|
KWayland::Server::Display *m_display;
|
|
@@ -1041,5 +1042,51 @@ void TestSubSurface::testDestroyAttachedBuffer()
|
|
QVERIFY(destroySpy.wait());
|
|
}
|
|
|
|
+void TestSubSurface::testDestroyParentSurface()
|
|
+{
|
|
+ // this test verifies that destroying a parent surface does not create problems
|
|
+ // see BUG 389231
|
|
+ using namespace KWayland::Client;
|
|
+ using namespace KWayland::Server;
|
|
+ // create surface
|
|
+ QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
|
+ QVERIFY(serverSurfaceCreated.isValid());
|
|
+ QScopedPointer<Surface> parent(m_compositor->createSurface());
|
|
+ QVERIFY(serverSurfaceCreated.wait());
|
|
+ SurfaceInterface *serverParentSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
|
+ QScopedPointer<Surface> child(m_compositor->createSurface());
|
|
+ QVERIFY(serverSurfaceCreated.wait());
|
|
+ SurfaceInterface *serverChildSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
|
+ QScopedPointer<Surface> grandChild(m_compositor->createSurface());
|
|
+ QVERIFY(serverSurfaceCreated.wait());
|
|
+ SurfaceInterface *serverGrandChildSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
|
+ // create sub-surface in desynchronized mode as Qt uses them
|
|
+ auto sub1 = m_subCompositor->createSubSurface(child.data(), parent.data());
|
|
+ sub1->setMode(SubSurface::Mode::Desynchronized);
|
|
+ auto sub2 = m_subCompositor->createSubSurface(grandChild.data(), child.data());
|
|
+ sub2->setMode(SubSurface::Mode::Desynchronized);
|
|
+
|
|
+ // let's damage this surface
|
|
+ // and at the same time delete the parent surface
|
|
+ parent.reset();
|
|
+ QSignalSpy parentDestroyedSpy(serverParentSurface, &QObject::destroyed);
|
|
+ QVERIFY(parentDestroyedSpy.isValid());
|
|
+ QVERIFY(parentDestroyedSpy.wait());
|
|
+ QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
|
|
+ image.fill(Qt::red);
|
|
+ grandChild->attachBuffer(m_shm->createBuffer(image));
|
|
+ grandChild->damage(QRect(0, 0, 100, 100));
|
|
+ grandChild->commit(Surface::CommitFlag::None);
|
|
+ QSignalSpy damagedSpy(serverGrandChildSurface, &SurfaceInterface::damaged);
|
|
+ QVERIFY(damagedSpy.isValid());
|
|
+ QVERIFY(damagedSpy.wait());
|
|
+
|
|
+ // Let's try to destroy it
|
|
+ QSignalSpy destroySpy(serverChildSurface, &QObject::destroyed);
|
|
+ QVERIFY(destroySpy.isValid());
|
|
+ child.reset();
|
|
+ QVERIFY(destroySpy.wait());
|
|
+}
|
|
+
|
|
QTEST_GUILESS_MAIN(TestSubSurface)
|
|
#include "test_wayland_subsurface.moc"
|
|
diff --git a/src/server/subcompositor_interface.cpp b/src/server/subcompositor_interface.cpp
|
|
index f829ab2..f2b6de9 100644
|
|
--- a/src/server/subcompositor_interface.cpp
|
|
+++ b/src/server/subcompositor_interface.cpp
|
|
@@ -360,6 +360,9 @@ bool SubSurfaceInterface::isSynchronized() const
|
|
QPointer<SurfaceInterface> SubSurfaceInterface::mainSurface() const
|
|
{
|
|
Q_D();
|
|
+ if (!d->parent) {
|
|
+ return QPointer<SurfaceInterface>();
|
|
+ }
|
|
if (d->parent->d_func()->subSurface) {
|
|
return d->parent->d_func()->subSurface->mainSurface();
|
|
}
|
|
diff --git a/src/server/surface_interface.cpp b/src/server/surface_interface.cpp
|
|
index 5102271..3787794 100644
|
|
--- a/src/server/surface_interface.cpp
|
|
+++ b/src/server/surface_interface.cpp
|
|
@@ -453,8 +453,11 @@ void SurfaceInterface::Private::swapStates(State *source, State *target, bool em
|
|
emit q->damaged(target->damage);
|
|
// workaround for https://bugreports.qt.io/browse/QTBUG-52092
|
|
// if the surface is a sub-surface, but the main surface is not yet mapped, fake frame rendered
|
|
- if (subSurface && !subSurface->mainSurface()->buffer()) {
|
|
- q->frameRendered(0);
|
|
+ if (subSurface) {
|
|
+ const auto mainSurface = subSurface->mainSurface();
|
|
+ if (!mainSurface || !mainSurface->buffer()) {
|
|
+ q->frameRendered(0);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
--
|
|
2.16.1
|
|
|