diff --git a/autotests/integration/move_resize_window_test.cpp b/autotests/integration/move_resize_window_test.cpp --- a/autotests/integration/move_resize_window_test.cpp +++ b/autotests/integration/move_resize_window_test.cpp @@ -76,6 +76,10 @@ void testAdjustClientGeometryOfAutohidingX11Panel(); void testAdjustClientGeometryOfAutohidingWaylandPanel_data(); void testAdjustClientGeometryOfAutohidingWaylandPanel(); + void testDestroyMoveClient(); + void testDestroyResizeClient(); + void testUnmapMoveClient(); + void testUnmapResizeClient(); private: KWayland::Client::ConnectionThread *m_connection = nullptr; @@ -852,6 +856,172 @@ QVERIFY(windowClosedSpy.wait()); } +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(Test::createSurface()); + QVERIFY(!surface.isNull()); + QScopedPointer 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(), 1); + 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(Test::createSurface()); + QVERIFY(!surface.isNull()); + QScopedPointer 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(), 1); + 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(Test::createSurface()); + QVERIFY(!surface.isNull()); + QScopedPointer 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(), 1); + QCOMPARE(workspace()->getMovingClient(), nullptr); + QCOMPARE(client->isMove(), false); + QCOMPARE(client->isResize(), false); + + // Destroy the client. + shellSurface.reset(); + QVERIFY(Test::waitForWindowDestroyed(client)); + QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1); +} + +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(Test::createSurface()); + QVERIFY(!surface.isNull()); + QScopedPointer 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(), 1); + QCOMPARE(workspace()->getMovingClient(), nullptr); + QCOMPARE(client->isMove(), false); + QCOMPARE(client->isResize(), false); + + // Destroy the client. + shellSurface.reset(); + QVERIFY(Test::waitForWindowDestroyed(client)); + QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1); +} + } WAYLANDTEST_MAIN(KWin::MoveResizeWindowTest) diff --git a/shell_client.cpp b/shell_client.cpp --- a/shell_client.cpp +++ b/shell_client.cpp @@ -310,7 +310,7 @@ } ); auto configure = [this] { - if (m_closing) { + if (m_closing || m_unmapped) { return; } if (m_requestGeometryBlockCounter != 0 || areGeometryUpdatesBlocked()) { @@ -388,6 +388,12 @@ void ShellClient::destroyClient() { m_closing = true; + + if (isMoveResize()) { + leaveMoveResize(); + emit clientFinishUserMovedResized(this); + } + Deleted *del = nullptr; if (workspace()) { del = Deleted::create(this); @@ -1190,6 +1196,10 @@ void ShellClient::unmap() { m_unmapped = true; + if (isMoveResize()) { + leaveMoveResize(); + emit clientFinishUserMovedResized(this); + } m_requestedClientSize = QSize(0, 0); destroyWindowManagementInterface(); if (Workspace::self()) {