File indexing completed on 2024-11-10 04:55:58

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