File indexing completed on 2024-05-05 17:35:46

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "kwin_wayland_test.h"
0010 
0011 #include "core/outputbackend.h"
0012 #include "virtualdesktops.h"
0013 #include "wayland_server.h"
0014 #include "window.h"
0015 #include "workspace.h"
0016 
0017 #include <KWayland/Client/surface.h>
0018 
0019 using namespace KWin;
0020 
0021 static const QString s_socketName = QStringLiteral("wayland_test_kwin_idle_inhbition_test-0");
0022 
0023 class TestIdleInhibition : public QObject
0024 {
0025     Q_OBJECT
0026 private Q_SLOTS:
0027     void initTestCase();
0028     void init();
0029     void cleanup();
0030 
0031     void testInhibit();
0032     void testDontInhibitWhenNotOnCurrentDesktop();
0033     void testDontInhibitWhenMinimized();
0034     void testDontInhibitWhenUnmapped();
0035     void testDontInhibitWhenLeftCurrentDesktop();
0036 };
0037 
0038 void TestIdleInhibition::initTestCase()
0039 {
0040     qRegisterMetaType<KWin::Window *>();
0041 
0042     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0043     QVERIFY(waylandServer()->init(s_socketName));
0044     QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024)));
0045 
0046     kwinApp()->start();
0047     QVERIFY(applicationStartedSpy.wait());
0048 }
0049 
0050 void TestIdleInhibition::init()
0051 {
0052     QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::IdleInhibitV1));
0053 }
0054 
0055 void TestIdleInhibition::cleanup()
0056 {
0057     Test::destroyWaylandConnection();
0058 
0059     VirtualDesktopManager::self()->setCount(1);
0060     QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
0061 }
0062 
0063 void TestIdleInhibition::testInhibit()
0064 {
0065     // no idle inhibitors at the start
0066     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0067 
0068     // now create window
0069     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0070     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0071 
0072     // now create inhibition on window
0073     std::unique_ptr<Test::IdleInhibitorV1> inhibitor(Test::createIdleInhibitorV1(surface.get()));
0074     QVERIFY(inhibitor);
0075 
0076     // render the window
0077     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0078     QVERIFY(window);
0079 
0080     // this should inhibit our server object
0081     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0082 
0083     // deleting the object should uninhibit again
0084     inhibitor.reset();
0085     Test::flushWaylandConnection(); // don't use QTRY_COMPARE(), it doesn't spin event loop
0086     QGuiApplication::processEvents();
0087     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0088 
0089     // inhibit again and destroy window
0090     std::unique_ptr<Test::IdleInhibitorV1> inhibitor2(Test::createIdleInhibitorV1(surface.get()));
0091     Test::flushWaylandConnection();
0092     QGuiApplication::processEvents();
0093     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0094 
0095     shellSurface.reset();
0096     QVERIFY(Test::waitForWindowDestroyed(window));
0097     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0098 }
0099 
0100 void TestIdleInhibition::testDontInhibitWhenNotOnCurrentDesktop()
0101 {
0102     // This test verifies that the idle inhibitor object is not honored when
0103     // the associated surface is not on the current virtual desktop.
0104 
0105     VirtualDesktopManager::self()->setCount(2);
0106     QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
0107 
0108     // Create the test window.
0109     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0110     QVERIFY(surface != nullptr);
0111     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0112     QVERIFY(shellSurface != nullptr);
0113 
0114     // Create the inhibitor object.
0115     std::unique_ptr<Test::IdleInhibitorV1> inhibitor(Test::createIdleInhibitorV1(surface.get()));
0116     QVERIFY(inhibitor);
0117 
0118     // Render the window.
0119     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0120     QVERIFY(window);
0121 
0122     // The test window should be only on the first virtual desktop.
0123     QCOMPARE(window->desktops().count(), 1);
0124     QCOMPARE(window->desktops().first(), VirtualDesktopManager::self()->desktops().first());
0125 
0126     // This should inhibit our server object.
0127     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0128 
0129     // Switch to the second virtual desktop.
0130     VirtualDesktopManager::self()->setCurrent(2);
0131 
0132     // The surface is no longer visible, so the compositor don't have to honor the
0133     // idle inhibitor object.
0134     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0135 
0136     // Switch back to the first virtual desktop.
0137     VirtualDesktopManager::self()->setCurrent(1);
0138 
0139     // The test window became visible again, so the compositor has to honor the idle
0140     // inhibitor object back again.
0141     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0142 
0143     // Destroy the test window.
0144     shellSurface.reset();
0145     QVERIFY(Test::waitForWindowDestroyed(window));
0146     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0147 }
0148 
0149 void TestIdleInhibition::testDontInhibitWhenMinimized()
0150 {
0151     // This test verifies that the idle inhibitor object is not honored when the
0152     // associated surface is minimized.
0153 
0154     // Create the test window.
0155     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0156     QVERIFY(surface != nullptr);
0157     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0158     QVERIFY(shellSurface != nullptr);
0159 
0160     // Create the inhibitor object.
0161     std::unique_ptr<Test::IdleInhibitorV1> inhibitor(Test::createIdleInhibitorV1(surface.get()));
0162     QVERIFY(inhibitor);
0163 
0164     // Render the window.
0165     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0166     QVERIFY(window);
0167 
0168     // This should inhibit our server object.
0169     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0170 
0171     // Minimize the window, the idle inhibitor object should not be honored.
0172     window->minimize();
0173     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0174 
0175     // Unminimize the window, the idle inhibitor object should be honored back again.
0176     window->unminimize();
0177     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0178 
0179     // Destroy the test window.
0180     shellSurface.reset();
0181     QVERIFY(Test::waitForWindowDestroyed(window));
0182     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0183 }
0184 
0185 void TestIdleInhibition::testDontInhibitWhenUnmapped()
0186 {
0187     // This test verifies that the idle inhibitor object is not honored by KWin
0188     // when the associated window is unmapped.
0189 
0190     // Create the test window.
0191     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0192     QVERIFY(surface != nullptr);
0193     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0194     QVERIFY(shellSurface != nullptr);
0195     QSignalSpy surfaceConfigureRequestedSpy(shellSurface->xdgSurface(), &Test::XdgSurface::configureRequested);
0196 
0197     // Create the inhibitor object.
0198     std::unique_ptr<Test::IdleInhibitorV1> inhibitor(Test::createIdleInhibitorV1(surface.get()));
0199     QVERIFY(inhibitor);
0200 
0201     // Map the window.
0202     QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
0203     Test::render(surface.get(), QSize(100, 50), Qt::blue);
0204     QVERIFY(windowAddedSpy.isEmpty());
0205     QVERIFY(windowAddedSpy.wait());
0206     QCOMPARE(windowAddedSpy.count(), 1);
0207     Window *window = windowAddedSpy.last().first().value<Window *>();
0208     QVERIFY(window);
0209     QCOMPARE(window->readyForPainting(), true);
0210 
0211     // The compositor will respond with a configure event when the surface becomes active.
0212     QVERIFY(surfaceConfigureRequestedSpy.wait());
0213     QCOMPARE(surfaceConfigureRequestedSpy.count(), 1);
0214 
0215     // This should inhibit our server object.
0216     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0217 
0218     // Unmap the window.
0219     surface->attachBuffer(KWayland::Client::Buffer::Ptr());
0220     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0221     QVERIFY(Test::waitForWindowDestroyed(window));
0222 
0223     // The surface is no longer visible, so the compositor doesn't have to honor the
0224     // idle inhibitor object.
0225     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0226 
0227     // Tell the compositor that we want to map the surface.
0228     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0229 
0230     // The compositor will respond with a configure event.
0231     QVERIFY(surfaceConfigureRequestedSpy.wait());
0232     QCOMPARE(surfaceConfigureRequestedSpy.count(), 2);
0233 
0234     // Map the window.
0235     Test::render(surface.get(), QSize(100, 50), Qt::blue);
0236     QVERIFY(windowAddedSpy.wait());
0237     QCOMPARE(windowAddedSpy.count(), 2);
0238     window = windowAddedSpy.last().first().value<Window *>();
0239     QVERIFY(window);
0240     QCOMPARE(window->readyForPainting(), true);
0241 
0242     // The test window became visible again, so the compositor has to honor the idle
0243     // inhibitor object back again.
0244     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0245 
0246     // Destroy the test window.
0247     shellSurface.reset();
0248     QVERIFY(Test::waitForWindowDestroyed(window));
0249     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0250 }
0251 
0252 void TestIdleInhibition::testDontInhibitWhenLeftCurrentDesktop()
0253 {
0254     // This test verifies that the idle inhibitor object is not honored by KWin
0255     // when the associated surface leaves the current virtual desktop.
0256 
0257     VirtualDesktopManager::self()->setCount(2);
0258     QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
0259 
0260     // Create the test window.
0261     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0262     QVERIFY(surface != nullptr);
0263     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0264     QVERIFY(shellSurface != nullptr);
0265 
0266     // Create the inhibitor object.
0267     std::unique_ptr<Test::IdleInhibitorV1> inhibitor(Test::createIdleInhibitorV1(surface.get()));
0268     QVERIFY(inhibitor);
0269 
0270     // Render the window.
0271     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0272     QVERIFY(window);
0273 
0274     // The test window should be only on the first virtual desktop.
0275     QCOMPARE(window->desktops().count(), 1);
0276     QCOMPARE(window->desktops().first(), VirtualDesktopManager::self()->desktops().first());
0277 
0278     // This should inhibit our server object.
0279     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0280 
0281     // Let the window enter the second virtual desktop.
0282     window->enterDesktop(VirtualDesktopManager::self()->desktops().at(1));
0283     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0284 
0285     // If the window leaves the first virtual desktop, then the associated idle
0286     // inhibitor object should not be honored.
0287     window->leaveDesktop(VirtualDesktopManager::self()->desktops().at(0));
0288     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0289 
0290     // If the window enters the first desktop, then the associated idle inhibitor
0291     // object should be honored back again.
0292     window->enterDesktop(VirtualDesktopManager::self()->desktops().at(0));
0293     QCOMPARE(input()->idleInhibitors(), QList<Window *>{window});
0294 
0295     // Destroy the test window.
0296     shellSurface.reset();
0297     QVERIFY(Test::waitForWindowDestroyed(window));
0298     QCOMPARE(input()->idleInhibitors(), QList<Window *>{});
0299 }
0300 
0301 WAYLANDTEST_MAIN(TestIdleInhibition)
0302 #include "idle_inhibition_test.moc"