File indexing completed on 2024-11-10 04:56:21
0001 /* 0002 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org> 0003 SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 // Qt 0009 #include <QSignalSpy> 0010 #include <QTest> 0011 // client 0012 #include "KWayland/Client/compositor.h" 0013 #include "KWayland/Client/connection_thread.h" 0014 #include "KWayland/Client/event_queue.h" 0015 #include "KWayland/Client/output.h" 0016 #include "KWayland/Client/registry.h" 0017 #include "KWayland/Client/seat.h" 0018 #include "KWayland/Client/shm_pool.h" 0019 #include "KWayland/Client/surface.h" 0020 #include "KWayland/Client/xdgshell.h" 0021 // server 0022 #include "wayland/compositor.h" 0023 #include "wayland/display.h" 0024 #include "wayland/output.h" 0025 #include "wayland/seat.h" 0026 #include "wayland/surface.h" 0027 #include "wayland/xdgshell.h" 0028 0029 #include "../../../tests/fakeoutput.h" 0030 0031 using namespace KWin; 0032 0033 Q_DECLARE_METATYPE(Qt::MouseButton) 0034 0035 static const QString s_socketName = QStringLiteral("kwayland-test-xdg_shell-0"); 0036 0037 class XdgShellTest : public QObject 0038 { 0039 Q_OBJECT 0040 0041 private Q_SLOTS: 0042 void init(); 0043 void cleanup(); 0044 0045 void testCreateSurface(); 0046 void testTitle(); 0047 void testWindowClass(); 0048 void testMaximize(); 0049 void testMinimize(); 0050 void testFullscreen(); 0051 void testShowWindowMenu(); 0052 void testMove(); 0053 void testResize_data(); 0054 void testResize(); 0055 void testTransient(); 0056 void testPing(); 0057 void testClose(); 0058 void testConfigureStates_data(); 0059 void testConfigureStates(); 0060 void testConfigureMultipleAcks(); 0061 0062 private: 0063 XdgShellInterface *m_xdgShellInterface = nullptr; 0064 KWayland::Client::Compositor *m_compositor = nullptr; 0065 KWayland::Client::XdgShell *m_xdgShell = nullptr; 0066 KWin::Display *m_display = nullptr; 0067 CompositorInterface *m_compositorInterface = nullptr; 0068 std::unique_ptr<FakeOutput> m_output1Handle; 0069 OutputInterface *m_output1Interface = nullptr; 0070 std::unique_ptr<FakeOutput> m_output2Handle; 0071 OutputInterface *m_output2Interface = nullptr; 0072 SeatInterface *m_seatInterface = nullptr; 0073 KWayland::Client::ConnectionThread *m_connection = nullptr; 0074 QThread *m_thread = nullptr; 0075 KWayland::Client::EventQueue *m_queue = nullptr; 0076 KWayland::Client::ShmPool *m_shmPool = nullptr; 0077 KWayland::Client::Output *m_output1 = nullptr; 0078 KWayland::Client::Output *m_output2 = nullptr; 0079 KWayland::Client::Seat *m_seat = nullptr; 0080 }; 0081 0082 #define SURFACE \ 0083 QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::toplevelCreated); \ 0084 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); \ 0085 std::unique_ptr<KWayland::Client::XdgShellSurface> xdgSurface(m_xdgShell->createSurface(surface.get())); \ 0086 QCOMPARE(xdgSurface->size(), QSize()); \ 0087 QVERIFY(xdgSurfaceCreatedSpy.wait()); \ 0088 auto serverXdgToplevel = xdgSurfaceCreatedSpy.first().first().value<XdgToplevelInterface *>(); \ 0089 QVERIFY(serverXdgToplevel); 0090 0091 void XdgShellTest::init() 0092 { 0093 delete m_display; 0094 m_display = new KWin::Display(this); 0095 m_display->addSocketName(s_socketName); 0096 m_display->start(); 0097 QVERIFY(m_display->isRunning()); 0098 m_display->createShm(); 0099 m_output1Handle = std::make_unique<FakeOutput>(); 0100 m_output1Handle->setMode(QSize(1024, 768), 60000); 0101 m_output1Interface = new OutputInterface(m_display, m_output1Handle.get(), m_display); 0102 m_output2Handle = std::make_unique<FakeOutput>(); 0103 m_output2Handle->setMode(QSize(1024, 768), 60000); 0104 m_output2Interface = new OutputInterface(m_display, m_output2Handle.get(), m_display); 0105 m_seatInterface = new SeatInterface(m_display, m_display); 0106 m_seatInterface->setHasKeyboard(true); 0107 m_seatInterface->setHasPointer(true); 0108 m_seatInterface->setHasTouch(true); 0109 m_compositorInterface = new CompositorInterface(m_display, m_display); 0110 m_xdgShellInterface = new XdgShellInterface(m_display, m_display); 0111 0112 // setup connection 0113 m_connection = new KWayland::Client::ConnectionThread; 0114 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected); 0115 m_connection->setSocketName(s_socketName); 0116 0117 m_thread = new QThread(this); 0118 m_connection->moveToThread(m_thread); 0119 m_thread->start(); 0120 0121 m_connection->initConnection(); 0122 QVERIFY(connectedSpy.wait()); 0123 0124 m_queue = new KWayland::Client::EventQueue(this); 0125 m_queue->setup(m_connection); 0126 0127 KWayland::Client::Registry registry; 0128 QSignalSpy interfacesAnnouncedSpy(®istry, &KWayland::Client::Registry::interfacesAnnounced); 0129 QSignalSpy interfaceAnnouncedSpy(®istry, &KWayland::Client::Registry::interfaceAnnounced); 0130 QSignalSpy outputAnnouncedSpy(®istry, &KWayland::Client::Registry::outputAnnounced); 0131 0132 QSignalSpy xdgShellAnnouncedSpy(®istry, &KWayland::Client::Registry::xdgShellStableAnnounced); 0133 registry.setEventQueue(m_queue); 0134 registry.create(m_connection); 0135 QVERIFY(registry.isValid()); 0136 registry.setup(); 0137 QVERIFY(interfacesAnnouncedSpy.wait()); 0138 0139 QCOMPARE(outputAnnouncedSpy.count(), 2); 0140 m_output1 = registry.createOutput(outputAnnouncedSpy.first().at(0).value<quint32>(), outputAnnouncedSpy.first().at(1).value<quint32>(), this); 0141 m_output2 = registry.createOutput(outputAnnouncedSpy.last().at(0).value<quint32>(), outputAnnouncedSpy.last().at(1).value<quint32>(), this); 0142 0143 m_shmPool = registry.createShmPool(registry.interface(KWayland::Client::Registry::Interface::Shm).name, registry.interface(KWayland::Client::Registry::Interface::Shm).version, this); 0144 QVERIFY(m_shmPool); 0145 QVERIFY(m_shmPool->isValid()); 0146 0147 m_compositor = 0148 registry.createCompositor(registry.interface(KWayland::Client::Registry::Interface::Compositor).name, registry.interface(KWayland::Client::Registry::Interface::Compositor).version, this); 0149 QVERIFY(m_compositor); 0150 QVERIFY(m_compositor->isValid()); 0151 0152 m_seat = registry.createSeat(registry.interface(KWayland::Client::Registry::Interface::Seat).name, registry.interface(KWayland::Client::Registry::Interface::Seat).version, this); 0153 QVERIFY(m_seat); 0154 QVERIFY(m_seat->isValid()); 0155 0156 QCOMPARE(xdgShellAnnouncedSpy.count(), 1); 0157 0158 m_xdgShell = registry.createXdgShell(registry.interface(KWayland::Client::Registry::Interface::XdgShellStable).name, 0159 registry.interface(KWayland::Client::Registry::Interface::XdgShellStable).version, 0160 this); 0161 QVERIFY(m_xdgShell); 0162 QVERIFY(m_xdgShell->isValid()); 0163 } 0164 0165 void XdgShellTest::cleanup() 0166 { 0167 #define CLEANUP(variable) \ 0168 if (variable) { \ 0169 delete variable; \ 0170 variable = nullptr; \ 0171 } 0172 CLEANUP(m_xdgShell) 0173 CLEANUP(m_compositor) 0174 CLEANUP(m_shmPool) 0175 CLEANUP(m_output1) 0176 CLEANUP(m_output2) 0177 CLEANUP(m_seat) 0178 CLEANUP(m_queue) 0179 if (m_connection) { 0180 m_connection->deleteLater(); 0181 m_connection = nullptr; 0182 } 0183 if (m_thread) { 0184 m_thread->quit(); 0185 m_thread->wait(); 0186 delete m_thread; 0187 m_thread = nullptr; 0188 } 0189 0190 CLEANUP(m_display) 0191 #undef CLEANUP 0192 0193 // these are the children of the display 0194 m_compositorInterface = nullptr; 0195 m_xdgShellInterface = nullptr; 0196 m_output1Handle.reset(); 0197 m_output1Interface = nullptr; 0198 m_output2Handle.reset(); 0199 m_output2Interface = nullptr; 0200 m_seatInterface = nullptr; 0201 } 0202 0203 void XdgShellTest::testCreateSurface() 0204 { 0205 // this test verifies that we can create a surface 0206 // first created the signal spies for the server 0207 QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); 0208 QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::toplevelCreated); 0209 0210 // create surface 0211 std::unique_ptr<KWayland::Client::Surface> surface(m_compositor->createSurface()); 0212 QVERIFY(surface != nullptr); 0213 QVERIFY(surfaceCreatedSpy.wait()); 0214 auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface *>(); 0215 QVERIFY(serverSurface); 0216 0217 // create shell surface 0218 std::unique_ptr<KWayland::Client::XdgShellSurface> xdgSurface(m_xdgShell->createSurface(surface.get())); 0219 QVERIFY(xdgSurface != nullptr); 0220 QVERIFY(xdgSurfaceCreatedSpy.wait()); 0221 // verify base things 0222 auto serverToplevel = xdgSurfaceCreatedSpy.first().first().value<XdgToplevelInterface *>(); 0223 QVERIFY(serverToplevel); 0224 QCOMPARE(serverToplevel->windowTitle(), QString()); 0225 QCOMPARE(serverToplevel->windowClass(), QByteArray()); 0226 QCOMPARE(serverToplevel->parentXdgToplevel(), nullptr); 0227 QCOMPARE(serverToplevel->surface(), serverSurface); 0228 0229 // now let's destroy it 0230 QSignalSpy destroyedSpy(serverToplevel, &QObject::destroyed); 0231 xdgSurface.reset(); 0232 QVERIFY(destroyedSpy.wait()); 0233 } 0234 0235 void XdgShellTest::testTitle() 0236 { 0237 // this test verifies that we can change the title of a shell surface 0238 // first create surface 0239 SURFACE 0240 0241 // should not have a title yet 0242 QCOMPARE(serverXdgToplevel->windowTitle(), QString()); 0243 0244 // lets' change the title 0245 QSignalSpy titleChangedSpy(serverXdgToplevel, &XdgToplevelInterface::windowTitleChanged); 0246 xdgSurface->setTitle(QStringLiteral("foo")); 0247 QVERIFY(titleChangedSpy.wait()); 0248 QCOMPARE(titleChangedSpy.count(), 1); 0249 QCOMPARE(titleChangedSpy.first().first().toString(), QStringLiteral("foo")); 0250 QCOMPARE(serverXdgToplevel->windowTitle(), QStringLiteral("foo")); 0251 } 0252 0253 void XdgShellTest::testWindowClass() 0254 { 0255 // this test verifies that we can change the window class/app id of a shell surface 0256 // first create surface 0257 SURFACE 0258 0259 // should not have a window class yet 0260 QCOMPARE(serverXdgToplevel->windowClass(), QByteArray()); 0261 0262 // let's change the window class 0263 QSignalSpy windowClassChanged(serverXdgToplevel, &XdgToplevelInterface::windowClassChanged); 0264 xdgSurface->setAppId(QByteArrayLiteral("org.kde.xdgsurfacetest")); 0265 QVERIFY(windowClassChanged.wait()); 0266 QCOMPARE(windowClassChanged.count(), 1); 0267 QCOMPARE(windowClassChanged.first().first().toByteArray(), QByteArrayLiteral("org.kde.xdgsurfacetest")); 0268 QCOMPARE(serverXdgToplevel->windowClass(), QByteArrayLiteral("org.kde.xdgsurfacetest")); 0269 } 0270 0271 void XdgShellTest::testMaximize() 0272 { 0273 // this test verifies that the maximize/unmaximize calls work 0274 SURFACE 0275 0276 QSignalSpy maximizeRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::maximizeRequested); 0277 QSignalSpy unmaximizeRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::unmaximizeRequested); 0278 0279 xdgSurface->setMaximized(true); 0280 QVERIFY(maximizeRequestedSpy.wait()); 0281 QCOMPARE(maximizeRequestedSpy.count(), 1); 0282 0283 xdgSurface->setMaximized(false); 0284 QVERIFY(unmaximizeRequestedSpy.wait()); 0285 QCOMPARE(unmaximizeRequestedSpy.count(), 1); 0286 } 0287 0288 void XdgShellTest::testMinimize() 0289 { 0290 // this test verifies that the minimize request is delivered 0291 SURFACE 0292 0293 QSignalSpy minimizeRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::minimizeRequested); 0294 0295 xdgSurface->requestMinimize(); 0296 QVERIFY(minimizeRequestedSpy.wait()); 0297 QCOMPARE(minimizeRequestedSpy.count(), 1); 0298 } 0299 0300 void XdgShellTest::testFullscreen() 0301 { 0302 qRegisterMetaType<OutputInterface *>(); 0303 // this test verifies going to/from fullscreen 0304 SURFACE 0305 0306 QSignalSpy fullscreenRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::fullscreenRequested); 0307 QSignalSpy unfullscreenRequestedSpy(serverXdgToplevel, &XdgToplevelInterface::unfullscreenRequested); 0308 0309 // without an output 0310 xdgSurface->setFullscreen(true, nullptr); 0311 QVERIFY(fullscreenRequestedSpy.wait()); 0312 QCOMPARE(fullscreenRequestedSpy.count(), 1); 0313 QVERIFY(!fullscreenRequestedSpy.last().at(0).value<OutputInterface *>()); 0314 0315 // unset 0316 xdgSurface->setFullscreen(false); 0317 QVERIFY(unfullscreenRequestedSpy.wait()); 0318 QCOMPARE(unfullscreenRequestedSpy.count(), 1); 0319 0320 // with outputs 0321 xdgSurface->setFullscreen(true, m_output1); 0322 QVERIFY(fullscreenRequestedSpy.wait()); 0323 QCOMPARE(fullscreenRequestedSpy.count(), 2); 0324 QCOMPARE(fullscreenRequestedSpy.last().at(0).value<OutputInterface *>(), m_output1Interface); 0325 0326 // now other output 0327 xdgSurface->setFullscreen(true, m_output2); 0328 QVERIFY(fullscreenRequestedSpy.wait()); 0329 QCOMPARE(fullscreenRequestedSpy.count(), 3); 0330 QCOMPARE(fullscreenRequestedSpy.last().at(0).value<OutputInterface *>(), m_output2Interface); 0331 } 0332 0333 void XdgShellTest::testShowWindowMenu() 0334 { 0335 qRegisterMetaType<SeatInterface *>(); 0336 // this test verifies that the show window menu request works 0337 SURFACE 0338 0339 // hack: pretend that the xdg-surface had been configured 0340 serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); 0341 0342 QSignalSpy windowMenuSpy(serverXdgToplevel, &XdgToplevelInterface::windowMenuRequested); 0343 0344 // TODO: the serial needs to be a proper one 0345 xdgSurface->requestShowWindowMenu(m_seat, 20, QPoint(30, 40)); 0346 QVERIFY(windowMenuSpy.wait()); 0347 QCOMPARE(windowMenuSpy.count(), 1); 0348 QCOMPARE(windowMenuSpy.first().at(0).value<SeatInterface *>(), m_seatInterface); 0349 QCOMPARE(windowMenuSpy.first().at(1).toPoint(), QPoint(30, 40)); 0350 QCOMPARE(windowMenuSpy.first().at(2).value<quint32>(), 20u); 0351 } 0352 0353 void XdgShellTest::testMove() 0354 { 0355 qRegisterMetaType<SeatInterface *>(); 0356 // this test verifies that the move request works 0357 SURFACE 0358 0359 // hack: pretend that the xdg-surface had been configured 0360 serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); 0361 0362 QSignalSpy moveSpy(serverXdgToplevel, &XdgToplevelInterface::moveRequested); 0363 0364 // TODO: the serial needs to be a proper one 0365 xdgSurface->requestMove(m_seat, 50); 0366 QVERIFY(moveSpy.wait()); 0367 QCOMPARE(moveSpy.count(), 1); 0368 QCOMPARE(moveSpy.first().at(0).value<SeatInterface *>(), m_seatInterface); 0369 QCOMPARE(moveSpy.first().at(1).value<quint32>(), 50u); 0370 } 0371 0372 void XdgShellTest::testResize_data() 0373 { 0374 QTest::addColumn<Qt::Edges>("edges"); 0375 QTest::addColumn<XdgToplevelInterface::ResizeAnchor>("anchor"); 0376 0377 QTest::newRow("none") << Qt::Edges() << XdgToplevelInterface::ResizeAnchor::None; 0378 QTest::newRow("top") << Qt::Edges(Qt::TopEdge) << XdgToplevelInterface::ResizeAnchor::Top; 0379 QTest::newRow("bottom") << Qt::Edges(Qt::BottomEdge) << XdgToplevelInterface::ResizeAnchor::Bottom; 0380 QTest::newRow("left") << Qt::Edges(Qt::LeftEdge) << XdgToplevelInterface::ResizeAnchor::Left; 0381 QTest::newRow("top left") << Qt::Edges(Qt::TopEdge | Qt::LeftEdge) << XdgToplevelInterface::ResizeAnchor::TopLeft; 0382 QTest::newRow("bottom left") << Qt::Edges(Qt::BottomEdge | Qt::LeftEdge) << XdgToplevelInterface::ResizeAnchor::BottomLeft; 0383 QTest::newRow("right") << Qt::Edges(Qt::RightEdge) << XdgToplevelInterface::ResizeAnchor::Right; 0384 QTest::newRow("top right") << Qt::Edges(Qt::TopEdge | Qt::RightEdge) << XdgToplevelInterface::ResizeAnchor::TopRight; 0385 QTest::newRow("bottom right") << Qt::Edges(Qt::BottomEdge | Qt::RightEdge) << XdgToplevelInterface::ResizeAnchor::BottomRight; 0386 } 0387 0388 void XdgShellTest::testResize() 0389 { 0390 qRegisterMetaType<SeatInterface *>(); 0391 // this test verifies that the resize request works 0392 SURFACE 0393 0394 // hack: pretend that the xdg-surface had been configured 0395 serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); 0396 0397 QSignalSpy resizeSpy(serverXdgToplevel, &XdgToplevelInterface::resizeRequested); 0398 0399 // TODO: the serial needs to be a proper one 0400 QFETCH(Qt::Edges, edges); 0401 xdgSurface->requestResize(m_seat, 60, edges); 0402 QVERIFY(resizeSpy.wait()); 0403 QCOMPARE(resizeSpy.count(), 1); 0404 QCOMPARE(resizeSpy.first().at(0).value<SeatInterface *>(), m_seatInterface); 0405 QTEST(resizeSpy.first().at(1).value<XdgToplevelInterface::ResizeAnchor>(), "anchor"); 0406 QCOMPARE(resizeSpy.first().at(2).value<quint32>(), 60u); 0407 } 0408 0409 void XdgShellTest::testTransient() 0410 { 0411 // this test verifies that setting the transient for works 0412 SURFACE 0413 std::unique_ptr<KWayland::Client::Surface> surface2(m_compositor->createSurface()); 0414 std::unique_ptr<KWayland::Client::XdgShellSurface> xdgSurface2(m_xdgShell->createSurface(surface2.get())); 0415 QVERIFY(xdgSurfaceCreatedSpy.wait()); 0416 auto serverXdgToplevel2 = xdgSurfaceCreatedSpy.last().first().value<XdgToplevelInterface *>(); 0417 QVERIFY(serverXdgToplevel2); 0418 0419 QVERIFY(!serverXdgToplevel->parentXdgToplevel()); 0420 QVERIFY(!serverXdgToplevel2->parentXdgToplevel()); 0421 0422 // now make xdsgSurface2 a transient for xdgSurface 0423 QSignalSpy transientForSpy(serverXdgToplevel2, &XdgToplevelInterface::parentXdgToplevelChanged); 0424 xdgSurface2->setTransientFor(xdgSurface.get()); 0425 0426 QVERIFY(transientForSpy.wait()); 0427 QCOMPARE(transientForSpy.count(), 1); 0428 QCOMPARE(serverXdgToplevel2->parentXdgToplevel(), serverXdgToplevel); 0429 QVERIFY(!serverXdgToplevel->parentXdgToplevel()); 0430 0431 // unset the transient for 0432 xdgSurface2->setTransientFor(nullptr); 0433 QVERIFY(transientForSpy.wait()); 0434 QCOMPARE(transientForSpy.count(), 2); 0435 QVERIFY(!serverXdgToplevel2->parentXdgToplevel()); 0436 QVERIFY(!serverXdgToplevel->parentXdgToplevel()); 0437 } 0438 0439 void XdgShellTest::testPing() 0440 { 0441 // this test verifies that a ping request is sent to the client 0442 SURFACE 0443 0444 QSignalSpy pingSpy(m_xdgShellInterface, &XdgShellInterface::pongReceived); 0445 0446 quint32 serial = m_xdgShellInterface->ping(serverXdgToplevel->xdgSurface()); 0447 QVERIFY(pingSpy.wait()); 0448 QCOMPARE(pingSpy.count(), 1); 0449 QCOMPARE(pingSpy.takeFirst().at(0).value<quint32>(), serial); 0450 0451 // test of a ping failure 0452 // disconnecting the connection thread to the queue will break the connection and pings will do a timeout 0453 disconnect(m_connection, &KWayland::Client::ConnectionThread::eventsRead, m_queue, &KWayland::Client::EventQueue::dispatch); 0454 m_xdgShellInterface->ping(serverXdgToplevel->xdgSurface()); 0455 QSignalSpy pingDelayedSpy(m_xdgShellInterface, &XdgShellInterface::pingDelayed); 0456 QVERIFY(pingDelayedSpy.wait()); 0457 0458 QSignalSpy pingTimeoutSpy(m_xdgShellInterface, &XdgShellInterface::pingTimeout); 0459 QVERIFY(pingTimeoutSpy.wait()); 0460 } 0461 0462 void XdgShellTest::testClose() 0463 { 0464 // this test verifies that a close request is sent to the client 0465 SURFACE 0466 0467 QSignalSpy closeSpy(xdgSurface.get(), &KWayland::Client::XdgShellSurface::closeRequested); 0468 0469 serverXdgToplevel->sendClose(); 0470 QVERIFY(closeSpy.wait()); 0471 QCOMPARE(closeSpy.count(), 1); 0472 0473 QSignalSpy destroyedSpy(serverXdgToplevel, &XdgToplevelInterface::destroyed); 0474 xdgSurface.reset(); 0475 QVERIFY(destroyedSpy.wait()); 0476 } 0477 0478 void XdgShellTest::testConfigureStates_data() 0479 { 0480 QTest::addColumn<XdgToplevelInterface::States>("serverStates"); 0481 QTest::addColumn<KWayland::Client::XdgShellSurface::States>("clientStates"); 0482 0483 const auto sa = XdgToplevelInterface::States(XdgToplevelInterface::State::Activated); 0484 const auto sm = XdgToplevelInterface::States(XdgToplevelInterface::State::Maximized); 0485 const auto sf = XdgToplevelInterface::States(XdgToplevelInterface::State::FullScreen); 0486 const auto sr = XdgToplevelInterface::States(XdgToplevelInterface::State::Resizing); 0487 0488 const auto ca = KWayland::Client::XdgShellSurface::States(KWayland::Client::XdgShellSurface::State::Activated); 0489 const auto cm = KWayland::Client::XdgShellSurface::States(KWayland::Client::XdgShellSurface::State::Maximized); 0490 const auto cf = KWayland::Client::XdgShellSurface::States(KWayland::Client::XdgShellSurface::State::Fullscreen); 0491 const auto cr = KWayland::Client::XdgShellSurface::States(KWayland::Client::XdgShellSurface::State::Resizing); 0492 0493 QTest::newRow("none") << XdgToplevelInterface::States() << KWayland::Client::XdgShellSurface::States(); 0494 QTest::newRow("Active") << sa << ca; 0495 QTest::newRow("Maximize") << sm << cm; 0496 QTest::newRow("Fullscreen") << sf << cf; 0497 QTest::newRow("Resizing") << sr << cr; 0498 0499 QTest::newRow("Active/Maximize") << (sa | sm) << (ca | cm); 0500 QTest::newRow("Active/Fullscreen") << (sa | sf) << (ca | cf); 0501 QTest::newRow("Active/Resizing") << (sa | sr) << (ca | cr); 0502 QTest::newRow("Maximize/Fullscreen") << (sm | sf) << (cm | cf); 0503 QTest::newRow("Maximize/Resizing") << (sm | sr) << (cm | cr); 0504 QTest::newRow("Fullscreen/Resizing") << (sf | sr) << (cf | cr); 0505 0506 QTest::newRow("Active/Maximize/Fullscreen") << (sa | sm | sf) << (ca | cm | cf); 0507 QTest::newRow("Active/Maximize/Resizing") << (sa | sm | sr) << (ca | cm | cr); 0508 QTest::newRow("Maximize/Fullscreen|Resizing") << (sm | sf | sr) << (cm | cf | cr); 0509 0510 QTest::newRow("Active/Maximize/Fullscreen/Resizing") << (sa | sm | sf | sr) << (ca | cm | cf | cr); 0511 } 0512 0513 void XdgShellTest::testConfigureStates() 0514 { 0515 qRegisterMetaType<KWayland::Client::XdgShellSurface::States>(); 0516 // this test verifies that configure states works 0517 SURFACE 0518 0519 QSignalSpy configureSpy(xdgSurface.get(), &KWayland::Client::XdgShellSurface::configureRequested); 0520 0521 QFETCH(XdgToplevelInterface::States, serverStates); 0522 serverXdgToplevel->sendConfigure(QSize(0, 0), serverStates); 0523 QVERIFY(configureSpy.wait()); 0524 QCOMPARE(configureSpy.count(), 1); 0525 QCOMPARE(configureSpy.first().at(0).toSize(), QSize(0, 0)); 0526 QTEST(configureSpy.first().at(1).value<KWayland::Client::XdgShellSurface::States>(), "clientStates"); 0527 QCOMPARE(configureSpy.first().at(2).value<quint32>(), m_display->serial()); 0528 0529 QSignalSpy ackSpy(serverXdgToplevel->xdgSurface(), &XdgSurfaceInterface::configureAcknowledged); 0530 0531 xdgSurface->ackConfigure(configureSpy.first().at(2).value<quint32>()); 0532 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0533 QVERIFY(ackSpy.wait()); 0534 QCOMPARE(ackSpy.count(), 1); 0535 QCOMPARE(ackSpy.first().first().value<quint32>(), configureSpy.first().at(2).value<quint32>()); 0536 } 0537 0538 void XdgShellTest::testConfigureMultipleAcks() 0539 { 0540 qRegisterMetaType<KWayland::Client::XdgShellSurface::States>(); 0541 // this test verifies that with multiple configure requests the last acknowledged one acknowledges all 0542 SURFACE 0543 0544 QSignalSpy configureSpy(xdgSurface.get(), &KWayland::Client::XdgShellSurface::configureRequested); 0545 QSignalSpy sizeChangedSpy(xdgSurface.get(), &KWayland::Client::XdgShellSurface::sizeChanged); 0546 QSignalSpy ackSpy(serverXdgToplevel->xdgSurface(), &XdgSurfaceInterface::configureAcknowledged); 0547 0548 serverXdgToplevel->sendConfigure(QSize(10, 20), XdgToplevelInterface::States()); 0549 const quint32 serial1 = m_display->serial(); 0550 serverXdgToplevel->sendConfigure(QSize(20, 30), XdgToplevelInterface::States()); 0551 const quint32 serial2 = m_display->serial(); 0552 QVERIFY(serial1 != serial2); 0553 serverXdgToplevel->sendConfigure(QSize(30, 40), XdgToplevelInterface::States()); 0554 const quint32 serial3 = m_display->serial(); 0555 QVERIFY(serial1 != serial3); 0556 QVERIFY(serial2 != serial3); 0557 0558 QVERIFY(configureSpy.wait()); 0559 QCOMPARE(configureSpy.count(), 3); 0560 QCOMPARE(configureSpy.at(0).at(0).toSize(), QSize(10, 20)); 0561 QCOMPARE(configureSpy.at(0).at(1).value<KWayland::Client::XdgShellSurface::States>(), KWayland::Client::XdgShellSurface::States()); 0562 QCOMPARE(configureSpy.at(0).at(2).value<quint32>(), serial1); 0563 QCOMPARE(configureSpy.at(1).at(0).toSize(), QSize(20, 30)); 0564 QCOMPARE(configureSpy.at(1).at(1).value<KWayland::Client::XdgShellSurface::States>(), KWayland::Client::XdgShellSurface::States()); 0565 QCOMPARE(configureSpy.at(1).at(2).value<quint32>(), serial2); 0566 QCOMPARE(configureSpy.at(2).at(0).toSize(), QSize(30, 40)); 0567 QCOMPARE(configureSpy.at(2).at(1).value<KWayland::Client::XdgShellSurface::States>(), KWayland::Client::XdgShellSurface::States()); 0568 QCOMPARE(configureSpy.at(2).at(2).value<quint32>(), serial3); 0569 QCOMPARE(sizeChangedSpy.count(), 3); 0570 QCOMPARE(sizeChangedSpy.at(0).at(0).toSize(), QSize(10, 20)); 0571 QCOMPARE(sizeChangedSpy.at(1).at(0).toSize(), QSize(20, 30)); 0572 QCOMPARE(sizeChangedSpy.at(2).at(0).toSize(), QSize(30, 40)); 0573 QCOMPARE(xdgSurface->size(), QSize(30, 40)); 0574 0575 xdgSurface->ackConfigure(serial3); 0576 surface->commit(KWayland::Client::Surface::CommitFlag::None); 0577 QVERIFY(ackSpy.wait()); 0578 QCOMPARE(ackSpy.count(), 1); 0579 QCOMPARE(ackSpy.last().first().value<quint32>(), serial3); 0580 0581 // configure once more with a null size 0582 serverXdgToplevel->sendConfigure(QSize(0, 0), XdgToplevelInterface::States()); 0583 // should not change size 0584 QVERIFY(configureSpy.wait()); 0585 QCOMPARE(configureSpy.count(), 4); 0586 QCOMPARE(sizeChangedSpy.count(), 3); 0587 QCOMPARE(xdgSurface->size(), QSize(30, 40)); 0588 } 0589 0590 QTEST_GUILESS_MAIN(XdgShellTest) 0591 #include "test_xdg_shell.moc"