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: 2016 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "kwin_wayland_test.h" 0010 0011 #include "core/output.h" 0012 #include "pointer_input.h" 0013 #include "virtualdesktops.h" 0014 #include "wayland_server.h" 0015 #include "window.h" 0016 #include "workspace.h" 0017 0018 #include <KWayland/Client/compositor.h> 0019 #include <KWayland/Client/connection_thread.h> 0020 #include <KWayland/Client/event_queue.h> 0021 #include <KWayland/Client/plasmashell.h> 0022 #include <KWayland/Client/registry.h> 0023 #include <KWayland/Client/shm_pool.h> 0024 #include <KWayland/Client/surface.h> 0025 0026 using namespace KWin; 0027 0028 Q_DECLARE_METATYPE(KWin::Layer) 0029 0030 static const QString s_socketName = QStringLiteral("wayland_test_kwin_plasma_surface-0"); 0031 0032 class PlasmaSurfaceTest : public QObject 0033 { 0034 Q_OBJECT 0035 private Q_SLOTS: 0036 void initTestCase(); 0037 void init(); 0038 void cleanup(); 0039 0040 void testRoleOnAllDesktops_data(); 0041 void testRoleOnAllDesktops(); 0042 void testAcceptsFocus_data(); 0043 void testAcceptsFocus(); 0044 void testOSDPlacement(); 0045 void testOSDPlacementManualPosition(); 0046 void testPanelActivate_data(); 0047 void testPanelActivate(); 0048 void testMovable_data(); 0049 void testMovable(); 0050 0051 private: 0052 KWayland::Client::Compositor *m_compositor = nullptr; 0053 KWayland::Client::PlasmaShell *m_plasmaShell = nullptr; 0054 }; 0055 0056 void PlasmaSurfaceTest::initTestCase() 0057 { 0058 qRegisterMetaType<KWin::Window *>(); 0059 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0060 QVERIFY(waylandServer()->init(s_socketName)); 0061 Test::setOutputConfig({QRect(0, 0, 1280, 1024)}); 0062 0063 kwinApp()->start(); 0064 QVERIFY(applicationStartedSpy.wait()); 0065 } 0066 0067 void PlasmaSurfaceTest::init() 0068 { 0069 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::PlasmaShell)); 0070 m_compositor = Test::waylandCompositor(); 0071 m_plasmaShell = Test::waylandPlasmaShell(); 0072 0073 KWin::input()->pointer()->warp(QPointF(640, 512)); 0074 } 0075 0076 void PlasmaSurfaceTest::cleanup() 0077 { 0078 Test::destroyWaylandConnection(); 0079 } 0080 0081 void PlasmaSurfaceTest::testRoleOnAllDesktops_data() 0082 { 0083 QTest::addColumn<KWayland::Client::PlasmaShellSurface::Role>("role"); 0084 QTest::addColumn<bool>("expectedOnAllDesktops"); 0085 0086 QTest::newRow("Desktop") << KWayland::Client::PlasmaShellSurface::Role::Desktop << true; 0087 QTest::newRow("Panel") << KWayland::Client::PlasmaShellSurface::Role::Panel << true; 0088 QTest::newRow("OSD") << KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay << true; 0089 QTest::newRow("Normal") << KWayland::Client::PlasmaShellSurface::Role::Normal << false; 0090 QTest::newRow("Notification") << KWayland::Client::PlasmaShellSurface::Role::Notification << true; 0091 QTest::newRow("ToolTip") << KWayland::Client::PlasmaShellSurface::Role::ToolTip << true; 0092 QTest::newRow("CriticalNotification") << KWayland::Client::PlasmaShellSurface::Role::CriticalNotification << true; 0093 QTest::newRow("AppletPopup") << KWayland::Client::PlasmaShellSurface::Role::AppletPopup << true; 0094 } 0095 0096 void PlasmaSurfaceTest::testRoleOnAllDesktops() 0097 { 0098 // this test verifies that a XdgShellClient is set on all desktops when the role changes 0099 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0100 QVERIFY(surface != nullptr); 0101 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0102 QVERIFY(shellSurface != nullptr); 0103 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get())); 0104 QVERIFY(plasmaSurface != nullptr); 0105 0106 // now render to map the window 0107 Window *window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0108 QVERIFY(window); 0109 QCOMPARE(workspace()->activeWindow(), window); 0110 0111 // currently the role is not yet set, so the window should not be on all desktops 0112 QCOMPARE(window->isOnAllDesktops(), false); 0113 0114 // now let's try to change that 0115 QSignalSpy onAllDesktopsSpy(window, &Window::desktopsChanged); 0116 QFETCH(KWayland::Client::PlasmaShellSurface::Role, role); 0117 plasmaSurface->setRole(role); 0118 QFETCH(bool, expectedOnAllDesktops); 0119 QCOMPARE(onAllDesktopsSpy.wait(), expectedOnAllDesktops); 0120 QCOMPARE(window->isOnAllDesktops(), expectedOnAllDesktops); 0121 0122 // let's create a second window where we init a little bit different 0123 // first creating the PlasmaSurface then the Shell Surface 0124 std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface()); 0125 QVERIFY(surface2 != nullptr); 0126 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface2(m_plasmaShell->createSurface(surface2.get())); 0127 QVERIFY(plasmaSurface2 != nullptr); 0128 plasmaSurface2->setRole(role); 0129 std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get())); 0130 QVERIFY(shellSurface2 != nullptr); 0131 auto c2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue); 0132 QVERIFY(c2); 0133 QVERIFY(window != c2); 0134 0135 QCOMPARE(c2->isOnAllDesktops(), expectedOnAllDesktops); 0136 } 0137 0138 void PlasmaSurfaceTest::testAcceptsFocus_data() 0139 { 0140 QTest::addColumn<KWayland::Client::PlasmaShellSurface::Role>("role"); 0141 QTest::addColumn<bool>("wantsInput"); 0142 QTest::addColumn<bool>("active"); 0143 0144 QTest::newRow("Desktop") << KWayland::Client::PlasmaShellSurface::Role::Desktop << true << true; 0145 QTest::newRow("Panel") << KWayland::Client::PlasmaShellSurface::Role::Panel << true << false; 0146 QTest::newRow("OSD") << KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay << false << false; 0147 QTest::newRow("Normal") << KWayland::Client::PlasmaShellSurface::Role::Normal << true << true; 0148 QTest::newRow("Notification") << KWayland::Client::PlasmaShellSurface::Role::Notification << false << false; 0149 QTest::newRow("ToolTip") << KWayland::Client::PlasmaShellSurface::Role::ToolTip << false << false; 0150 QTest::newRow("CriticalNotification") << KWayland::Client::PlasmaShellSurface::Role::CriticalNotification << false << false; 0151 QTest::newRow("AppletPopup") << KWayland::Client::PlasmaShellSurface::Role::AppletPopup << true << true; 0152 } 0153 0154 void PlasmaSurfaceTest::testAcceptsFocus() 0155 { 0156 // this test verifies that some surface roles don't get focus 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 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get())); 0162 QVERIFY(plasmaSurface != nullptr); 0163 QFETCH(KWayland::Client::PlasmaShellSurface::Role, role); 0164 plasmaSurface->setRole(role); 0165 0166 // now render to map the window 0167 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0168 0169 QVERIFY(window); 0170 QTEST(window->wantsInput(), "wantsInput"); 0171 QTEST(window->isActive(), "active"); 0172 } 0173 0174 void PlasmaSurfaceTest::testOSDPlacement() 0175 { 0176 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0177 QVERIFY(surface != nullptr); 0178 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0179 QVERIFY(shellSurface != nullptr); 0180 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get())); 0181 QVERIFY(plasmaSurface != nullptr); 0182 plasmaSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay); 0183 0184 // now render and map the window 0185 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0186 0187 QVERIFY(window); 0188 QCOMPARE(window->windowType(), NET::OnScreenDisplay); 0189 QVERIFY(window->isOnScreenDisplay()); 0190 QCOMPARE(window->frameGeometry(), QRect(1280 / 2 - 100 / 2, 2 * 1024 / 3 - 50 / 2, 100, 50)); 0191 0192 // change the screen size 0193 const QList<QRect> geometries{QRect(0, 0, 1280, 1024), QRect(1280, 0, 1280, 1024)}; 0194 Test::setOutputConfig(geometries); 0195 const auto outputs = workspace()->outputs(); 0196 QCOMPARE(outputs.count(), 2); 0197 QCOMPARE(outputs[0]->geometry(), geometries[0]); 0198 QCOMPARE(outputs[1]->geometry(), geometries[1]); 0199 0200 QCOMPARE(window->frameGeometry(), QRect(1280 / 2 - 100 / 2, 2 * 1024 / 3 - 50 / 2, 100, 50)); 0201 0202 // change size of window 0203 QSignalSpy frameGeometryChangedSpy(window, &Window::frameGeometryChanged); 0204 Test::render(surface.get(), QSize(200, 100), Qt::red); 0205 QVERIFY(frameGeometryChangedSpy.wait()); 0206 QCOMPARE(window->frameGeometry(), QRect(1280 / 2 - 200 / 2, 2 * 1024 / 3 - 100 / 2, 200, 100)); 0207 } 0208 0209 void PlasmaSurfaceTest::testOSDPlacementManualPosition() 0210 { 0211 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0212 QVERIFY(surface != nullptr); 0213 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get())); 0214 QVERIFY(plasmaSurface != nullptr); 0215 plasmaSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay); 0216 0217 plasmaSurface->setPosition(QPoint(50, 70)); 0218 0219 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0220 QVERIFY(shellSurface != nullptr); 0221 0222 // now render and map the window 0223 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0224 0225 QVERIFY(window); 0226 QVERIFY(!window->isPlaceable()); 0227 QCOMPARE(window->windowType(), NET::OnScreenDisplay); 0228 QVERIFY(window->isOnScreenDisplay()); 0229 QCOMPARE(window->frameGeometry(), QRect(50, 70, 100, 50)); 0230 } 0231 0232 void PlasmaSurfaceTest::testPanelActivate_data() 0233 { 0234 QTest::addColumn<bool>("wantsFocus"); 0235 QTest::addColumn<bool>("active"); 0236 0237 QTest::newRow("no focus") << false << false; 0238 QTest::newRow("focus") << true << true; 0239 } 0240 0241 void PlasmaSurfaceTest::testPanelActivate() 0242 { 0243 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0244 QVERIFY(surface != nullptr); 0245 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0246 QVERIFY(shellSurface != nullptr); 0247 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(m_plasmaShell->createSurface(surface.get())); 0248 QVERIFY(plasmaSurface != nullptr); 0249 plasmaSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::Panel); 0250 QFETCH(bool, wantsFocus); 0251 plasmaSurface->setPanelTakesFocus(wantsFocus); 0252 0253 auto panel = Test::renderAndWaitForShown(surface.get(), QSize(100, 200), Qt::blue); 0254 0255 QVERIFY(panel); 0256 QCOMPARE(panel->windowType(), NET::Dock); 0257 QVERIFY(panel->isDock()); 0258 QFETCH(bool, active); 0259 QCOMPARE(panel->dockWantsInput(), active); 0260 QCOMPARE(panel->isActive(), active); 0261 } 0262 0263 void PlasmaSurfaceTest::testMovable_data() 0264 { 0265 QTest::addColumn<KWayland::Client::PlasmaShellSurface::Role>("role"); 0266 QTest::addColumn<bool>("movable"); 0267 QTest::addColumn<bool>("movableAcrossScreens"); 0268 QTest::addColumn<bool>("resizable"); 0269 0270 QTest::newRow("normal") << KWayland::Client::PlasmaShellSurface::Role::Normal << true << true << true; 0271 QTest::newRow("desktop") << KWayland::Client::PlasmaShellSurface::Role::Desktop << false << false << false; 0272 QTest::newRow("panel") << KWayland::Client::PlasmaShellSurface::Role::Panel << false << false << false; 0273 QTest::newRow("osd") << KWayland::Client::PlasmaShellSurface::Role::OnScreenDisplay << false << false << false; 0274 } 0275 0276 void PlasmaSurfaceTest::testMovable() 0277 { 0278 // this test verifies that certain window types from PlasmaShellSurface are not moveable or resizable 0279 std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface()); 0280 QVERIFY(surface != nullptr); 0281 0282 std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get())); 0283 QVERIFY(shellSurface != nullptr); 0284 // and a PlasmaShellSurface 0285 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(Test::waylandPlasmaShell()->createSurface(surface.get())); 0286 QVERIFY(plasmaSurface != nullptr); 0287 QFETCH(KWayland::Client::PlasmaShellSurface::Role, role); 0288 plasmaSurface->setRole(role); 0289 // let's render 0290 auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); 0291 0292 QVERIFY(window); 0293 QTEST(window->isMovable(), "movable"); 0294 QTEST(window->isMovableAcrossScreens(), "movableAcrossScreens"); 0295 QTEST(window->isResizable(), "resizable"); 0296 surface.reset(); 0297 QVERIFY(Test::waitForWindowClosed(window)); 0298 } 0299 0300 WAYLANDTEST_MAIN(PlasmaSurfaceTest) 0301 #include "plasma_surface_test.moc"