File indexing completed on 2024-11-10 04:56:03

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
0006     SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0007     SPDX-FileCopyrightText: 2023 Natalie Clarius <natalie_clarius@yahoo.de>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 #include "kwin_wayland_test.h"
0012 
0013 #include "core/output.h"
0014 #include "placement.h"
0015 #include "pointer_input.h"
0016 #include "wayland_server.h"
0017 #include "window.h"
0018 #include "workspace.h"
0019 
0020 #include <KWayland/Client/compositor.h>
0021 #include <KWayland/Client/shm_pool.h>
0022 #include <KWayland/Client/surface.h>
0023 
0024 using namespace KWin;
0025 
0026 static const QString s_socketName = QStringLiteral("wayland_test_kwin_placement-0");
0027 
0028 struct PlaceWindowResult
0029 {
0030     QSizeF initiallyConfiguredSize;
0031     Test::XdgToplevel::States initiallyConfiguredStates;
0032     QRectF finalGeometry;
0033 };
0034 
0035 class TestPlacement : public QObject
0036 {
0037     Q_OBJECT
0038 
0039 private Q_SLOTS:
0040     void init();
0041     void cleanup();
0042     void initTestCase();
0043 
0044     void testPlaceSmart();
0045     void testPlaceMaximized();
0046     void testPlaceMaximizedLeavesFullscreen();
0047     void testPlaceCentered();
0048     void testPlaceUnderMouse();
0049     void testPlaceZeroCornered();
0050     void testPlaceRandom();
0051     void testFullscreen();
0052     void testCascadeIfCovering();
0053     void testCascadeIfCoveringIgnoreNonCovering();
0054     void testCascadeIfCoveringIgnoreOutOfArea();
0055     void testCascadeIfCoveringIgnoreAlreadyCovered();
0056 
0057 private:
0058     void setPlacementPolicy(PlacementPolicy policy);
0059     /*
0060      * Create a window and return relevant results for testing
0061      * defaultSize is the buffer size to use if the compositor returns an empty size in the first configure
0062      * event.
0063      */
0064     std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> createAndPlaceWindow(const QSize &defaultSize);
0065 };
0066 
0067 void TestPlacement::init()
0068 {
0069     QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::LayerShellV1));
0070 
0071     workspace()->setActiveOutput(QPoint(640, 512));
0072     KWin::input()->pointer()->warp(QPoint(640, 512));
0073 }
0074 
0075 void TestPlacement::cleanup()
0076 {
0077     Test::destroyWaylandConnection();
0078 }
0079 
0080 void TestPlacement::initTestCase()
0081 {
0082     qRegisterMetaType<KWin::Window *>();
0083     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0084     QVERIFY(waylandServer()->init(s_socketName));
0085     Test::setOutputConfig({
0086         QRect(0, 0, 1280, 1024),
0087         QRect(1280, 0, 1280, 1024),
0088     });
0089 
0090     kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
0091 
0092     kwinApp()->start();
0093     QVERIFY(applicationStartedSpy.wait());
0094     const auto outputs = workspace()->outputs();
0095     QCOMPARE(outputs.count(), 2);
0096     QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
0097     QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
0098 }
0099 
0100 void TestPlacement::setPlacementPolicy(PlacementPolicy policy)
0101 {
0102     auto group = kwinApp()->config()->group(QStringLiteral("Windows"));
0103     group.writeEntry("Placement", Placement::policyToString(policy));
0104     group.sync();
0105     Workspace::self()->slotReconfigure();
0106 }
0107 
0108 std::pair<PlaceWindowResult, std::unique_ptr<KWayland::Client::Surface>> TestPlacement::createAndPlaceWindow(const QSize &defaultSize)
0109 {
0110     PlaceWindowResult rc;
0111 
0112     // create a new window
0113     std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
0114     auto shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
0115 
0116     QSignalSpy toplevelConfigureRequestedSpy(shellSurface, &Test::XdgToplevel::configureRequested);
0117     QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
0118     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0119     surfaceConfigureRequestedSpy.wait();
0120 
0121     rc.initiallyConfiguredSize = toplevelConfigureRequestedSpy[0][0].toSize();
0122     rc.initiallyConfiguredStates = toplevelConfigureRequestedSpy[0][1].value<Test::XdgToplevel::States>();
0123     shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy[0][0].toUInt());
0124 
0125     QSizeF size = rc.initiallyConfiguredSize;
0126 
0127     if (size.isEmpty()) {
0128         size = defaultSize;
0129     }
0130 
0131     auto window = Test::renderAndWaitForShown(surface.get(), size.toSize(), Qt::red);
0132 
0133     rc.finalGeometry = window->frameGeometry();
0134     return {rc, std::move(surface)};
0135 }
0136 
0137 void TestPlacement::testPlaceSmart()
0138 {
0139     const auto outputs = workspace()->outputs();
0140     const QList<QRect> desiredGeometries{
0141         QRect(0, 0, 600, 500),
0142         QRect(600, 0, 600, 500),
0143         QRect(0, 500, 600, 500),
0144         QRect(600, 500, 600, 500),
0145         QRect(680, 524, 600, 500),
0146         QRect(680, 0, 600, 500),
0147         QRect(0, 524, 600, 500),
0148         QRect(0, 0, 600, 500),
0149     };
0150 
0151     setPlacementPolicy(PlacementSmart);
0152 
0153     std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
0154 
0155     for (const QRect &desiredGeometry : desiredGeometries) {
0156         auto [windowPlacement, surface] = createAndPlaceWindow(QSize(600, 500));
0157         surfaces.push_back(std::move(surface));
0158 
0159         // smart placement shouldn't define a size on windows
0160         QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(0, 0));
0161         QCOMPARE(windowPlacement.finalGeometry.size(), QSize(600, 500));
0162 
0163         QVERIFY(outputs[0]->geometry().contains(windowPlacement.finalGeometry.toRect()));
0164 
0165         QCOMPARE(windowPlacement.finalGeometry.toRect(), desiredGeometry);
0166     }
0167 }
0168 
0169 void TestPlacement::testPlaceMaximized()
0170 {
0171     setPlacementPolicy(PlacementMaximizing);
0172 
0173     // add a top panel
0174     std::unique_ptr<KWayland::Client::Surface> panelSurface{Test::createSurface()};
0175     std::unique_ptr<Test::LayerSurfaceV1> panelShellSurface{Test::createLayerSurfaceV1(panelSurface.get(), QStringLiteral("dock"))};
0176     panelShellSurface->set_size(1280, 20);
0177     panelShellSurface->set_anchor(Test::LayerSurfaceV1::anchor_top);
0178     panelShellSurface->set_exclusive_zone(20);
0179     panelSurface->commit(KWayland::Client::Surface::CommitFlag::None);
0180     QSignalSpy panelConfigureRequestedSpy(panelShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0181     QVERIFY(panelConfigureRequestedSpy.wait());
0182     Test::renderAndWaitForShown(panelSurface.get(), panelConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
0183 
0184     std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
0185 
0186     // all windows should be initially maximized with an initial configure size sent
0187     for (int i = 0; i < 4; i++) {
0188         auto [windowPlacement, surface] = createAndPlaceWindow(QSize(600, 500));
0189         QVERIFY(windowPlacement.initiallyConfiguredStates & Test::XdgToplevel::State::Maximized);
0190         QCOMPARE(windowPlacement.initiallyConfiguredSize, QSize(1280, 1024 - 20));
0191         QCOMPARE(windowPlacement.finalGeometry, QRect(0, 20, 1280, 1024 - 20)); // under the panel
0192         surfaces.push_back(std::move(surface));
0193     }
0194 }
0195 
0196 void TestPlacement::testPlaceMaximizedLeavesFullscreen()
0197 {
0198     setPlacementPolicy(PlacementMaximizing);
0199 
0200     // add a top panel
0201     std::unique_ptr<KWayland::Client::Surface> panelSurface{Test::createSurface()};
0202     std::unique_ptr<Test::LayerSurfaceV1> panelShellSurface{Test::createLayerSurfaceV1(panelSurface.get(), QStringLiteral("dock"))};
0203     panelShellSurface->set_size(1280, 20);
0204     panelShellSurface->set_anchor(Test::LayerSurfaceV1::anchor_top);
0205     panelShellSurface->set_exclusive_zone(20);
0206     panelSurface->commit(KWayland::Client::Surface::CommitFlag::None);
0207     QSignalSpy panelConfigureRequestedSpy(panelShellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0208     QVERIFY(panelConfigureRequestedSpy.wait());
0209     Test::renderAndWaitForShown(panelSurface.get(), panelConfigureRequestedSpy.last().at(1).toSize(), Qt::blue);
0210 
0211     std::vector<std::unique_ptr<KWayland::Client::Surface>> surfaces;
0212 
0213     // all windows should be initially fullscreen with an initial configure size sent, despite the policy
0214     for (int i = 0; i < 4; i++) {
0215         std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
0216         auto shellSurface = Test::createXdgToplevelSurface(surface.get(), Test::CreationSetup::CreateOnly, surface.get());
0217         shellSurface->set_fullscreen(nullptr);
0218         QSignalSpy toplevelConfigureRequestedSpy(shellSurface, &Test::XdgToplevel::configureRequested);
0219         QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
0220         surface->commit(KWayland::Client::Surface::CommitFlag::None);
0221         QVERIFY(surfaceConfigureRequestedSpy.wait());
0222 
0223         auto initiallyConfiguredSize = toplevelConfigureRequestedSpy[0][0].toSize();
0224         auto initiallyConfiguredStates = toplevelConfigureRequestedSpy[0][1].value<Test::XdgToplevel::States>();
0225         shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy[0][0].toUInt());
0226 
0227         auto window = Test::renderAndWaitForShown(surface.get(), initiallyConfiguredSize, Qt::red);
0228 
0229         QVERIFY(initiallyConfiguredStates & Test::XdgToplevel::State::Fullscreen);
0230         QCOMPARE(initiallyConfiguredSize, QSize(1280, 1024));
0231         QCOMPARE(window->frameGeometry(), QRect(0, 0, 1280, 1024));
0232 
0233         surfaces.push_back(std::move(surface));
0234     }
0235 }
0236 
0237 void TestPlacement::testPlaceCentered()
0238 {
0239     // This test verifies that Centered placement policy works.
0240 
0241     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0242     group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
0243     group.sync();
0244     workspace()->slotReconfigure();
0245 
0246     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0247     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0248     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::red);
0249     QVERIFY(window);
0250     QCOMPARE(window->frameGeometry(), QRect(590, 487, 100, 50));
0251 
0252     shellSurface.reset();
0253     QVERIFY(Test::waitForWindowClosed(window));
0254 }
0255 
0256 void TestPlacement::testPlaceUnderMouse()
0257 {
0258     // This test verifies that Under Mouse placement policy works.
0259 
0260     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0261     group.writeEntry("Placement", Placement::policyToString(PlacementUnderMouse));
0262     group.sync();
0263     workspace()->slotReconfigure();
0264 
0265     KWin::input()->pointer()->warp(QPoint(200, 300));
0266     QCOMPARE(KWin::Cursors::self()->mouse()->pos(), QPoint(200, 300));
0267 
0268     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0269     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0270     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::red);
0271     QVERIFY(window);
0272     QCOMPARE(window->frameGeometry(), QRect(150, 275, 100, 50));
0273 
0274     shellSurface.reset();
0275     QVERIFY(Test::waitForWindowClosed(window));
0276 }
0277 
0278 void TestPlacement::testPlaceZeroCornered()
0279 {
0280     // This test verifies that the Zero-Cornered placement policy works.
0281 
0282     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0283     group.writeEntry("Placement", Placement::policyToString(PlacementZeroCornered));
0284     group.sync();
0285     workspace()->slotReconfigure();
0286 
0287     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0288     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0289     Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
0290     QVERIFY(window1);
0291     QCOMPARE(window1->pos(), QPoint(0, 0));
0292     QCOMPARE(window1->size(), QSize(100, 50));
0293 
0294     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0295     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0296     Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
0297     QVERIFY(window2);
0298     QCOMPARE(window2->pos(), window1->pos() + workspace()->cascadeOffset(window2));
0299     QCOMPARE(window2->size(), QSize(100, 50));
0300 
0301     std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
0302     std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
0303     Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
0304     QVERIFY(window3);
0305     QCOMPARE(window3->pos(), window2->pos() + workspace()->cascadeOffset(window3));
0306     QCOMPARE(window3->size(), QSize(100, 50));
0307 
0308     shellSurface3.reset();
0309     QVERIFY(Test::waitForWindowClosed(window3));
0310     shellSurface2.reset();
0311     QVERIFY(Test::waitForWindowClosed(window2));
0312     shellSurface1.reset();
0313     QVERIFY(Test::waitForWindowClosed(window1));
0314 }
0315 
0316 void TestPlacement::testPlaceRandom()
0317 {
0318     // This test verifies that Random placement policy works.
0319 
0320     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0321     group.writeEntry("Placement", Placement::policyToString(PlacementRandom));
0322     group.sync();
0323     workspace()->slotReconfigure();
0324 
0325     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0326     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0327     Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
0328     QVERIFY(window1);
0329     QCOMPARE(window1->size(), QSize(100, 50));
0330 
0331     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0332     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0333     Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
0334     QVERIFY(window2);
0335     QVERIFY(window2->pos() != window1->pos());
0336     QCOMPARE(window2->size(), QSize(100, 50));
0337 
0338     std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
0339     std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
0340     Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
0341     QVERIFY(window3);
0342     QVERIFY(window3->pos() != window1->pos());
0343     QVERIFY(window3->pos() != window2->pos());
0344     QCOMPARE(window3->size(), QSize(100, 50));
0345 
0346     shellSurface3.reset();
0347     QVERIFY(Test::waitForWindowClosed(window3));
0348     shellSurface2.reset();
0349     QVERIFY(Test::waitForWindowClosed(window2));
0350     shellSurface1.reset();
0351     QVERIFY(Test::waitForWindowClosed(window1));
0352 }
0353 
0354 void TestPlacement::testFullscreen()
0355 {
0356     const QList<Output *> outputs = workspace()->outputs();
0357 
0358     setPlacementPolicy(PlacementSmart);
0359     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0360     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0361 
0362     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::red);
0363     QVERIFY(window);
0364     window->sendToOutput(outputs[0]);
0365 
0366     // Wait for the configure event with the activated state.
0367     QSignalSpy toplevelConfigureRequestedSpy(shellSurface.get(), &Test::XdgToplevel::configureRequested);
0368     QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
0369     QVERIFY(surfaceConfigureRequestedSpy.wait());
0370 
0371     window->setFullScreen(true);
0372 
0373     QSignalSpy geometryChangedSpy(window, &Window::frameGeometryChanged);
0374     QVERIFY(surfaceConfigureRequestedSpy.wait());
0375     shellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>());
0376     Test::render(surface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red);
0377     QVERIFY(geometryChangedSpy.wait());
0378     QCOMPARE(window->frameGeometry(), outputs[0]->geometry());
0379 
0380     // this doesn't require a round trip, so should be immediate
0381     window->sendToOutput(outputs[1]);
0382     QCOMPARE(window->frameGeometry(), outputs[1]->geometry());
0383     QCOMPARE(geometryChangedSpy.count(), 2);
0384 }
0385 
0386 void TestPlacement::testCascadeIfCovering()
0387 {
0388     // This test verifies that the cascade-if-covering adjustment works for the Centered placement
0389     // policy.
0390 
0391     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0392     group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
0393     group.sync();
0394     workspace()->slotReconfigure();
0395 
0396     // window should be in center
0397     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0398     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0399     Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
0400     QVERIFY(window1);
0401     QCOMPARE(window1->pos(), QPoint(590, 487));
0402     QCOMPARE(window1->size(), QSize(100, 50));
0403 
0404     // window should be cascaded to avoid overlapping window 1
0405     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0406     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0407     Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
0408     QVERIFY(window2);
0409     QCOMPARE(window2->pos(), window1->pos() + workspace()->cascadeOffset(window2));
0410     QCOMPARE(window2->size(), QSize(100, 50));
0411 
0412     // window should be cascaded to avoid overlapping window 1 and 2
0413     std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
0414     std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
0415     Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
0416     QVERIFY(window3);
0417     QCOMPARE(window3->pos(), window2->pos() + workspace()->cascadeOffset(window3));
0418     QCOMPARE(window3->size(), QSize(100, 50));
0419 
0420     shellSurface3.reset();
0421     QVERIFY(Test::waitForWindowClosed(window3));
0422     shellSurface2.reset();
0423     QVERIFY(Test::waitForWindowClosed(window2));
0424     shellSurface1.reset();
0425     QVERIFY(Test::waitForWindowClosed(window1));
0426 }
0427 
0428 void TestPlacement::testCascadeIfCoveringIgnoreNonCovering()
0429 {
0430     // This test verifies that the cascade-if-covering adjustment doesn't take effect when the
0431     // other window wouldn't be fully covered.
0432 
0433     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0434     group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
0435     group.sync();
0436     workspace()->slotReconfigure();
0437 
0438     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0439     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0440     Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
0441     QVERIFY(window1);
0442 
0443     // window should not be cascaded since it wouldn't fully overlap
0444     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0445     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0446     Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(50, 50), Qt::blue);
0447     QVERIFY(window2);
0448     QCOMPARE(window2->pos(), QPoint(615, 487));
0449     QCOMPARE(window2->size(), QSize(50, 50));
0450 
0451     shellSurface2.reset();
0452     QVERIFY(Test::waitForWindowClosed(window2));
0453     shellSurface1.reset();
0454     QVERIFY(Test::waitForWindowClosed(window1));
0455 }
0456 
0457 void TestPlacement::testCascadeIfCoveringIgnoreOutOfArea()
0458 {
0459     // This test verifies that the cascade-if-covering adjustment doesn't take effect when there is
0460     // not enough space on the placement area to cascade.
0461 
0462     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0463     group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
0464     group.sync();
0465     workspace()->slotReconfigure();
0466 
0467     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0468     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0469     Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
0470     QVERIFY(window1);
0471 
0472     // window should not be cascaded since it would be out of bounds of work area
0473     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0474     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0475     Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(1280, 1024), Qt::blue);
0476     QVERIFY(window2);
0477     QCOMPARE(window2->pos(), QPoint(0, 0));
0478     QCOMPARE(window2->size(), QSize(1280, 1024));
0479 
0480     shellSurface2.reset();
0481     QVERIFY(Test::waitForWindowClosed(window2));
0482     shellSurface1.reset();
0483     QVERIFY(Test::waitForWindowClosed(window1));
0484 }
0485 
0486 void TestPlacement::testCascadeIfCoveringIgnoreAlreadyCovered()
0487 {
0488     // This test verifies that the cascade-if-covering adjustment doesn't take effect when the
0489     // other window is already fully covered by other windows anyway.
0490 
0491     KConfigGroup group = kwinApp()->config()->group(QStringLiteral("Windows"));
0492     group.writeEntry("Placement", Placement::policyToString(PlacementCentered));
0493     group.sync();
0494     workspace()->slotReconfigure();
0495 
0496     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0497     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0498     Window *window1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::red);
0499     QVERIFY(window1);
0500 
0501     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0502     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0503     Window *window2 = Test::renderAndWaitForShown(surface2.get(), QSize(1280, 1024), Qt::blue);
0504     QVERIFY(window2);
0505 
0506     // window should not be cascaded since the small window is already fully covered by the
0507     // large window anyway
0508     std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
0509     std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
0510     Window *window3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::green);
0511     QVERIFY(window3);
0512     QCOMPARE(window3->pos(), QPoint(590, 487));
0513     QCOMPARE(window3->size(), QSize(100, 50));
0514 
0515     shellSurface3.reset();
0516     QVERIFY(Test::waitForWindowClosed(window3));
0517     shellSurface2.reset();
0518     QVERIFY(Test::waitForWindowClosed(window2));
0519     shellSurface1.reset();
0520     QVERIFY(Test::waitForWindowClosed(window1));
0521 }
0522 
0523 WAYLANDTEST_MAIN(TestPlacement)
0524 #include "placement_test.moc"