diff --git a/autotests/integration/xdgshellclient_test.cpp b/autotests/integration/xdgshellclient_test.cpp index 3ab8428563..3f8e17d663 100644 --- a/autotests/integration/xdgshellclient_test.cpp +++ b/autotests/integration/xdgshellclient_test.cpp @@ -99,11 +99,72 @@ private Q_SLOTS: void testXdgWindowGeometryInteractiveResize(); void testXdgWindowGeometryFullScreen(); void testXdgWindowGeometryMaximize(); + void testXdgWindowReactive(); + void testXdgWindowRepositioning(); void testPointerInputTransform(); void testReentrantSetFrameGeometry(); void testDoubleMaximize(); }; +void TestXdgShellClient::testXdgWindowReactive() +{ + QScopedPointer positioner(Test::createXdgPositioner()); + positioner->set_size(10, 10); + positioner->set_anchor_rect(10, 10, 10, 10); + positioner->set_reactive(); + + QScopedPointer rootSurface(Test::createSurface()); + QScopedPointer childSurface(Test::createSurface()); + + QScopedPointer root(Test::createXdgToplevelSurface(rootSurface.data())); + QScopedPointer popup(Test::createXdgPopupSurface(childSurface.data(), root->xdgSurface(), positioner.data())); + + auto rootClient = Test::renderAndWaitForShown(rootSurface.data(), QSize(100, 100), Qt::cyan); + auto childClient = Test::renderAndWaitForShown(childSurface.data(), QSize(10, 10), Qt::cyan); + + QVERIFY(rootClient); + QVERIFY(childClient); + + QSignalSpy frameGeometryChangedSpy(childClient, &AbstractClient::frameGeometryChanged); + QVERIFY(frameGeometryChangedSpy.isValid()); + + rootClient->move(rootClient->x()+20, rootClient->y()+20); + + QVERIFY(frameGeometryChangedSpy.wait()); + QCOMPARE(frameGeometryChangedSpy.count(), 1); +} + +void TestXdgShellClient::testXdgWindowRepositioning() +{ + QScopedPointer positioner(Test::createXdgPositioner()); + positioner->set_size(10, 10); + positioner->set_anchor_rect(10, 10, 10, 10); + + QScopedPointer otherPositioner(Test::createXdgPositioner()); + otherPositioner->set_size(50, 50); + otherPositioner->set_anchor_rect(10, 10, 10, 10); + + QScopedPointer rootSurface(Test::createSurface()); + QScopedPointer childSurface(Test::createSurface()); + + QScopedPointer root(Test::createXdgToplevelSurface(rootSurface.data())); + QScopedPointer popup(Test::createXdgPopupSurface(childSurface.data(), root->xdgSurface(), positioner.data())); + + auto rootClient = Test::renderAndWaitForShown(rootSurface.data(), QSize(100, 100), Qt::cyan); + auto childClient = Test::renderAndWaitForShown(childSurface.data(), QSize(10, 10), Qt::cyan); + + QVERIFY(rootClient); + QVERIFY(childClient); + + QSignalSpy reconfigureSpy(popup.data(), &Test::XdgPopup::configureRequested); + QVERIFY(reconfigureSpy.isValid()); + + popup->reposition(otherPositioner->object(), 500000); + + QVERIFY(reconfigureSpy.wait()); + QCOMPARE(reconfigureSpy.count(), 1); +} + void TestXdgShellClient::initTestCase() { qRegisterMetaType(); diff --git a/xdgshellclient.cpp b/xdgshellclient.cpp index 3fcfed4662..99e0486195 100644 --- a/xdgshellclient.cpp +++ b/xdgshellclient.cpp @@ -1705,10 +1705,37 @@ XdgPopupClient::XdgPopupClient(XdgPopupInterface *shellSurface) this, &XdgPopupClient::handleGrabRequested); connect(shellSurface, &XdgPopupInterface::initializeRequested, this, &XdgPopupClient::initialize); + connect(shellSurface, &XdgPopupInterface::repositionRequested, + this, &XdgPopupClient::handleRepositionRequested); connect(shellSurface, &XdgPopupInterface::destroyed, this, &XdgPopupClient::destroyClient); } +void XdgPopupClient::handlePositionerBindings() +{ + if (m_shellSurface->positioner().isReactive()) { + connect(transientFor(), &AbstractClient::frameGeometryChanged, + this, &XdgPopupClient::relayout, Qt::UniqueConnection); + } else { + disconnect(transientFor(), &AbstractClient::frameGeometryChanged, + this, &XdgPopupClient::relayout); + } +} + +void XdgPopupClient::handleRepositionRequested(quint32 token) +{ + handlePositionerBindings(); + m_shellSurface->sendRepositioned(token); + relayout(); +} + +void XdgPopupClient::relayout() +{ + GeometryUpdatesBlocker blocker(this); + Placement::self()->place(this, QRect()); + scheduleConfigure(ConfigureRequired); +} + XdgPopupClient::~XdgPopupClient() { } diff --git a/xdgshellclient.h b/xdgshellclient.h index eeed71f6c8..35360917cf 100644 --- a/xdgshellclient.h +++ b/xdgshellclient.h @@ -249,7 +249,10 @@ protected: private: void handleGrabRequested(KWaylandServer::SeatInterface *seat, quint32 serial); + void handlePositionerBindings(); + void handleRepositionRequested(quint32 token); void initialize(); + void relayout(); KWaylandServer::XdgPopupInterface *m_shellSurface; bool m_haveExplicitGrab = false;