diff --git a/autotests/integration/internal_window.cpp b/autotests/integration/internal_window.cpp index b1b2072311..45be338486 100644 --- a/autotests/integration/internal_window.cpp +++ b/autotests/integration/internal_window.cpp @@ -58,6 +58,7 @@ private Q_SLOTS: void testKeyboardTriggersLeave(); void testTouch(); void testOpacity(); + void testMove(); }; class HelperWindow : public QRasterWindow @@ -518,6 +519,40 @@ void InternalWindowTest::testOpacity() QCOMPARE(internalClient->opacity(), 0.75); } +void InternalWindowTest::testMove() +{ + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + HelperWindow win; + win.setOpacity(0.5); + win.setGeometry(0, 0, 100, 100); + win.show(); + QVERIFY(clientAddedSpy.wait()); + QCOMPARE(clientAddedSpy.count(), 1); + auto internalClient = clientAddedSpy.first().first().value(); + QVERIFY(internalClient); + QCOMPARE(internalClient->geometry(), QRect(0, 0, 100, 100)); + + // 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)); + // 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)); + + // now move with a Geometry update blocker + { + GeometryUpdatesBlocker blocker(internalClient); + internalClient->move(5, 10); + // not synced! + QCOMPARE(win.geometry(), QRect(10, 20, 100, 100)); + } + // after destroying the blocker it should be synced + QCOMPARE(win.geometry(), QRect(5, 10, 100, 100)); +} + } WAYLANDTEST_MAIN(KWin::InternalWindowTest) diff --git a/shell_client.cpp b/shell_client.cpp index 56ea20a6dc..172f10e2a4 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -482,7 +482,7 @@ void ShellClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force) void ShellClient::doSetGeometry(const QRect &rect) { - if (geom == rect) { + if (geom == rect && pendingGeometryUpdate() == PendingGeometryNone) { return; } if (!m_unmapped) { @@ -499,19 +499,32 @@ void ShellClient::doSetGeometry(const QRect &rect) if (!m_unmapped) { addWorkspaceRepaint(visibleRect()); } - if (m_internalWindow) { - 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); - } - } + syncGeometryToInternalWindow(); if (hasStrut()) { workspace()->updateClientArea(); } emit geometryShapeChanged(this, old); } +void ShellClient::doMove(int x, int y) +{ + Q_UNUSED(x) + Q_UNUSED(y) + syncGeometryToInternalWindow(); +} + +void ShellClient::syncGeometryToInternalWindow() +{ + if (!m_internalWindow) { + return; + } + 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); + } +} + QByteArray ShellClient::windowRole() const { return QByteArray(); diff --git a/shell_client.h b/shell_client.h index 32b612a801..6c3f38eb86 100644 --- a/shell_client.h +++ b/shell_client.h @@ -150,6 +150,7 @@ protected: bool isWaitingForMoveResizeSync() const override; bool acceptsFocus() const override; void doMinimize() override; + void doMove(int x, int y) override; private Q_SLOTS: void clientFullScreenChanged(bool fullScreen); @@ -166,6 +167,7 @@ private: void createWindowId(); void findInternalWindow(); void updateInternalWindowGeometry(); + void syncGeometryToInternalWindow(); void updateIcon(); void markAsMapped(); void setTransient();