File indexing completed on 2024-05-12 05:30:35

0001 /*
0002     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "kwin_wayland_test.h"
0008 
0009 #include "core/output.h"
0010 #include "main.h"
0011 #include "pointer_input.h"
0012 #include "screenedge.h"
0013 #include "wayland_server.h"
0014 #include "window.h"
0015 #include "workspace.h"
0016 
0017 #include <KWayland/Client/output.h>
0018 #include <KWayland/Client/surface.h>
0019 
0020 Q_DECLARE_METATYPE(QMargins)
0021 Q_DECLARE_METATYPE(KWin::Layer)
0022 
0023 namespace KWin
0024 {
0025 
0026 static const QString s_socketName = QStringLiteral("wayland_test_kwin_layershellv1window-0");
0027 
0028 class LayerShellV1WindowTest : public QObject
0029 {
0030     Q_OBJECT
0031 
0032 private Q_SLOTS:
0033     void initTestCase();
0034     void init();
0035     void cleanup();
0036     void testOutput_data();
0037     void testOutput();
0038     void testAnchor_data();
0039     void testAnchor();
0040     void testMargins_data();
0041     void testMargins();
0042     void testLayer_data();
0043     void testLayer();
0044     void testChangeLayer();
0045     void testPlacementArea_data();
0046     void testPlacementArea();
0047     void testFill_data();
0048     void testFill();
0049     void testStack();
0050     void testKeyboardInteractivityNone();
0051     void testKeyboardInteractivityOnDemand();
0052     void testActivate_data();
0053     void testActivate();
0054     void testUnmap();
0055     void testScreenEdge_data();
0056     void testScreenEdge();
0057 };
0058 
0059 void LayerShellV1WindowTest::initTestCase()
0060 {
0061     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0062     QVERIFY(waylandServer()->init(s_socketName));
0063     Test::setOutputConfig({
0064         QRect(0, 0, 1280, 1024),
0065         QRect(1280, 0, 1280, 1024),
0066     });
0067 
0068     kwinApp()->start();
0069     QVERIFY(applicationStartedSpy.wait());
0070     const auto outputs = workspace()->outputs();
0071     QCOMPARE(outputs.count(), 2);
0072     QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
0073     QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
0074 }
0075 
0076 void LayerShellV1WindowTest::init()
0077 {
0078     QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::LayerShellV1 | Test::AdditionalWaylandInterface::ScreenEdgeV1));
0079 
0080     workspace()->setActiveOutput(QPoint(640, 512));
0081     input()->pointer()->warp(QPoint(640, 512));
0082 }
0083 
0084 void LayerShellV1WindowTest::cleanup()
0085 {
0086     Test::destroyWaylandConnection();
0087 }
0088 
0089 void LayerShellV1WindowTest::testOutput_data()
0090 {
0091     QTest::addColumn<int>("screenId");
0092 
0093     QTest::addRow("first output") << 0;
0094     QTest::addRow("second output") << 1;
0095 }
0096 
0097 void LayerShellV1WindowTest::testOutput()
0098 {
0099     // Fetch the wl_output object.
0100     QFETCH(int, screenId);
0101     KWayland::Client::Output *output = Test::waylandOutputs().value(screenId);
0102     QVERIFY(output);
0103 
0104     // Create a layer shell surface.
0105     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0106     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test"), output));
0107 
0108     // Set the initial state of the layer surface.
0109     shellSurface->set_size(280, 124);
0110     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0111 
0112     // Wait for the compositor to position the surface.
0113     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0114     QVERIFY(configureRequestedSpy.wait());
0115     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0116 
0117     // Map the layer surface.
0118     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0119     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0120     QVERIFY(window);
0121 
0122     // Verify that the window is on the requested screen.
0123     QVERIFY(output->geometry().contains(window->frameGeometry().toRect()));
0124 
0125     // Destroy the window.
0126     shellSurface.reset();
0127     QVERIFY(Test::waitForWindowClosed(window));
0128 }
0129 
0130 void LayerShellV1WindowTest::testAnchor_data()
0131 {
0132     QTest::addColumn<int>("anchor");
0133     QTest::addColumn<QRectF>("expectedGeometry");
0134 
0135     QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left)
0136                           << QRectF(0, 450, 280, 124);
0137 
0138     QTest::addRow("top left") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left)
0139                               << QRectF(0, 0, 280, 124);
0140 
0141     QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top)
0142                          << QRectF(500, 0, 280, 124);
0143 
0144     QTest::addRow("top right") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right)
0145                                << QRectF(1000, 0, 280, 124);
0146 
0147     QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right)
0148                            << QRectF(1000, 450, 280, 124);
0149 
0150     QTest::addRow("bottom right") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right)
0151                                   << QRectF(1000, 900, 280, 124);
0152 
0153     QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom)
0154                             << QRectF(500, 900, 280, 124);
0155 
0156     QTest::addRow("bottom left") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left)
0157                                  << QRectF(0, 900, 280, 124);
0158 }
0159 
0160 void LayerShellV1WindowTest::testAnchor()
0161 {
0162     // Create a layer shell surface.
0163     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0164     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0165 
0166     // Set the initial state of the layer surface.
0167     QFETCH(int, anchor);
0168     shellSurface->set_anchor(anchor);
0169     shellSurface->set_size(280, 124);
0170     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0171 
0172     // Wait for the compositor to position the surface.
0173     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0174     QVERIFY(configureRequestedSpy.wait());
0175     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0176     QCOMPARE(requestedSize, QSize(280, 124));
0177 
0178     // Map the layer surface.
0179     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0180     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(280, 124), Qt::red);
0181     QVERIFY(window);
0182 
0183     // Verify that the window is placed at expected location.
0184     QTEST(window->frameGeometry(), "expectedGeometry");
0185 
0186     // Destroy the window.
0187     shellSurface.reset();
0188     QVERIFY(Test::waitForWindowClosed(window));
0189 }
0190 
0191 void LayerShellV1WindowTest::testMargins_data()
0192 {
0193     QTest::addColumn<int>("anchor");
0194     QTest::addColumn<QMargins>("margins");
0195     QTest::addColumn<QRectF>("expectedGeometry");
0196 
0197     QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left)
0198                           << QMargins(100, 0, 0, 0)
0199                           << QRectF(100, 450, 280, 124);
0200 
0201     QTest::addRow("top left") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left)
0202                               << QMargins(100, 200, 0, 0)
0203                               << QRectF(100, 200, 280, 124);
0204 
0205     QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top)
0206                          << QMargins(0, 200, 0, 0)
0207                          << QRectF(500, 200, 280, 124);
0208 
0209     QTest::addRow("top right") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right)
0210                                << QMargins(0, 200, 300, 0)
0211                                << QRectF(700, 200, 280, 124);
0212 
0213     QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right)
0214                            << QMargins(0, 0, 300, 0)
0215                            << QRectF(700, 450, 280, 124);
0216 
0217     QTest::addRow("bottom right") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right)
0218                                   << QMargins(0, 0, 300, 400)
0219                                   << QRectF(700, 500, 280, 124);
0220 
0221     QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom)
0222                             << QMargins(0, 0, 0, 400)
0223                             << QRectF(500, 500, 280, 124);
0224 
0225     QTest::addRow("bottom left") << (Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left)
0226                                  << QMargins(100, 0, 0, 400)
0227                                  << QRectF(100, 500, 280, 124);
0228 }
0229 
0230 void LayerShellV1WindowTest::testMargins()
0231 {
0232     // Create a layer shell surface.
0233     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0234     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0235 
0236     // Set the initial state of the layer surface.
0237     QFETCH(QMargins, margins);
0238     QFETCH(int, anchor);
0239     shellSurface->set_anchor(anchor);
0240     shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
0241     shellSurface->set_size(280, 124);
0242     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0243 
0244     // Wait for the compositor to position the surface.
0245     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0246     QVERIFY(configureRequestedSpy.wait());
0247     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0248 
0249     // Map the layer surface.
0250     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0251     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0252     QVERIFY(window);
0253 
0254     // Verify that the window is placed at expected location.
0255     QTEST(window->frameGeometry(), "expectedGeometry");
0256 
0257     // Destroy the window.
0258     shellSurface.reset();
0259     QVERIFY(Test::waitForWindowClosed(window));
0260 }
0261 
0262 void LayerShellV1WindowTest::testLayer_data()
0263 {
0264     QTest::addColumn<int>("protocolLayer");
0265     QTest::addColumn<Layer>("compositorLayer");
0266 
0267     QTest::addRow("overlay") << int(Test::LayerShellV1::layer_overlay) << OverlayLayer;
0268     QTest::addRow("top") << int(Test::LayerShellV1::layer_top) << AboveLayer;
0269     QTest::addRow("bottom") << int(Test::LayerShellV1::layer_bottom) << BelowLayer;
0270     QTest::addRow("background") << int(Test::LayerShellV1::layer_background) << DesktopLayer;
0271 }
0272 
0273 void LayerShellV1WindowTest::testLayer()
0274 {
0275     // Create a layer shell surface.
0276     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0277     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0278 
0279     // Set the initial state of the layer surface.
0280     QFETCH(int, protocolLayer);
0281     shellSurface->set_layer(protocolLayer);
0282     shellSurface->set_size(280, 124);
0283     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0284 
0285     // Wait for the compositor to position the surface.
0286     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0287     QVERIFY(configureRequestedSpy.wait());
0288     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0289 
0290     // Map the layer surface.
0291     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0292     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0293     QVERIFY(window);
0294 
0295     // Verify that the window is placed at expected location.
0296     QTEST(window->layer(), "compositorLayer");
0297 
0298     // Destroy the window.
0299     shellSurface.reset();
0300     QVERIFY(Test::waitForWindowClosed(window));
0301 }
0302 
0303 void LayerShellV1WindowTest::testChangeLayer()
0304 {
0305     // This test verifies that set_layer requests are handled properly after the surface has
0306     // been mapped on the screen.
0307 
0308     // Create layer shell surfaces.
0309     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0310     std::unique_ptr<Test::LayerSurfaceV1> shellSurface1(Test::createLayerSurfaceV1(surface1.get(), QStringLiteral("test")));
0311     shellSurface1->set_layer(Test::LayerShellV1::layer_bottom);
0312     shellSurface1->set_size(200, 100);
0313     surface1->commit(KWayland::Client::Surface::CommitFlag::None);
0314 
0315     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0316     std::unique_ptr<Test::LayerSurfaceV1> shellSurface2(Test::createLayerSurfaceV1(surface2.get(), QStringLiteral("test")));
0317     shellSurface2->set_layer(Test::LayerShellV1::layer_bottom);
0318     shellSurface2->set_size(200, 100);
0319     surface2->commit(KWayland::Client::Surface::CommitFlag::None);
0320 
0321     // Wait for the compositor to position the surfaces.
0322     QSignalSpy configureRequestedSpy1(shellSurface1.get(), &Test::LayerSurfaceV1::configureRequested);
0323     QSignalSpy configureRequestedSpy2(shellSurface2.get(), &Test::LayerSurfaceV1::configureRequested);
0324     QVERIFY(configureRequestedSpy2.wait());
0325     const QSize requestedSize1 = configureRequestedSpy1.last().at(1).toSize();
0326     const QSize requestedSize2 = configureRequestedSpy2.last().at(1).toSize();
0327 
0328     // Map the layer surfaces.
0329     shellSurface1->ack_configure(configureRequestedSpy1.last().at(0).toUInt());
0330     Window *window1 = Test::renderAndWaitForShown(surface1.get(), requestedSize1, Qt::red);
0331     QVERIFY(window1);
0332     shellSurface2->ack_configure(configureRequestedSpy2.last().at(0).toUInt());
0333     Window *window2 = Test::renderAndWaitForShown(surface2.get(), requestedSize2, Qt::red);
0334     QVERIFY(window2);
0335 
0336     // The first layer shell window is stacked below the second one.
0337     QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window1, window2}));
0338 
0339     // Move the first layer shell window to the top layer.
0340     QSignalSpy stackingOrderChangedSpy(workspace(), &Workspace::stackingOrderChanged);
0341     shellSurface1->set_layer(Test::LayerShellV1::layer_top);
0342     surface1->commit(KWayland::Client::Surface::CommitFlag::None);
0343     QVERIFY(stackingOrderChangedSpy.wait());
0344 
0345     // The first layer shell window should be on top now.
0346     QCOMPARE(workspace()->stackingOrder(), (QList<Window *>{window2, window1}));
0347 
0348     // Destroy the window.
0349     shellSurface1.reset();
0350     QVERIFY(Test::waitForWindowClosed(window1));
0351     shellSurface2.reset();
0352     QVERIFY(Test::waitForWindowClosed(window2));
0353 }
0354 
0355 void LayerShellV1WindowTest::testPlacementArea_data()
0356 {
0357     QTest::addColumn<int>("anchor");
0358     QTest::addColumn<QMargins>("margins");
0359     QTest::addColumn<int>("exclusiveZone");
0360     QTest::addColumn<int>("exclusiveEdge");
0361     QTest::addColumn<QRectF>("placementArea");
0362 
0363     QTest::addRow("left") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(300, 0, 980, 1024);
0364     QTest::addRow("top") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 300, 1280, 724);
0365     QTest::addRow("right") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 980, 1024);
0366     QTest::addRow("bottom") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 724);
0367 
0368     QTest::addRow("top | left") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
0369     QTest::addRow("top | right") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
0370     QTest::addRow("bottom | left") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
0371     QTest::addRow("bottom | right") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << 0 << QRectF(0, 0, 1280, 1024);
0372 
0373     QTest::addRow("left, negative margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(-5, 0, 0, 0) << 300 << 0 << QRectF(295, 0, 985, 1024);
0374     QTest::addRow("top, negative margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, -5, 0, 0) << 300 << 0 << QRectF(0, 295, 1280, 729);
0375     QTest::addRow("right, negative margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, -5, 0) << 300 << 0 << QRectF(0, 0, 985, 1024);
0376     QTest::addRow("bottom, negative margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, -5) << 300 << 0 << QRectF(0, 0, 1280, 729);
0377 
0378     QTest::addRow("left, positive margin") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(5, 0, 0, 0) << 300 << 0 << QRectF(305, 0, 975, 1024);
0379     QTest::addRow("top, positive margin") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 5, 0, 0) << 300 << 0 << QRectF(0, 305, 1280, 719);
0380     QTest::addRow("right, positive margin") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 5, 0) << 300 << 0 << QRectF(0, 0, 975, 1024);
0381     QTest::addRow("bottom, positive margin") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 5) << 300 << 0 << QRectF(0, 0, 1280, 719);
0382 
0383     QTest::addRow("left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
0384     QTest::addRow("top + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
0385     QTest::addRow("right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
0386     QTest::addRow("bottom + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
0387 
0388     QTest::addRow("top | left + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
0389     QTest::addRow("top | left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
0390     QTest::addRow("top | right + top exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_top) << QRectF(0, 300, 1280, 724);
0391     QTest::addRow("top | right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
0392     QTest::addRow("bottom | left + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
0393     QTest::addRow("bottom | left + left exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_left) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_left) << QRectF(300, 0, 980, 1024);
0394     QTest::addRow("bottom | right + bottom exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_bottom) << QRectF(0, 0, 1280, 724);
0395     QTest::addRow("bottom | right + right exclusive edge") << int(Test::LayerSurfaceV1::anchor_bottom | Test::LayerSurfaceV1::anchor_right) << QMargins(0, 0, 0, 0) << 300 << int(Test::LayerSurfaceV1::anchor_right) << QRectF(0, 0, 980, 1024);
0396 }
0397 
0398 void LayerShellV1WindowTest::testPlacementArea()
0399 {
0400     // Create a layer shell surface.
0401     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0402     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0403 
0404     // Set the initial state of the layer surface.
0405     QFETCH(int, anchor);
0406     QFETCH(QMargins, margins);
0407     QFETCH(int, exclusiveZone);
0408     QFETCH(int, exclusiveEdge);
0409     shellSurface->set_anchor(anchor);
0410     shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
0411     shellSurface->set_exclusive_zone(exclusiveZone);
0412     shellSurface->set_exclusive_edge(exclusiveEdge);
0413     shellSurface->set_size(280, 124);
0414     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0415 
0416     // Wait for the compositor to position the surface.
0417     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0418     QVERIFY(configureRequestedSpy.wait());
0419     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0420 
0421     // Map the layer surface.
0422     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0423     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0424     QVERIFY(window);
0425 
0426     // Verify that the work area has been adjusted.
0427     QTEST(workspace()->clientArea(PlacementArea, window), "placementArea");
0428 
0429     // Destroy the window.
0430     shellSurface.reset();
0431     QVERIFY(Test::waitForWindowClosed(window));
0432 }
0433 
0434 void LayerShellV1WindowTest::testFill_data()
0435 {
0436     QTest::addColumn<int>("anchor");
0437     QTest::addColumn<QSize>("desiredSize");
0438     QTest::addColumn<QRectF>("expectedGeometry");
0439 
0440     QTest::addRow("horizontal") << (Test::LayerSurfaceV1::anchor_left | Test::LayerSurfaceV1::anchor_right)
0441                                 << QSize(0, 124)
0442                                 << QRectF(0, 450, 1280, 124);
0443 
0444     QTest::addRow("vertical") << (Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_bottom)
0445                               << QSize(280, 0)
0446                               << QRectF(500, 0, 280, 1024);
0447 
0448     QTest::addRow("all") << (Test::LayerSurfaceV1::anchor_left | Test::LayerSurfaceV1::anchor_top | Test::LayerSurfaceV1::anchor_right | Test::LayerSurfaceV1::anchor_bottom)
0449                          << QSize(0, 0)
0450                          << QRectF(0, 0, 1280, 1024);
0451 }
0452 
0453 void LayerShellV1WindowTest::testFill()
0454 {
0455     // Create a layer shell surface.
0456     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0457     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0458 
0459     // Set the initial state of the layer surface.
0460     QFETCH(int, anchor);
0461     QFETCH(QSize, desiredSize);
0462     shellSurface->set_anchor(anchor);
0463     shellSurface->set_size(desiredSize.width(), desiredSize.height());
0464     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0465 
0466     // Wait for the compositor to position the surface.
0467     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0468     QVERIFY(configureRequestedSpy.wait());
0469     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0470 
0471     // Map the layer surface.
0472     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0473     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0474     QVERIFY(window);
0475 
0476     // Verify that the window is placed at expected location.
0477     QTEST(window->frameGeometry(), "expectedGeometry");
0478 
0479     // Destroy the window.
0480     shellSurface.reset();
0481     QVERIFY(Test::waitForWindowClosed(window));
0482 }
0483 
0484 void LayerShellV1WindowTest::testStack()
0485 {
0486     // Create a layer shell surface.
0487     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0488     std::unique_ptr<Test::LayerSurfaceV1> shellSurface1(Test::createLayerSurfaceV1(surface1.get(), QStringLiteral("test")));
0489 
0490     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0491     std::unique_ptr<Test::LayerSurfaceV1> shellSurface2(Test::createLayerSurfaceV1(surface2.get(), QStringLiteral("test")));
0492 
0493     // Set the initial state of the layer surface.
0494     shellSurface1->set_anchor(Test::LayerSurfaceV1::anchor_left);
0495     shellSurface1->set_size(80, 124);
0496     shellSurface1->set_exclusive_zone(80);
0497     surface1->commit(KWayland::Client::Surface::CommitFlag::None);
0498 
0499     shellSurface2->set_anchor(Test::LayerSurfaceV1::anchor_left);
0500     shellSurface2->set_size(200, 124);
0501     shellSurface2->set_exclusive_zone(200);
0502     surface2->commit(KWayland::Client::Surface::CommitFlag::None);
0503 
0504     // Wait for the compositor to position the surfaces.
0505     QSignalSpy configureRequestedSpy1(shellSurface1.get(), &Test::LayerSurfaceV1::configureRequested);
0506     QSignalSpy configureRequestedSpy2(shellSurface2.get(), &Test::LayerSurfaceV1::configureRequested);
0507     QVERIFY(configureRequestedSpy2.wait());
0508     const QSize requestedSize1 = configureRequestedSpy1.last().at(1).toSize();
0509     const QSize requestedSize2 = configureRequestedSpy2.last().at(1).toSize();
0510 
0511     // Map the layer surface.
0512     shellSurface1->ack_configure(configureRequestedSpy1.last().at(0).toUInt());
0513     Window *window1 = Test::renderAndWaitForShown(surface1.get(), requestedSize1, Qt::red);
0514     QVERIFY(window1);
0515 
0516     shellSurface2->ack_configure(configureRequestedSpy2.last().at(0).toUInt());
0517     Window *window2 = Test::renderAndWaitForShown(surface2.get(), requestedSize2, Qt::red);
0518     QVERIFY(window2);
0519 
0520     // Check that the second layer surface is placed next to the first.
0521     QCOMPARE(window1->frameGeometry(), QRect(0, 450, 80, 124));
0522     QCOMPARE(window2->frameGeometry(), QRect(80, 450, 200, 124));
0523 
0524     // Check that the work area has been adjusted accordingly.
0525     QCOMPARE(workspace()->clientArea(PlacementArea, window1), QRect(280, 0, 1000, 1024));
0526     QCOMPARE(workspace()->clientArea(PlacementArea, window2), QRect(280, 0, 1000, 1024));
0527 
0528     // Destroy the window.
0529     shellSurface1.reset();
0530     QVERIFY(Test::waitForWindowClosed(window1));
0531     shellSurface2.reset();
0532     QVERIFY(Test::waitForWindowClosed(window2));
0533 }
0534 
0535 void LayerShellV1WindowTest::testKeyboardInteractivityNone()
0536 {
0537     // Create a layer shell surface.
0538     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0539     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0540 
0541     // Set the initial state of the layer surface.
0542     shellSurface->set_keyboard_interactivity(0);
0543     shellSurface->set_size(100, 50);
0544     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0545 
0546     // Wait for the compositor to position the surface.
0547     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0548     QVERIFY(configureRequestedSpy.wait());
0549     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0550 
0551     // Map the layer surface.
0552     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0553     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0554     QVERIFY(window);
0555     QVERIFY(!window->isActive());
0556 
0557     // Try to activate the surface.
0558     workspace()->activateWindow(window);
0559     QVERIFY(!window->isActive());
0560 
0561     // Destroy the window.
0562     shellSurface.reset();
0563     QVERIFY(Test::waitForWindowClosed(window));
0564 }
0565 
0566 void LayerShellV1WindowTest::testKeyboardInteractivityOnDemand()
0567 {
0568     // Create a layer shell surface.
0569     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0570     std::unique_ptr<Test::LayerSurfaceV1> shellSurface1(Test::createLayerSurfaceV1(surface1.get(), QStringLiteral("test")));
0571     shellSurface1->set_keyboard_interactivity(1);
0572     shellSurface1->set_size(280, 124);
0573     surface1->commit(KWayland::Client::Surface::CommitFlag::None);
0574 
0575     QSignalSpy configureRequestedSpy1(shellSurface1.get(), &Test::LayerSurfaceV1::configureRequested);
0576     QVERIFY(configureRequestedSpy1.wait());
0577     const QSize requestedSize1 = configureRequestedSpy1.last().at(1).toSize();
0578     shellSurface1->ack_configure(configureRequestedSpy1.last().at(0).toUInt());
0579     Window *window1 = Test::renderAndWaitForShown(surface1.get(), requestedSize1, Qt::red);
0580     QVERIFY(window1);
0581     QVERIFY(window1->isActive());
0582 
0583     // Create the second layer shell surface.
0584     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0585     std::unique_ptr<Test::LayerSurfaceV1> shellSurface2(Test::createLayerSurfaceV1(surface2.get(), QStringLiteral("test")));
0586     shellSurface2->set_keyboard_interactivity(1);
0587     shellSurface2->set_size(280, 124);
0588     surface2->commit(KWayland::Client::Surface::CommitFlag::None);
0589 
0590     QSignalSpy configureRequestedSpy2(shellSurface2.get(), &Test::LayerSurfaceV1::configureRequested);
0591     QVERIFY(configureRequestedSpy2.wait());
0592     const QSize requestedSize2 = configureRequestedSpy2.last().at(1).toSize();
0593     shellSurface2->ack_configure(configureRequestedSpy2.last().at(0).toUInt());
0594     Window *window2 = Test::renderAndWaitForShown(surface2.get(), requestedSize2, Qt::red);
0595     QVERIFY(window2);
0596     QVERIFY(window2->isActive());
0597     QVERIFY(!window1->isActive());
0598 
0599     // Activate the first surface.
0600     workspace()->activateWindow(window1);
0601     QVERIFY(window1->isActive());
0602     QVERIFY(!window2->isActive());
0603 
0604     // Destroy the window.
0605     shellSurface1.reset();
0606     QVERIFY(Test::waitForWindowClosed(window1));
0607     shellSurface2.reset();
0608     QVERIFY(Test::waitForWindowClosed(window2));
0609 }
0610 
0611 void LayerShellV1WindowTest::testActivate_data()
0612 {
0613     QTest::addColumn<int>("layer");
0614     QTest::addColumn<bool>("active");
0615 
0616     QTest::addRow("overlay") << int(Test::LayerShellV1::layer_overlay) << true;
0617     QTest::addRow("top") << int(Test::LayerShellV1::layer_top) << true;
0618     QTest::addRow("bottom") << int(Test::LayerShellV1::layer_bottom) << false;
0619     QTest::addRow("background") << int(Test::LayerShellV1::layer_background) << false;
0620 }
0621 
0622 void LayerShellV1WindowTest::testActivate()
0623 {
0624     // Create a layer shell surface.
0625     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0626     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0627 
0628     // Set the initial state of the layer surface.
0629     QFETCH(int, layer);
0630     shellSurface->set_layer(layer);
0631     shellSurface->set_size(280, 124);
0632     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0633 
0634     // Wait for the compositor to position the surface.
0635     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0636     QVERIFY(configureRequestedSpy.wait());
0637     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0638 
0639     // Map the layer surface.
0640     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0641     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0642     QVERIFY(window);
0643     QVERIFY(!window->isActive());
0644 
0645     // Try to activate the layer surface.
0646     shellSurface->set_keyboard_interactivity(1);
0647     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0648 
0649     QSignalSpy activeChangedSpy(window, &Window::activeChanged);
0650     QTEST(activeChangedSpy.wait(1000), "active");
0651 
0652     // Destroy the window.
0653     shellSurface.reset();
0654     QVERIFY(Test::waitForWindowClosed(window));
0655 }
0656 
0657 void LayerShellV1WindowTest::testUnmap()
0658 {
0659     // Create a layer shell surface.
0660     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0661     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0662 
0663     // Set the initial state of the layer surface.
0664     shellSurface->set_size(280, 124);
0665     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0666 
0667     // Wait for the compositor to position the surface.
0668     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0669     QVERIFY(configureRequestedSpy.wait());
0670 
0671     // Map the layer surface.
0672     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0673     Window *window = Test::renderAndWaitForShown(surface.get(), QSize(280, 124), Qt::red);
0674     QVERIFY(window);
0675 
0676     // Unmap the layer surface.
0677     surface->attachBuffer(KWayland::Client::Buffer::Ptr());
0678     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0679     QVERIFY(Test::waitForWindowClosed(window));
0680 
0681     // Notify the compositor that we want to map the layer surface.
0682     shellSurface->set_size(280, 124);
0683     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0684 
0685     // Wait for the configure event.
0686     QVERIFY(configureRequestedSpy.wait());
0687 
0688     // Map the layer surface back.
0689     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0690     window = Test::renderAndWaitForShown(surface.get(), QSize(280, 124), Qt::red);
0691     QVERIFY(window);
0692 
0693     // Destroy the window.
0694     shellSurface.reset();
0695     QVERIFY(Test::waitForWindowClosed(window));
0696 }
0697 
0698 void LayerShellV1WindowTest::testScreenEdge_data()
0699 {
0700     QTest::addColumn<QMargins>("margins");
0701 
0702     QTest::addRow("normal") << QMargins(0, 0, 0, 0);
0703     QTest::addRow("with margin") << QMargins(0, 0, 0, 10);
0704 }
0705 
0706 void LayerShellV1WindowTest::testScreenEdge()
0707 {
0708     auto config = kwinApp()->config();
0709     config->group(QStringLiteral("Windows")).writeEntry("ElectricBorderDelay", 75);
0710     config->sync();
0711     workspace()->slotReconfigure();
0712 
0713     // Create a layer shell surface.
0714     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0715     std::unique_ptr<Test::LayerSurfaceV1> shellSurface(Test::createLayerSurfaceV1(surface.get(), QStringLiteral("test")));
0716     std::unique_ptr<Test::AutoHideScreenEdgeV1> screenEdge(Test::createAutoHideScreenEdgeV1(surface.get(), Test::ScreenEdgeManagerV1::border_bottom));
0717 
0718     // Set the initial state of the layer surface.
0719     QFETCH(QMargins, margins);
0720     shellSurface->set_layer(Test::LayerShellV1::layer_top);
0721     shellSurface->set_anchor(Test::LayerSurfaceV1::anchor_bottom);
0722     shellSurface->set_size(100, 50);
0723     shellSurface->set_margin(margins.top(), margins.right(), margins.bottom(), margins.left());
0724     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0725 
0726     // Wait for the compositor to position the surface.
0727     QSignalSpy configureRequestedSpy(shellSurface.get(), &Test::LayerSurfaceV1::configureRequested);
0728     QVERIFY(configureRequestedSpy.wait());
0729     const QSize requestedSize = configureRequestedSpy.last().at(1).toSize();
0730 
0731     // Map the layer surface.
0732     shellSurface->ack_configure(configureRequestedSpy.last().at(0).toUInt());
0733     Window *window = Test::renderAndWaitForShown(surface.get(), requestedSize, Qt::red);
0734     QVERIFY(window);
0735     QVERIFY(!window->isActive());
0736 
0737     QSignalSpy windowShowSpy(window, &Window::windowShown);
0738     QSignalSpy windowHiddenSpy(window, &Window::windowHidden);
0739     quint32 timestamp = 0;
0740 
0741     // The layer surface will be hidden and shown when the screen edge is activated or deactivated.
0742     {
0743         screenEdge->activate();
0744         QVERIFY(windowHiddenSpy.wait());
0745         QVERIFY(!window->isShown());
0746 
0747         screenEdge->deactivate();
0748         QVERIFY(windowShowSpy.wait());
0749         QVERIFY(window->isShown());
0750     }
0751 
0752     // The layer surface will be shown when the screen edge is triggered.
0753     {
0754         screenEdge->activate();
0755         QVERIFY(windowHiddenSpy.wait());
0756         QVERIFY(!window->isShown());
0757 
0758         Test::pointerMotion(QPointF(640, 1023), timestamp);
0759         timestamp += 160;
0760         Test::pointerMotion(QPointF(640, 1023), timestamp);
0761         timestamp += 160;
0762         Test::pointerMotion(QPointF(640, 512), timestamp);
0763         QVERIFY(windowShowSpy.wait());
0764         QVERIFY(window->isShown());
0765     }
0766 
0767     // The approaching state will be reset if the window is shown manually.
0768     {
0769         QSignalSpy approachingSpy(workspace()->screenEdges(), &ScreenEdges::approaching);
0770         screenEdge->activate();
0771         QVERIFY(windowHiddenSpy.wait());
0772         QVERIFY(!window->isShown());
0773 
0774         Test::pointerMotion(QPointF(640, 1020), timestamp++);
0775         QVERIFY(approachingSpy.last().at(1).toReal() == 0.0);
0776         Test::pointerMotion(QPointF(640, 1021), timestamp++);
0777         QVERIFY(approachingSpy.last().at(1).toReal() != 0.0);
0778 
0779         screenEdge->deactivate();
0780         QVERIFY(windowShowSpy.wait());
0781         QVERIFY(window->isShown());
0782         QVERIFY(approachingSpy.last().at(1).toReal() == 0.0);
0783 
0784         Test::pointerMotion(QPointF(640, 512), timestamp++);
0785     }
0786 
0787     // The layer surface will be shown when the screen edge is destroyed.
0788     {
0789         screenEdge->activate();
0790         QVERIFY(windowHiddenSpy.wait());
0791         QVERIFY(!window->isShown());
0792 
0793         screenEdge.reset();
0794         QVERIFY(windowShowSpy.wait());
0795         QVERIFY(window->isShown());
0796     }
0797 }
0798 
0799 } // namespace KWin
0800 
0801 WAYLANDTEST_MAIN(KWin::LayerShellV1WindowTest)
0802 #include "layershellv1window_test.moc"