[wayland] Finish active move-resize op when client is destroyed or unmapped

Summary:
It might happen that the moving client gets closed or crashes. In that
case, we have to manually reset Workspace::movingClient, otherwise KWin
will most likely crash later on.

BUG: 405379

Reviewers: #kwin, davidedmundson

Reviewed By: #kwin, davidedmundson

Subscribers: davidedmundson, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D19708
This commit is contained in:
Vlad Zagorodniy 2019-03-12 11:35:17 +02:00
parent 3024a7358b
commit f10760d8a9
2 changed files with 176 additions and 0 deletions

View file

@ -80,6 +80,10 @@ private Q_SLOTS:
void testResizeForVirtualKeyboard();
void testResizeForVirtualKeyboardWithMaximize();
void testResizeForVirtualKeyboardWithFullScreen();
void testDestroyMoveClient();
void testDestroyResizeClient();
void testUnmapMoveClient();
void testUnmapResizeClient();
private:
KWayland::Client::ConnectionThread *m_connection = nullptr;
@ -986,6 +990,172 @@ void MoveResizeWindowTest::testResizeForVirtualKeyboardWithFullScreen()
QCOMPARE(client->geometry(), QRect(0, 0, 1280, 1024));
}
void MoveResizeWindowTest::testDestroyMoveClient()
{
// This test verifies that active move operation gets finished when
// the associated client is destroyed.
// Create the test client.
using namespace KWayland::Client;
QScopedPointer<Surface> surface(Test::createSurface());
QVERIFY(!surface.isNull());
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(surface.data()));
QVERIFY(!shellSurface.isNull());
ShellClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
QVERIFY(client);
// Start moving the client.
QSignalSpy clientStartMoveResizedSpy(client, &AbstractClient::clientStartUserMovedResized);
QVERIFY(clientStartMoveResizedSpy.isValid());
QSignalSpy clientFinishUserMovedResizedSpy(client, &AbstractClient::clientFinishUserMovedResized);
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
QCOMPARE(workspace()->getMovingClient(), nullptr);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), false);
workspace()->slotWindowMove();
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
QCOMPARE(workspace()->getMovingClient(), client);
QCOMPARE(client->isMove(), true);
QCOMPARE(client->isResize(), false);
// Let's pretend that the client crashed.
shellSurface.reset();
surface.reset();
QVERIFY(Test::waitForWindowDestroyed(client));
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 0);
QCOMPARE(workspace()->getMovingClient(), nullptr);
}
void MoveResizeWindowTest::testDestroyResizeClient()
{
// This test verifies that active resize operation gets finished when
// the associated client is destroyed.
// Create the test client.
using namespace KWayland::Client;
QScopedPointer<Surface> surface(Test::createSurface());
QVERIFY(!surface.isNull());
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(surface.data()));
QVERIFY(!shellSurface.isNull());
ShellClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
QVERIFY(client);
// Start resizing the client.
QSignalSpy clientStartMoveResizedSpy(client, &AbstractClient::clientStartUserMovedResized);
QVERIFY(clientStartMoveResizedSpy.isValid());
QSignalSpy clientFinishUserMovedResizedSpy(client, &AbstractClient::clientFinishUserMovedResized);
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
QCOMPARE(workspace()->getMovingClient(), nullptr);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), false);
workspace()->slotWindowResize();
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
QCOMPARE(workspace()->getMovingClient(), client);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), true);
// Let's pretend that the client crashed.
shellSurface.reset();
surface.reset();
QVERIFY(Test::waitForWindowDestroyed(client));
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 0);
QCOMPARE(workspace()->getMovingClient(), nullptr);
}
void MoveResizeWindowTest::testUnmapMoveClient()
{
// This test verifies that active move operation gets cancelled when
// the associated client is unmapped.
// Create the test client.
using namespace KWayland::Client;
QScopedPointer<Surface> surface(Test::createSurface());
QVERIFY(!surface.isNull());
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(surface.data()));
QVERIFY(!shellSurface.isNull());
ShellClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
QVERIFY(client);
// Start resizing the client.
QSignalSpy clientStartMoveResizedSpy(client, &AbstractClient::clientStartUserMovedResized);
QVERIFY(clientStartMoveResizedSpy.isValid());
QSignalSpy clientFinishUserMovedResizedSpy(client, &AbstractClient::clientFinishUserMovedResized);
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
QCOMPARE(workspace()->getMovingClient(), nullptr);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), false);
workspace()->slotWindowMove();
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
QCOMPARE(workspace()->getMovingClient(), client);
QCOMPARE(client->isMove(), true);
QCOMPARE(client->isResize(), false);
// Unmap the client while we're moving it.
QSignalSpy hiddenSpy(client, &ShellClient::windowHidden);
QVERIFY(hiddenSpy.isValid());
surface->attachBuffer(Buffer::Ptr());
surface->commit(Surface::CommitFlag::None);
QVERIFY(hiddenSpy.wait());
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 0);
QCOMPARE(workspace()->getMovingClient(), nullptr);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), false);
// Destroy the client.
shellSurface.reset();
QVERIFY(Test::waitForWindowDestroyed(client));
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 0);
}
void MoveResizeWindowTest::testUnmapResizeClient()
{
// This test verifies that active resize operation gets cancelled when
// the associated client is unmapped.
// Create the test client.
using namespace KWayland::Client;
QScopedPointer<Surface> surface(Test::createSurface());
QVERIFY(!surface.isNull());
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(surface.data()));
QVERIFY(!shellSurface.isNull());
ShellClient *client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
QVERIFY(client);
// Start resizing the client.
QSignalSpy clientStartMoveResizedSpy(client, &AbstractClient::clientStartUserMovedResized);
QVERIFY(clientStartMoveResizedSpy.isValid());
QSignalSpy clientFinishUserMovedResizedSpy(client, &AbstractClient::clientFinishUserMovedResized);
QVERIFY(clientFinishUserMovedResizedSpy.isValid());
QCOMPARE(workspace()->getMovingClient(), nullptr);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), false);
workspace()->slotWindowResize();
QCOMPARE(clientStartMoveResizedSpy.count(), 1);
QCOMPARE(workspace()->getMovingClient(), client);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), true);
// Unmap the client while we're resizing it.
QSignalSpy hiddenSpy(client, &ShellClient::windowHidden);
QVERIFY(hiddenSpy.isValid());
surface->attachBuffer(Buffer::Ptr());
surface->commit(Surface::CommitFlag::None);
QVERIFY(hiddenSpy.wait());
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 0);
QCOMPARE(workspace()->getMovingClient(), nullptr);
QCOMPARE(client->isMove(), false);
QCOMPARE(client->isResize(), false);
// Destroy the client.
shellSurface.reset();
QVERIFY(Test::waitForWindowDestroyed(client));
QCOMPARE(clientFinishUserMovedResizedSpy.count(), 0);
}
}
WAYLANDTEST_MAIN(KWin::MoveResizeWindowTest)

View file

@ -386,6 +386,9 @@ void ShellClient::finishInit() {
void ShellClient::destroyClient()
{
m_closing = true;
if (isMoveResize()) {
leaveMoveResize();
}
Deleted *del = nullptr;
if (workspace()) {
del = Deleted::create(this);
@ -1188,6 +1191,9 @@ void ShellClient::resizeWithChecks(int w, int h, ForceGeometry_t force)
void ShellClient::unmap()
{
m_unmapped = true;
if (isMoveResize()) {
leaveMoveResize();
}
m_requestedClientSize = QSize(0, 0);
destroyWindowManagementInterface();
if (Workspace::self()) {