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
master
Martin Flöser 7 years ago
parent d1e0c6f9d7
commit e0f95fd913

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

@ -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<void (QWindow::*)(const QRect&)>(&QWindow::setGeometry), m_internalWindow, windowRect));
}
}

Loading…
Cancel
Save