From e0f95fd913b6e7c9106ca153c0dd1e3d46c9e297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= Date: Wed, 6 Sep 2017 20:45:51 +0200 Subject: [PATCH] Delay syncing internal window geometry to end of cycle Summary: The syncing of the window geometry to the internal geometry can unfortunately cause a freeze in very special conditions: 1. create QML component 2. a Plasma::Dialog gets created 3. It creates the DialogShadows 4. This triggers QGlobalStatic creation which locks a non-recursive mutex 5. The creation of DialogShadows creates a Registry and triggers a roundtrip on the Wayland server 6. KWin processes all Wayland events 7. This triggers the creation of a ShellClient 8. The ShellClient has a PlasmaShellSurface which requested a position 9. The new geometry does not match the geometry of the Plasma::Dialog 10. ShellClient syncs the geometry to the Plasma::Dialog 11. Plasma::Dialog updates the theme because window geometry changed 12. This accesses the DialogShadows... which is still in the non recursive mutex and we have a freeze. By delaying the sync to the end of cycle we jump out of this deadly sequence. BUG: 384441 Test Plan: The freeze doesn't hit any more. It's possible that some test cases need adjustments. Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D7712 --- autotests/integration/internal_window.cpp | 6 +++--- shell_client.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/autotests/integration/internal_window.cpp b/autotests/integration/internal_window.cpp index 72957a27e2..f67da3faaa 100644 --- a/autotests/integration/internal_window.cpp +++ b/autotests/integration/internal_window.cpp @@ -538,11 +538,11 @@ void InternalWindowTest::testMove() // normal move should be synced internalClient->move(5, 10); QCOMPARE(internalClient->geometry(), QRect(5, 10, 100, 100)); - QCOMPARE(win.geometry(), QRect(5, 10, 100, 100)); + QTRY_COMPARE(win.geometry(), QRect(5, 10, 100, 100)); // another move should also be synced internalClient->move(10, 20); QCOMPARE(internalClient->geometry(), QRect(10, 20, 100, 100)); - QCOMPARE(win.geometry(), QRect(10, 20, 100, 100)); + QTRY_COMPARE(win.geometry(), QRect(10, 20, 100, 100)); // now move with a Geometry update blocker { @@ -552,7 +552,7 @@ void InternalWindowTest::testMove() QCOMPARE(win.geometry(), QRect(10, 20, 100, 100)); } // after destroying the blocker it should be synced - QCOMPARE(win.geometry(), QRect(5, 10, 100, 100)); + QTRY_COMPARE(win.geometry(), QRect(5, 10, 100, 100)); } void InternalWindowTest::testSkipCloseAnimation_data() diff --git a/shell_client.cpp b/shell_client.cpp index e4b169e677..c72105ceb0 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -543,7 +543,8 @@ void ShellClient::syncGeometryToInternalWindow() const QRect windowRect = QRect(geom.topLeft() + QPoint(borderLeft(), borderTop()), geom.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())); if (m_internalWindow->geometry() != windowRect) { - m_internalWindow->setGeometry(windowRect); + // delay to end of cycle to prevent freeze, see BUG 384441 + QTimer::singleShot(0, m_internalWindow, std::bind(static_cast(&QWindow::setGeometry), m_internalWindow, windowRect)); } }