File indexing completed on 2025-03-23 13:47:56
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"