File indexing completed on 2024-11-10 04:56:20
0001 /* 0002 SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 // Qt 0007 #include <QSignalSpy> 0008 #include <QTest> 0009 // KWin 0010 #include "wayland/compositor.h" 0011 #include "wayland/display.h" 0012 #include "wayland/plasmawindowmanagement.h" 0013 #include "wayland/surface.h" 0014 #include <wayland-plasma-window-management-client-protocol.h> 0015 0016 #include "KWayland/Client/compositor.h" 0017 #include "KWayland/Client/connection_thread.h" 0018 #include "KWayland/Client/event_queue.h" 0019 #include "KWayland/Client/plasmawindowmanagement.h" 0020 #include "KWayland/Client/region.h" 0021 #include "KWayland/Client/registry.h" 0022 #include "KWayland/Client/surface.h" 0023 0024 typedef void (KWin::PlasmaWindowInterface::*ServerWindowSignal)(); 0025 Q_DECLARE_METATYPE(ServerWindowSignal) 0026 typedef void (KWin::PlasmaWindowInterface::*ServerWindowBooleanSignal)(bool); 0027 Q_DECLARE_METATYPE(ServerWindowBooleanSignal) 0028 typedef void (KWayland::Client::PlasmaWindow::*ClientWindowVoidSetter)(); 0029 Q_DECLARE_METATYPE(ClientWindowVoidSetter) 0030 0031 class TestWindowManagement : public QObject 0032 { 0033 Q_OBJECT 0034 public: 0035 explicit TestWindowManagement(QObject *parent = nullptr); 0036 private Q_SLOTS: 0037 void init(); 0038 0039 void testWindowTitle(); 0040 void testReallyLongTitle(); 0041 void testMinimizedGeometry(); 0042 void testUseAfterUnmap(); 0043 void testServerDelete(); 0044 void testActiveWindowOnUnmapped(); 0045 void testDeleteActiveWindow(); 0046 void testCreateAfterUnmap(); 0047 void testRequests_data(); 0048 void testRequests(); 0049 void testRequestsBoolean_data(); 0050 void testRequestsBoolean(); 0051 void testKeepAbove(); 0052 void testKeepBelow(); 0053 void testShowingDesktop(); 0054 void testRequestShowingDesktop_data(); 0055 void testRequestShowingDesktop(); 0056 void testParentWindow(); 0057 void testGeometry(); 0058 void testIcon(); 0059 void testPid(); 0060 void testApplicationMenu(); 0061 0062 void cleanup(); 0063 0064 private: 0065 KWin::Display *m_display; 0066 KWin::CompositorInterface *m_compositorInterface; 0067 KWin::PlasmaWindowManagementInterface *m_windowManagementInterface; 0068 KWin::PlasmaWindowInterface *m_windowInterface; 0069 QPointer<KWin::SurfaceInterface> m_surfaceInterface; 0070 0071 KWayland::Client::Surface *m_surface = nullptr; 0072 KWayland::Client::ConnectionThread *m_connection; 0073 KWayland::Client::Compositor *m_compositor; 0074 KWayland::Client::EventQueue *m_queue; 0075 KWayland::Client::PlasmaWindowManagement *m_windowManagement; 0076 KWayland::Client::PlasmaWindow *m_window; 0077 QThread *m_thread; 0078 KWayland::Client::Registry *m_registry; 0079 }; 0080 0081 static const QString s_socketName = QStringLiteral("kwayland-test-wayland-windowmanagement-0"); 0082 0083 TestWindowManagement::TestWindowManagement(QObject *parent) 0084 : QObject(parent) 0085 , m_display(nullptr) 0086 , m_compositorInterface(nullptr) 0087 , m_connection(nullptr) 0088 , m_compositor(nullptr) 0089 , m_queue(nullptr) 0090 , m_thread(nullptr) 0091 { 0092 } 0093 0094 void TestWindowManagement::init() 0095 { 0096 using namespace KWin; 0097 qRegisterMetaType<KWin::PlasmaWindowManagementInterface::ShowingDesktopState>("ShowingDesktopState"); 0098 delete m_display; 0099 m_display = new KWin::Display(this); 0100 m_display->addSocketName(s_socketName); 0101 m_display->start(); 0102 QVERIFY(m_display->isRunning()); 0103 0104 // setup connection 0105 m_connection = new KWayland::Client::ConnectionThread; 0106 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected); 0107 m_connection->setSocketName(s_socketName); 0108 0109 m_thread = new QThread(this); 0110 m_connection->moveToThread(m_thread); 0111 m_thread->start(); 0112 0113 m_connection->initConnection(); 0114 QVERIFY(connectedSpy.wait()); 0115 0116 m_queue = new KWayland::Client::EventQueue(this); 0117 QVERIFY(!m_queue->isValid()); 0118 m_queue->setup(m_connection); 0119 QVERIFY(m_queue->isValid()); 0120 0121 m_registry = new KWayland::Client::Registry(this); 0122 QSignalSpy compositorSpy(m_registry, &KWayland::Client::Registry::compositorAnnounced); 0123 0124 QSignalSpy windowManagementSpy(m_registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced); 0125 0126 QVERIFY(!m_registry->eventQueue()); 0127 m_registry->setEventQueue(m_queue); 0128 QCOMPARE(m_registry->eventQueue(), m_queue); 0129 m_registry->create(m_connection->display()); 0130 QVERIFY(m_registry->isValid()); 0131 m_registry->setup(); 0132 0133 m_compositorInterface = new CompositorInterface(m_display, m_display); 0134 QVERIFY(compositorSpy.wait()); 0135 m_compositor = m_registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this); 0136 0137 m_windowManagementInterface = new PlasmaWindowManagementInterface(m_display, m_display); 0138 0139 QVERIFY(windowManagementSpy.wait()); 0140 m_windowManagement = m_registry->createPlasmaWindowManagement(windowManagementSpy.first().first().value<quint32>(), 0141 windowManagementSpy.first().last().value<quint32>(), 0142 this); 0143 0144 QSignalSpy windowSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::windowCreated); 0145 m_windowInterface = m_windowManagementInterface->createWindow(this, QUuid::createUuid()); 0146 m_windowInterface->setPid(1337); 0147 0148 QVERIFY(windowSpy.wait()); 0149 m_window = windowSpy.first().first().value<KWayland::Client::PlasmaWindow *>(); 0150 0151 QSignalSpy serverSurfaceCreated(m_compositorInterface, &KWin::CompositorInterface::surfaceCreated); 0152 m_surface = m_compositor->createSurface(this); 0153 QVERIFY(m_surface); 0154 0155 QVERIFY(serverSurfaceCreated.wait()); 0156 m_surfaceInterface = serverSurfaceCreated.first().first().value<KWin::SurfaceInterface *>(); 0157 QVERIFY(m_surfaceInterface); 0158 } 0159 0160 void TestWindowManagement::testWindowTitle() 0161 { 0162 m_windowInterface->setTitle(QStringLiteral("Test Title")); 0163 0164 QSignalSpy titleSpy(m_window, &KWayland::Client::PlasmaWindow::titleChanged); 0165 0166 QVERIFY(titleSpy.wait()); 0167 0168 QCOMPARE(m_window->title(), QString::fromUtf8("Test Title")); 0169 } 0170 0171 void TestWindowManagement::testReallyLongTitle() 0172 { 0173 QString title; 0174 title.fill(QLatin1Char('t'), 500000); 0175 m_windowInterface->setTitle(title); 0176 0177 QSignalSpy titleSpy(m_window, &KWayland::Client::PlasmaWindow::titleChanged); 0178 0179 QVERIFY(titleSpy.wait()); 0180 QVERIFY(m_window->title().startsWith("t")); 0181 } 0182 0183 void TestWindowManagement::testMinimizedGeometry() 0184 { 0185 m_window->setMinimizedGeometry(m_surface, QRect(5, 10, 100, 200)); 0186 0187 QSignalSpy geometrySpy(m_windowInterface, &KWin::PlasmaWindowInterface::minimizedGeometriesChanged); 0188 0189 QVERIFY(geometrySpy.wait()); 0190 QCOMPARE(m_windowInterface->minimizedGeometries().values().first(), QRect(5, 10, 100, 200)); 0191 0192 m_window->unsetMinimizedGeometry(m_surface); 0193 QVERIFY(geometrySpy.wait()); 0194 QVERIFY(m_windowInterface->minimizedGeometries().isEmpty()); 0195 } 0196 0197 void TestWindowManagement::cleanup() 0198 { 0199 if (m_surface) { 0200 delete m_surface; 0201 m_surface = nullptr; 0202 } 0203 if (m_compositor) { 0204 delete m_compositor; 0205 m_compositor = nullptr; 0206 } 0207 if (m_queue) { 0208 delete m_queue; 0209 m_queue = nullptr; 0210 } 0211 if (m_windowManagement) { 0212 delete m_windowManagement; 0213 m_windowManagement = nullptr; 0214 } 0215 if (m_registry) { 0216 delete m_registry; 0217 m_registry = nullptr; 0218 } 0219 if (m_thread) { 0220 if (m_connection) { 0221 m_connection->flush(); 0222 m_connection->deleteLater(); 0223 } 0224 m_thread->quit(); 0225 m_thread->wait(); 0226 delete m_thread; 0227 m_thread = nullptr; 0228 } 0229 m_connection = nullptr; 0230 0231 m_display->dispatchEvents(); 0232 0233 QVERIFY(m_surfaceInterface.isNull()); 0234 0235 delete m_display; 0236 m_display = nullptr; 0237 0238 // these are the children of the display 0239 m_windowManagementInterface = nullptr; 0240 m_windowInterface = nullptr; 0241 } 0242 0243 void TestWindowManagement::testUseAfterUnmap() 0244 { 0245 // this test verifies that when the client uses a window after it's unmapped, things don't break 0246 QSignalSpy unmappedSpy(m_window, &KWayland::Client::PlasmaWindow::unmapped); 0247 QSignalSpy destroyedSpy(m_window, &QObject::destroyed); 0248 m_windowInterface->deleteLater(); 0249 m_windowInterface = nullptr; 0250 m_window->requestClose(); 0251 QVERIFY(unmappedSpy.wait()); 0252 QVERIFY(destroyedSpy.wait()); 0253 m_window = nullptr; 0254 } 0255 0256 void TestWindowManagement::testServerDelete() 0257 { 0258 QSignalSpy unmappedSpy(m_window, &KWayland::Client::PlasmaWindow::unmapped); 0259 QSignalSpy destroyedSpy(m_window, &QObject::destroyed); 0260 delete m_windowInterface; 0261 m_windowInterface = nullptr; 0262 QVERIFY(unmappedSpy.wait()); 0263 QVERIFY(destroyedSpy.wait()); 0264 m_window = nullptr; 0265 } 0266 0267 void TestWindowManagement::testActiveWindowOnUnmapped() 0268 { 0269 // This test verifies that unmapping the active window changes the active window. 0270 // first make the window active 0271 QVERIFY(!m_windowManagement->activeWindow()); 0272 QVERIFY(!m_window->isActive()); 0273 QSignalSpy activeWindowChangedSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::activeWindowChanged); 0274 m_windowInterface->setActive(true); 0275 QVERIFY(activeWindowChangedSpy.wait()); 0276 QCOMPARE(m_windowManagement->activeWindow(), m_window); 0277 QVERIFY(m_window->isActive()); 0278 0279 // now unmap should change the active window 0280 QSignalSpy destroyedSpy(m_window, &QObject::destroyed); 0281 QSignalSpy serverDestroyedSpy(m_windowInterface, &QObject::destroyed); 0282 delete m_windowInterface; 0283 m_windowInterface = nullptr; 0284 QVERIFY(activeWindowChangedSpy.wait()); 0285 QVERIFY(!m_windowManagement->activeWindow()); 0286 } 0287 0288 void TestWindowManagement::testDeleteActiveWindow() 0289 { 0290 // This test verifies that deleting the active window on client side changes the active window 0291 // first make the window active 0292 QVERIFY(!m_windowManagement->activeWindow()); 0293 QVERIFY(!m_window->isActive()); 0294 QSignalSpy activeWindowChangedSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::activeWindowChanged); 0295 m_windowInterface->setActive(true); 0296 QVERIFY(activeWindowChangedSpy.wait()); 0297 QCOMPARE(activeWindowChangedSpy.count(), 1); 0298 QCOMPARE(m_windowManagement->activeWindow(), m_window); 0299 QVERIFY(m_window->isActive()); 0300 0301 // delete the client side window - that's semantically kind of wrong, but shouldn't make our code crash 0302 delete m_window; 0303 m_window = nullptr; 0304 QCOMPARE(activeWindowChangedSpy.count(), 2); 0305 QVERIFY(!m_windowManagement->activeWindow()); 0306 } 0307 0308 void TestWindowManagement::testCreateAfterUnmap() 0309 { 0310 // this test verifies that we don't get a protocol error on client side when creating an already unmapped window. 0311 QCOMPARE(m_windowManagement->children().count(), 1); 0312 0313 QSignalSpy windowAddedSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::windowCreated); 0314 0315 // create and unmap in one go 0316 // client will first handle the create, the unmap will be sent once the server side is bound 0317 auto serverWindow = m_windowManagementInterface->createWindow(m_windowManagementInterface, QUuid::createUuid()); 0318 delete serverWindow; 0319 QCOMPARE(m_windowManagementInterface->children().count(), 0); 0320 0321 windowAddedSpy.wait(); 0322 auto window = dynamic_cast<KWayland::Client::PlasmaWindow *>(m_windowManagement->children().last()); 0323 QVERIFY(window); 0324 // now this is not yet on the server, on the server it will be after next roundtrip 0325 // which we can trigger by waiting for destroy of the newly created window. 0326 // why destroy? Because we will get the unmap which triggers a destroy 0327 QSignalSpy clientDestroyedSpy(window, &QObject::destroyed); 0328 QVERIFY(clientDestroyedSpy.wait()); 0329 // Verify that any wrappers created for our temporary window are now gone 0330 QCOMPARE(m_windowManagement->children().count(), 1); 0331 } 0332 0333 void TestWindowManagement::testRequests_data() 0334 { 0335 using namespace KWin; 0336 QTest::addColumn<ServerWindowSignal>("changedSignal"); 0337 QTest::addColumn<ClientWindowVoidSetter>("requester"); 0338 0339 QTest::newRow("close") << &PlasmaWindowInterface::closeRequested << &KWayland::Client::PlasmaWindow::requestClose; 0340 QTest::newRow("move") << &PlasmaWindowInterface::moveRequested << &KWayland::Client::PlasmaWindow::requestMove; 0341 QTest::newRow("resize") << &PlasmaWindowInterface::resizeRequested << &KWayland::Client::PlasmaWindow::requestResize; 0342 } 0343 0344 void TestWindowManagement::testRequests() 0345 { 0346 // this test case verifies all the different requests on a PlasmaWindow 0347 QFETCH(ServerWindowSignal, changedSignal); 0348 QSignalSpy requestSpy(m_windowInterface, changedSignal); 0349 QFETCH(ClientWindowVoidSetter, requester); 0350 (m_window->*(requester))(); 0351 QVERIFY(requestSpy.wait()); 0352 } 0353 0354 void TestWindowManagement::testRequestsBoolean_data() 0355 { 0356 using namespace KWin; 0357 QTest::addColumn<ServerWindowBooleanSignal>("changedSignal"); 0358 QTest::addColumn<int>("flag"); 0359 0360 QTest::newRow("activate") << &PlasmaWindowInterface::activeRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE); 0361 QTest::newRow("minimized") << &PlasmaWindowInterface::minimizedRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED); 0362 QTest::newRow("maximized") << &PlasmaWindowInterface::maximizedRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED); 0363 QTest::newRow("fullscreen") << &PlasmaWindowInterface::fullscreenRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN); 0364 QTest::newRow("keepAbove") << &PlasmaWindowInterface::keepAboveRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE); 0365 QTest::newRow("keepBelow") << &PlasmaWindowInterface::keepBelowRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW); 0366 QTest::newRow("demandsAttention") << &PlasmaWindowInterface::demandsAttentionRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION); 0367 QTest::newRow("closeable") << &PlasmaWindowInterface::closeableRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE); 0368 QTest::newRow("minimizable") << &PlasmaWindowInterface::minimizeableRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE); 0369 QTest::newRow("maximizable") << &PlasmaWindowInterface::maximizeableRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE); 0370 QTest::newRow("fullscreenable") << &PlasmaWindowInterface::fullscreenableRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE); 0371 QTest::newRow("skiptaskbar") << &PlasmaWindowInterface::skipTaskbarRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR); 0372 QTest::newRow("skipSwitcher") << &PlasmaWindowInterface::skipSwitcherRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER); 0373 QTest::newRow("shadeable") << &PlasmaWindowInterface::shadeableRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE); 0374 QTest::newRow("shaded") << &PlasmaWindowInterface::shadedRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED); 0375 QTest::newRow("movable") << &PlasmaWindowInterface::movableRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE); 0376 QTest::newRow("resizable") << &PlasmaWindowInterface::resizableRequested << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE); 0377 QTest::newRow("virtualDesktopChangeable") << &PlasmaWindowInterface::virtualDesktopChangeableRequested 0378 << int(ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE); 0379 } 0380 0381 void TestWindowManagement::testRequestsBoolean() 0382 { 0383 // this test case verifies all the different requests on a PlasmaWindow 0384 QFETCH(ServerWindowBooleanSignal, changedSignal); 0385 QSignalSpy requestSpy(m_windowInterface, changedSignal); 0386 QFETCH(int, flag); 0387 org_kde_plasma_window_set_state(*m_window, flag, flag); 0388 QVERIFY(requestSpy.wait()); 0389 QCOMPARE(requestSpy.count(), 1); 0390 QCOMPARE(requestSpy.first().first().toBool(), true); 0391 org_kde_plasma_window_set_state(*m_window, flag, 0); 0392 QVERIFY(requestSpy.wait()); 0393 QCOMPARE(requestSpy.count(), 2); 0394 QCOMPARE(requestSpy.last().first().toBool(), false); 0395 } 0396 0397 void TestWindowManagement::testShowingDesktop() 0398 { 0399 using namespace KWin; 0400 // this test verifies setting the showing desktop state 0401 QVERIFY(!m_windowManagement->isShowingDesktop()); 0402 QSignalSpy showingDesktopChangedSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::showingDesktopChanged); 0403 m_windowManagementInterface->setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState::Enabled); 0404 QVERIFY(showingDesktopChangedSpy.wait()); 0405 QCOMPARE(showingDesktopChangedSpy.count(), 1); 0406 QCOMPARE(showingDesktopChangedSpy.first().first().toBool(), true); 0407 QVERIFY(m_windowManagement->isShowingDesktop()); 0408 // setting to same should not change 0409 m_windowManagementInterface->setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState::Enabled); 0410 QVERIFY(!showingDesktopChangedSpy.wait(100)); 0411 QCOMPARE(showingDesktopChangedSpy.count(), 1); 0412 // setting to other state should change 0413 m_windowManagementInterface->setShowingDesktopState(PlasmaWindowManagementInterface::ShowingDesktopState::Disabled); 0414 QVERIFY(showingDesktopChangedSpy.wait()); 0415 QCOMPARE(showingDesktopChangedSpy.count(), 2); 0416 QCOMPARE(showingDesktopChangedSpy.first().first().toBool(), true); 0417 QCOMPARE(showingDesktopChangedSpy.last().first().toBool(), false); 0418 QVERIFY(!m_windowManagement->isShowingDesktop()); 0419 } 0420 0421 void TestWindowManagement::testRequestShowingDesktop_data() 0422 { 0423 using namespace KWin; 0424 QTest::addColumn<bool>("value"); 0425 QTest::addColumn<PlasmaWindowManagementInterface::ShowingDesktopState>("expectedValue"); 0426 0427 QTest::newRow("enable") << true << PlasmaWindowManagementInterface::ShowingDesktopState::Enabled; 0428 QTest::newRow("disable") << false << PlasmaWindowManagementInterface::ShowingDesktopState::Disabled; 0429 } 0430 0431 void TestWindowManagement::testRequestShowingDesktop() 0432 { 0433 // this test verifies requesting show desktop state 0434 using namespace KWin; 0435 QSignalSpy requestSpy(m_windowManagementInterface, &PlasmaWindowManagementInterface::requestChangeShowingDesktop); 0436 QFETCH(bool, value); 0437 m_windowManagement->setShowingDesktop(value); 0438 QVERIFY(requestSpy.wait()); 0439 QCOMPARE(requestSpy.count(), 1); 0440 QTEST(requestSpy.first().first().value<PlasmaWindowManagementInterface::ShowingDesktopState>(), "expectedValue"); 0441 } 0442 0443 void TestWindowManagement::testKeepAbove() 0444 { 0445 using namespace KWin; 0446 // this test verifies setting the keep above state 0447 QVERIFY(!m_window->isKeepAbove()); 0448 QSignalSpy keepAboveChangedSpy(m_window, &KWayland::Client::PlasmaWindow::keepAboveChanged); 0449 m_windowInterface->setKeepAbove(true); 0450 QVERIFY(keepAboveChangedSpy.wait()); 0451 QCOMPARE(keepAboveChangedSpy.count(), 1); 0452 QVERIFY(m_window->isKeepAbove()); 0453 // setting to same should not change 0454 m_windowInterface->setKeepAbove(true); 0455 QVERIFY(!keepAboveChangedSpy.wait(100)); 0456 QCOMPARE(keepAboveChangedSpy.count(), 1); 0457 // setting to other state should change 0458 m_windowInterface->setKeepAbove(false); 0459 QVERIFY(keepAboveChangedSpy.wait()); 0460 QCOMPARE(keepAboveChangedSpy.count(), 2); 0461 QVERIFY(!m_window->isKeepAbove()); 0462 } 0463 0464 void TestWindowManagement::testKeepBelow() 0465 { 0466 using namespace KWin; 0467 // this test verifies setting the keep below state 0468 QVERIFY(!m_window->isKeepBelow()); 0469 QSignalSpy keepBelowChangedSpy(m_window, &KWayland::Client::PlasmaWindow::keepBelowChanged); 0470 m_windowInterface->setKeepBelow(true); 0471 QVERIFY(keepBelowChangedSpy.wait()); 0472 QCOMPARE(keepBelowChangedSpy.count(), 1); 0473 QVERIFY(m_window->isKeepBelow()); 0474 // setting to same should not change 0475 m_windowInterface->setKeepBelow(true); 0476 QVERIFY(!keepBelowChangedSpy.wait(100)); 0477 QCOMPARE(keepBelowChangedSpy.count(), 1); 0478 // setting to other state should change 0479 m_windowInterface->setKeepBelow(false); 0480 QVERIFY(keepBelowChangedSpy.wait()); 0481 QCOMPARE(keepBelowChangedSpy.count(), 2); 0482 QVERIFY(!m_window->isKeepBelow()); 0483 } 0484 0485 void TestWindowManagement::testParentWindow() 0486 { 0487 // this test verifies the functionality of ParentWindows 0488 QCOMPARE(m_windowManagement->windows().count(), 1); 0489 auto parentWindow = m_windowManagement->windows().first(); 0490 QVERIFY(parentWindow); 0491 QVERIFY(parentWindow->parentWindow().isNull()); 0492 0493 // now let's create a second window 0494 QSignalSpy windowAddedSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::windowCreated); 0495 std::unique_ptr<KWin::PlasmaWindowInterface> serverTransient(m_windowManagementInterface->createWindow(this, QUuid::createUuid())); 0496 serverTransient->setParentWindow(m_windowInterface); 0497 QVERIFY(windowAddedSpy.wait()); 0498 auto transient = windowAddedSpy.first().first().value<KWayland::Client::PlasmaWindow *>(); 0499 QCOMPARE(transient->parentWindow().data(), parentWindow); 0500 0501 // let's unset the parent 0502 QSignalSpy parentWindowChangedSpy(transient, &KWayland::Client::PlasmaWindow::parentWindowChanged); 0503 serverTransient->setParentWindow(nullptr); 0504 QVERIFY(parentWindowChangedSpy.wait()); 0505 QVERIFY(transient->parentWindow().isNull()); 0506 0507 // and set it again 0508 serverTransient->setParentWindow(m_windowInterface); 0509 QVERIFY(parentWindowChangedSpy.wait()); 0510 QCOMPARE(transient->parentWindow().data(), parentWindow); 0511 0512 // now let's try to unmap the parent 0513 m_windowInterface->deleteLater(); 0514 m_window = nullptr; 0515 m_windowInterface = nullptr; 0516 QVERIFY(parentWindowChangedSpy.wait()); 0517 QVERIFY(transient->parentWindow().isNull()); 0518 } 0519 0520 void TestWindowManagement::testGeometry() 0521 { 0522 QVERIFY(m_window); 0523 QCOMPARE(m_window->geometry(), QRect()); 0524 QSignalSpy windowGeometryChangedSpy(m_window, &KWayland::Client::PlasmaWindow::geometryChanged); 0525 m_windowInterface->setGeometry(QRect(20, -10, 30, 40)); 0526 QVERIFY(windowGeometryChangedSpy.wait()); 0527 QCOMPARE(m_window->geometry(), QRect(20, -10, 30, 40)); 0528 // setting an empty geometry should not be sent to the client 0529 m_windowInterface->setGeometry(QRect()); 0530 QVERIFY(!windowGeometryChangedSpy.wait(10)); 0531 // setting to the geometry which the client still has should not trigger signal 0532 m_windowInterface->setGeometry(QRect(20, -10, 30, 40)); 0533 QVERIFY(!windowGeometryChangedSpy.wait(10)); 0534 // setting another geometry should work, though 0535 m_windowInterface->setGeometry(QRect(0, 0, 35, 45)); 0536 QVERIFY(windowGeometryChangedSpy.wait()); 0537 QCOMPARE(windowGeometryChangedSpy.count(), 2); 0538 QCOMPARE(m_window->geometry(), QRect(0, 0, 35, 45)); 0539 0540 // let's bind a second PlasmaWindowManagement to verify the initial setting 0541 std::unique_ptr<KWayland::Client::PlasmaWindowManagement> pm( 0542 m_registry->createPlasmaWindowManagement(m_registry->interface(KWayland::Client::Registry::Interface::PlasmaWindowManagement).name, 0543 m_registry->interface(KWayland::Client::Registry::Interface::PlasmaWindowManagement).version)); 0544 QVERIFY(pm != nullptr); 0545 QSignalSpy windowAddedSpy(pm.get(), &KWayland::Client::PlasmaWindowManagement::windowCreated); 0546 QVERIFY(windowAddedSpy.wait()); 0547 auto window = pm->windows().first(); 0548 QCOMPARE(window->geometry(), QRect(0, 0, 35, 45)); 0549 } 0550 0551 void TestWindowManagement::testIcon() 0552 { 0553 // initially, there shouldn't be any icon 0554 QSignalSpy iconChangedSpy(m_window, &KWayland::Client::PlasmaWindow::iconChanged); 0555 QVERIFY(m_window->icon().isNull()); 0556 0557 // create an icon with a pixmap 0558 QImage p(32, 32, QImage::Format_ARGB32_Premultiplied); 0559 p.fill(Qt::red); 0560 const QIcon dummyIcon(QPixmap::fromImage(p)); 0561 m_windowInterface->setIcon(dummyIcon); 0562 QVERIFY(iconChangedSpy.wait()); 0563 QCOMPARE(iconChangedSpy.count(), 1); 0564 QCOMPARE(m_window->icon().pixmap(32, 32), dummyIcon.pixmap(32, 32)); 0565 0566 // let's set a themed icon 0567 m_windowInterface->setIcon(QIcon::fromTheme(QStringLiteral("wayland"))); 0568 QVERIFY(iconChangedSpy.wait()); 0569 QCOMPARE(iconChangedSpy.count(), 2); 0570 if (!QIcon::hasThemeIcon(QStringLiteral("wayland"))) { 0571 QEXPECT_FAIL("", "no wayland icon", Continue); 0572 } 0573 QCOMPARE(m_window->icon().name(), QStringLiteral("wayland")); 0574 } 0575 0576 void TestWindowManagement::testPid() 0577 { 0578 QVERIFY(m_window); 0579 QVERIFY(m_window->pid() == 1337); 0580 0581 // test server not setting a PID for whatever reason 0582 std::unique_ptr<KWin::PlasmaWindowInterface> newWindowInterface(m_windowManagementInterface->createWindow(this, QUuid::createUuid())); 0583 QSignalSpy windowSpy(m_windowManagement, &KWayland::Client::PlasmaWindowManagement::windowCreated); 0584 QVERIFY(windowSpy.wait()); 0585 std::unique_ptr<KWayland::Client::PlasmaWindow> newWindow(windowSpy.first().first().value<KWayland::Client::PlasmaWindow *>()); 0586 QVERIFY(newWindow); 0587 QVERIFY(newWindow->pid() == 0); 0588 } 0589 0590 void TestWindowManagement::testApplicationMenu() 0591 { 0592 const auto serviceName = QStringLiteral("org.kde.foo"); 0593 const auto objectPath = QStringLiteral("/org/kde/bar"); 0594 0595 m_windowInterface->setApplicationMenuPaths(serviceName, objectPath); 0596 0597 QSignalSpy applicationMenuChangedSpy(m_window, &KWayland::Client::PlasmaWindow::applicationMenuChanged); 0598 QVERIFY(applicationMenuChangedSpy.wait()); 0599 0600 QCOMPARE(m_window->applicationMenuServiceName(), serviceName); 0601 QCOMPARE(m_window->applicationMenuObjectPath(), objectPath); 0602 } 0603 0604 QTEST_MAIN(TestWindowManagement) 0605 #include "test_wayland_windowmanagement.moc"