diff --git a/autotests/client/CMakeLists.txt b/autotests/client/CMakeLists.txt index 64cda34..c4329be 100644 --- a/autotests/client/CMakeLists.txt +++ b/autotests/client/CMakeLists.txt @@ -1,357 +1,357 @@ ######################################################## # Test WaylandConnectionThread ######################################################## set( testWaylandConnectionThread_SRCS test_wayland_connection_thread.cpp ) add_executable(testWaylandConnectionThread ${testWaylandConnectionThread_SRCS}) target_link_libraries( testWaylandConnectionThread Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server) add_test(kwayland-testWaylandConnectionThread testWaylandConnectionThread) ecm_mark_as_test(testWaylandConnectionThread) ######################################################## # Test WaylandRegistry ######################################################## set( testWaylandRegistry_SRCS test_wayland_registry.cpp ) add_executable(testWaylandRegistry ${testWaylandRegistry_SRCS}) target_link_libraries( testWaylandRegistry Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server) add_test(kwayland-testWaylandRegistry testWaylandRegistry) ecm_mark_as_test(testWaylandRegistry) ######################################################## # Test WaylandFullscreenShell ######################################################## if(Wayland_VERSION VERSION_GREATER "1.4.0") set( testWaylandFullscreenShell_SRCS test_wayland_fullscreen_shell.cpp ) add_executable(testWaylandFullscreenShell ${testWaylandFullscreenShell_SRCS}) target_link_libraries( testWaylandFullscreenShell Qt5::Test KF5::WaylandClient Wayland::Client) add_test(kwayland-testWaylandFullscreenShell testWaylandFullscreenShell) ecm_mark_as_test(testWaylandFullscreenShell) endif() ######################################################## # Test WaylandOutput ######################################################## set( testWaylandOutput_SRCS test_wayland_output.cpp ) add_executable(testWaylandOutput ${testWaylandOutput_SRCS}) target_link_libraries( testWaylandOutput Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server) add_test(kwayland-testWaylandOutput testWaylandOutput) ecm_mark_as_test(testWaylandOutput) ######################################################## # Test WaylandShell ######################################################## set( testWaylandShell_SRCS test_wayland_shell.cpp ) add_executable(testWaylandShell ${testWaylandShell_SRCS}) target_link_libraries( testWaylandShell Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server) add_test(kwayland-testWaylandShell testWaylandShell) ecm_mark_as_test(testWaylandShell) ######################################################## # Test WaylandSurface ######################################################## set( testWaylandSurface_SRCS test_wayland_surface.cpp ) add_executable(testWaylandSurface ${testWaylandSurface_SRCS}) target_link_libraries( testWaylandSurface Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server) add_test(kwayland-testWaylandSurface testWaylandSurface) ecm_mark_as_test(testWaylandSurface) ######################################################## # Test WaylandSeat ######################################################## if (HAVE_LINUX_INPUT_H) set( testWaylandSeat_SRCS test_wayland_seat.cpp ) add_executable(testWaylandSeat ${testWaylandSeat_SRCS}) target_link_libraries( testWaylandSeat Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server) add_test(kwayland-testWaylandSeat testWaylandSeat) ecm_mark_as_test(testWaylandSeat) endif() ######################################################## # Test ShmPool ######################################################## set( testShmPool_SRCS test_shm_pool.cpp ) add_executable(testShmPool ${testShmPool_SRCS}) target_link_libraries( testShmPool Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testShmPool testShmPool) ecm_mark_as_test(testShmPool) ######################################################## # Test KWin OutputManagement ######################################################## set( test_wayland_outputmanagement_SRCS test_wayland_outputmanagement.cpp ) add_executable(testWaylandOutputManagement ${test_wayland_outputmanagement_SRCS}) target_link_libraries( testWaylandOutputManagement Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testWaylandOutputManagement testWaylandOutputManagement) ecm_mark_as_test(testWaylandOutputManagement) ######################################################## # Test KWin OutputDevice ######################################################## set( test_wayland_outputdevice_SRCS test_wayland_outputdevice.cpp ) add_executable(testWaylandOutputDevice ${test_wayland_outputdevice_SRCS}) target_link_libraries( testWaylandOutputDevice Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testWaylandOutputDevice testWaylandOutputDevice) ecm_mark_as_test(testWaylandOutputDevice) ######################################################## # Test Compositor ######################################################## set( testCompositor_SRCS test_compositor.cpp ) add_executable(testCompositor ${testCompositor_SRCS}) target_link_libraries( testCompositor Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testCompositor testCompositor) ecm_mark_as_test(testCompositor) ######################################################## # Test SubCompositor ######################################################## set( testSubCompositor_SRCS test_wayland_subcompositor.cpp ) add_executable(testSubCompositor ${testSubCompositor_SRCS}) target_link_libraries( testSubCompositor Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testSubCompositor testSubCompositor) ecm_mark_as_test(testSubCompositor) ######################################################## # Test SubSurface ######################################################## set( testSubSurface_SRCS test_wayland_subsurface.cpp ) add_executable(testSubSurface ${testSubSurface_SRCS}) target_link_libraries( testSubSurface Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testSubSurface testSubSurface) ecm_mark_as_test(testSubSurface) ######################################################## # Test Region ######################################################## set( testRegion_SRCS test_wayland_region.cpp ) add_executable(testRegion ${testRegion_SRCS}) target_link_libraries( testRegion Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testRegion testRegion) ecm_mark_as_test(testRegion) ######################################################## # Test Blur ######################################################## set( testBlur_SRCS test_wayland_blur.cpp ) add_executable(testBlur ${testBlur_SRCS}) target_link_libraries( testBlur Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testBlur testBlur) ecm_mark_as_test(testBlur) ######################################################## # Test Contrast ######################################################## set( testContrast_SRCS test_wayland_contrast.cpp ) add_executable(testContrast ${testContrast_SRCS}) target_link_libraries( testContrast Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testContrast testContrast) ecm_mark_as_test(testContrast) ######################################################## # Test Slide ######################################################## set( testSlide_SRCS test_wayland_slide.cpp ) add_executable(testSlide ${testSlide_SRCS}) target_link_libraries( testSlide Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testSlide testSlide) ecm_mark_as_test(testSlide) ######################################################## # Test Window Management ######################################################## set( testWindowmanagement_SRCS test_wayland_windowmanagement.cpp ) add_executable(testWindowmanagement ${testWindowmanagement_SRCS}) target_link_libraries( testWindowmanagement Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testWindowmanagement testWindowmanagement) ecm_mark_as_test(testWindowmanagement) ######################################################## # Test DataSource ######################################################## set( testDataSource_SRCS test_datasource.cpp ) add_executable(testDataSource ${testDataSource_SRCS}) target_link_libraries( testDataSource Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testDataSource testDataSource) ecm_mark_as_test(testDataSource) ######################################################## # Test DataDevice ######################################################## set( testDataDevice_SRCS test_datadevice.cpp ) add_executable(testDataDevice ${testDataDevice_SRCS}) target_link_libraries( testDataDevice Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testDataDevice testDataDevice) ecm_mark_as_test(testDataDevice) ######################################################## # Test ServerSideDecoration ######################################################## set( testServerSideDecoration_SRCS test_server_side_decoration.cpp ) add_executable(testServerSideDecoration ${testServerSideDecoration_SRCS}) target_link_libraries( testServerSideDecoration Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testServerSideDecoration testServerSideDecoration) ecm_mark_as_test(testServerSideDecoration) ######################################################## # Test Drag'N'Drop ######################################################## set( testDragAndDrop_SRCS test_drag_drop.cpp ) add_executable(testDragAndDrop ${testDragAndDrop_SRCS}) target_link_libraries( testDragAndDrop Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testDragAndDrop testDragAndDrop) ecm_mark_as_test(testDragAndDrop) ######################################################## # Test PlasmaShell ######################################################## set( testPlasmaShell_SRCS test_plasmashell.cpp ) add_executable(testPlasmaShell ${testPlasmaShell_SRCS}) target_link_libraries( testPlasmaShell Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testPlasmaShell testPlasmaShell) ecm_mark_as_test(testPlasmaShell) ######################################################## # Test Idle ######################################################## set( testIdle_SRCS test_idle.cpp ) add_executable(testIdle ${testIdle_SRCS}) target_link_libraries( testIdle Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testIdle testIdle) ecm_mark_as_test(testIdle) ######################################################## # Test Shadow ######################################################## set( testShadow_SRCS test_shadow.cpp ) add_executable(testShadow ${testShadow_SRCS}) target_link_libraries( testShadow Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testShadow testShadow) ecm_mark_as_test(testShadow) ######################################################## # Test FakeInput ######################################################## if (HAVE_LINUX_INPUT_H) set( testFakeInput_SRCS test_fake_input.cpp ) add_executable(testFakeInput ${testFakeInput_SRCS}) target_link_libraries( testFakeInput Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testFakeInput testFakeInput) ecm_mark_as_test(testFakeInput) endif() ######################################################## # Test PlasmaWindowModel ######################################################## if (HAVE_LINUX_INPUT_H) set( testPlasmaWindowModel_SRCS test_plasma_window_model.cpp ) add_executable(testPlasmaWindowModel ${testPlasmaWindowModel_SRCS}) target_link_libraries( testPlasmaWindowModel Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testPlasmaWindowModel testPlasmaWindowModel) ecm_mark_as_test(testPlasmaWindowModel) endif() ######################################################## # Test TextInput ######################################################## set( testTextInput_SRCS test_text_input.cpp ) add_executable(testTextInput ${testTextInput_SRCS}) target_link_libraries( testTextInput Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer) add_test(kwayland-testTextInput testTextInput) ecm_mark_as_test(testTextInput) ######################################################## # Test Error ######################################################## set( testError_SRCS test_error.cpp ) add_executable(testError ${testError_SRCS}) target_link_libraries( testError Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testError testError) ecm_mark_as_test(testError) ######################################################## # Test Selection ######################################################## set( testSelection_SRCS test_selection.cpp ) add_executable(testSelection ${testSelection_SRCS}) target_link_libraries( testSelection Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client) add_test(kwayland-testSelection testSelection) ecm_mark_as_test(testSelection) ######################################################## # Test XdgShellV5 ######################################################## set( testXdgShellV5_SRCS - test_xdg_shell.cpp + test_xdg_shell_v5.cpp ) add_executable(testXdgShellV5 ${testXdgShellV5_SRCS}) target_link_libraries( testXdgShellV5 Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client) add_test(kwayland-testXdgShellV5 testXdgShellV5) ecm_mark_as_test(testXdgShellV5) ######################################################## # Test Pointer Constraints ######################################################## add_executable(testPointerConstraints test_pointer_constraints.cpp) target_link_libraries( testPointerConstraints Qt5::Test Qt5::Gui KF5::WaylandServer KF5::WaylandClient Wayland::Client) add_test(kwayland-testPointerConstraints testPointerConstraints) ecm_mark_as_test(testPointerConstraints) diff --git a/autotests/client/test_xdg_shell.cpp b/autotests/client/test_xdg_shell.cpp index c62630f..32bb6b6 100644 --- a/autotests/client/test_xdg_shell.cpp +++ b/autotests/client/test_xdg_shell.cpp @@ -1,649 +1,658 @@ /******************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ // Qt #include // client #include "../../src/client/xdgshell.h" #include "../../src/client/connection_thread.h" #include "../../src/client/compositor.h" #include "../../src/client/event_queue.h" #include "../../src/client/registry.h" #include "../../src/client/output.h" #include "../../src/client/seat.h" #include "../../src/client/shm_pool.h" #include "../../src/client/surface.h" // server #include "../../src/server/display.h" #include "../../src/server/compositor_interface.h" #include "../../src/server/output_interface.h" #include "../../src/server/seat_interface.h" #include "../../src/server/surface_interface.h" #include "../../src/server/xdgshell_interface.h" using namespace KWayland::Client; using namespace KWayland::Server; Q_DECLARE_METATYPE(Qt::MouseButton) class XdgShellTest : public QObject { Q_OBJECT + +protected: + XdgShellTest(XdgShellInterfaceVersion version); private Q_SLOTS: void init(); void cleanup(); void testCreateSurface(); void testTitle(); void testWindowClass(); void testMaximize(); void testMinimize(); void testFullscreen(); void testShowWindowMenu(); void testMove(); void testResize_data(); void testResize(); void testTransient(); void testClose(); void testConfigureStates_data(); void testConfigureStates(); void testConfigureMultipleAcks(); void testPopup(); private: Display *m_display = nullptr; CompositorInterface *m_compositorInterface = nullptr; OutputInterface *m_o1Interface = nullptr; OutputInterface *m_o2Interface = nullptr; SeatInterface *m_seatInterface = nullptr; XdgShellInterface *m_xdgShellInterface = nullptr; ConnectionThread *m_connection = nullptr; QThread *m_thread = nullptr; EventQueue *m_queue = nullptr; Compositor *m_compositor = nullptr; ShmPool *m_shmPool = nullptr; XdgShell *m_xdgShell = nullptr; Output *m_output1 = nullptr; Output *m_output2 = nullptr; Seat *m_seat = nullptr; + + XdgShellInterfaceVersion m_version; }; + +XdgShellTest::XdgShellTest(XdgShellInterfaceVersion version): + m_version(version) +{} + static const QString s_socketName = QStringLiteral("kwayland-test-xdg_shell-0"); void XdgShellTest::init() { delete m_display; m_display = new Display(this); m_display->setSocketName(s_socketName); m_display->start(); QVERIFY(m_display->isRunning()); m_display->createShm(); m_o1Interface = m_display->createOutput(m_display); m_o1Interface->addMode(QSize(1024, 768)); m_o1Interface->create(); m_o2Interface = m_display->createOutput(m_display); m_o2Interface->addMode(QSize(1024, 768)); m_o2Interface->create(); m_seatInterface = m_display->createSeat(m_display); m_seatInterface->setHasKeyboard(true); m_seatInterface->setHasPointer(true); m_seatInterface->setHasTouch(true); m_seatInterface->create(); m_compositorInterface = m_display->createCompositor(m_display); m_compositorInterface->create(); - m_xdgShellInterface = m_display->createXdgShell(XdgShellInterfaceVersion::UnstableV5, m_display); - QCOMPARE(m_xdgShellInterface->interfaceVersion(), XdgShellInterfaceVersion::UnstableV5); + m_xdgShellInterface = m_display->createXdgShell(m_version, m_display); + QCOMPARE(m_xdgShellInterface->interfaceVersion(), m_version); m_xdgShellInterface->create(); // setup connection m_connection = new KWayland::Client::ConnectionThread; QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); QVERIFY(connectedSpy.isValid()); m_connection->setSocketName(s_socketName); m_thread = new QThread(this); m_connection->moveToThread(m_thread); m_thread->start(); m_connection->initConnection(); QVERIFY(connectedSpy.wait()); m_queue = new EventQueue(this); m_queue->setup(m_connection); Registry registry; QSignalSpy interfacesAnnouncedSpy(®istry, &Registry::interfacesAnnounced); QVERIFY(interfacesAnnouncedSpy.isValid()); QSignalSpy interfaceAnnouncedSpy(®istry, &Registry::interfaceAnnounced); QVERIFY(interfaceAnnouncedSpy.isValid()); QSignalSpy outputAnnouncedSpy(®istry, &Registry::outputAnnounced); QVERIFY(outputAnnouncedSpy.isValid()); QSignalSpy xdgShellAnnouncedSpy(®istry, &Registry::xdgShellUnstableV5Announced); QVERIFY(xdgShellAnnouncedSpy.isValid()); registry.setEventQueue(m_queue); registry.create(m_connection); QVERIFY(registry.isValid()); registry.setup(); QVERIFY(interfacesAnnouncedSpy.wait()); QCOMPARE(outputAnnouncedSpy.count(), 2); m_output1 = registry.createOutput(outputAnnouncedSpy.first().at(0).value(), outputAnnouncedSpy.first().at(1).value(), this); m_output2 = registry.createOutput(outputAnnouncedSpy.last().at(0).value(), outputAnnouncedSpy.last().at(1).value(), this); m_shmPool = registry.createShmPool(registry.interface(Registry::Interface::Shm).name, registry.interface(Registry::Interface::Shm).version, this); QVERIFY(m_shmPool); QVERIFY(m_shmPool->isValid()); m_compositor = registry.createCompositor(registry.interface(Registry::Interface::Compositor).name, registry.interface(Registry::Interface::Compositor).version, this); QVERIFY(m_compositor); QVERIFY(m_compositor->isValid()); m_seat = registry.createSeat(registry.interface(Registry::Interface::Seat).name, registry.interface(Registry::Interface::Seat).version, this); QVERIFY(m_seat); QVERIFY(m_seat->isValid()); QCOMPARE(xdgShellAnnouncedSpy.count(), 1); m_xdgShell = registry.createXdgShell(registry.interface(Registry::Interface::XdgShellUnstableV5).name, registry.interface(Registry::Interface::XdgShellUnstableV5).version, this); QVERIFY(m_xdgShell); QVERIFY(m_xdgShell->isValid()); } void XdgShellTest::cleanup() { #define CLEANUP(variable) \ if (variable) { \ delete variable; \ variable = nullptr; \ } CLEANUP(m_xdgShell) CLEANUP(m_compositor) CLEANUP(m_shmPool) CLEANUP(m_output1) CLEANUP(m_output2) CLEANUP(m_seat) CLEANUP(m_queue) if (m_connection) { m_connection->deleteLater(); m_connection = nullptr; } if (m_thread) { m_thread->quit(); m_thread->wait(); delete m_thread; m_thread = nullptr; } CLEANUP(m_compositorInterface) CLEANUP(m_xdgShellInterface) CLEANUP(m_o1Interface); CLEANUP(m_o2Interface); CLEANUP(m_seatInterface); CLEANUP(m_display) #undef CLEANUP } void XdgShellTest::testCreateSurface() { // this test verifies that we can create a surface // first created the signal spies for the server QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); QVERIFY(xdgSurfaceCreatedSpy.isValid()); // create surface QScopedPointer surface(m_compositor->createSurface()); QVERIFY(!surface.isNull()); QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); // create shell surface QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); QVERIFY(!xdgSurface.isNull()); QVERIFY(xdgSurfaceCreatedSpy.wait()); // verify base things auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); QVERIFY(serverXdgSurface); QCOMPARE(serverXdgSurface->isConfigurePending(), false); QCOMPARE(serverXdgSurface->title(), QString()); QCOMPARE(serverXdgSurface->windowClass(), QByteArray()); QCOMPARE(serverXdgSurface->isTransient(), false); QCOMPARE(serverXdgSurface->transientFor(), QPointer()); QCOMPARE(serverXdgSurface->surface(), serverSurface); // now let's destroy it QSignalSpy destroyedSpy(serverXdgSurface, &QObject::destroyed); QVERIFY(destroyedSpy.isValid()); xdgSurface.reset(); QVERIFY(destroyedSpy.wait()); } #define SURFACE \ QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); \ QVERIFY(xdgSurfaceCreatedSpy.isValid()); \ QScopedPointer surface(m_compositor->createSurface()); \ QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); \ QCOMPARE(xdgSurface->size(), QSize()); \ QVERIFY(xdgSurfaceCreatedSpy.wait()); \ auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); \ QVERIFY(serverXdgSurface); void XdgShellTest::testTitle() { // this test verifies that we can change the title of a shell surface // first create surface SURFACE // should not have a title yet QCOMPARE(serverXdgSurface->title(), QString()); // lets' change the title QSignalSpy titleChangedSpy(serverXdgSurface, &XdgShellSurfaceInterface::titleChanged); QVERIFY(titleChangedSpy.isValid()); xdgSurface->setTitle(QStringLiteral("foo")); QVERIFY(titleChangedSpy.wait()); QCOMPARE(titleChangedSpy.count(), 1); QCOMPARE(titleChangedSpy.first().first().toString(), QStringLiteral("foo")); QCOMPARE(serverXdgSurface->title(), QStringLiteral("foo")); } void XdgShellTest::testWindowClass() { // this test verifies that we can change the window class/app id of a shell surface // first create surface SURFACE // should not have a window class yet QCOMPARE(serverXdgSurface->windowClass(), QByteArray()); // let's change the window class QSignalSpy windowClassChanged(serverXdgSurface, &XdgShellSurfaceInterface::windowClassChanged); QVERIFY(windowClassChanged.isValid()); xdgSurface->setAppId(QByteArrayLiteral("org.kde.xdgsurfacetest")); QVERIFY(windowClassChanged.wait()); QCOMPARE(windowClassChanged.count(), 1); QCOMPARE(windowClassChanged.first().first().toByteArray(), QByteArrayLiteral("org.kde.xdgsurfacetest")); QCOMPARE(serverXdgSurface->windowClass(), QByteArrayLiteral("org.kde.xdgsurfacetest")); } void XdgShellTest::testMaximize() { // this test verifies that the maximize/unmaximize calls work SURFACE QSignalSpy maximizeRequestedSpy(serverXdgSurface, &XdgShellSurfaceInterface::maximizedChanged); QVERIFY(maximizeRequestedSpy.isValid()); xdgSurface->setMaximized(true); QVERIFY(maximizeRequestedSpy.wait()); QCOMPARE(maximizeRequestedSpy.count(), 1); QCOMPARE(maximizeRequestedSpy.last().first().toBool(), true); xdgSurface->setMaximized(false); QVERIFY(maximizeRequestedSpy.wait()); QCOMPARE(maximizeRequestedSpy.count(), 2); QCOMPARE(maximizeRequestedSpy.last().first().toBool(), false); } void XdgShellTest::testMinimize() { // this test verifies that the minimize request is delivered SURFACE QSignalSpy minimizeRequestedSpy(serverXdgSurface, &XdgShellSurfaceInterface::minimizeRequested); QVERIFY(minimizeRequestedSpy.isValid()); xdgSurface->requestMinimize(); QVERIFY(minimizeRequestedSpy.wait()); QCOMPARE(minimizeRequestedSpy.count(), 1); } void XdgShellTest::testFullscreen() { qRegisterMetaType(); // this test verifies going to/from fullscreen QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); QVERIFY(xdgSurfaceCreatedSpy.isValid()); QScopedPointer surface(m_compositor->createSurface()); QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); QVERIFY(xdgSurfaceCreatedSpy.wait()); auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); QVERIFY(serverXdgSurface); QSignalSpy fullscreenSpy(serverXdgSurface, &XdgShellSurfaceInterface::fullscreenChanged); QVERIFY(fullscreenSpy.isValid()); // without an output xdgSurface->setFullscreen(true, nullptr); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 1); QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); QVERIFY(!fullscreenSpy.last().at(1).value()); // unset xdgSurface->setFullscreen(false); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 2); QCOMPARE(fullscreenSpy.last().at(0).toBool(), false); QVERIFY(!fullscreenSpy.last().at(1).value()); // with outputs xdgSurface->setFullscreen(true, m_output1); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 3); QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); QCOMPARE(fullscreenSpy.last().at(1).value(), m_o1Interface); // now other output xdgSurface->setFullscreen(true, m_output2); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 4); QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); QCOMPARE(fullscreenSpy.last().at(1).value(), m_o2Interface); } void XdgShellTest::testShowWindowMenu() { qRegisterMetaType(); // this test verifies that the show window menu request works SURFACE QSignalSpy windowMenuSpy(serverXdgSurface, &XdgShellSurfaceInterface::windowMenuRequested); QVERIFY(windowMenuSpy.isValid()); // TODO: the serial needs to be a proper one xdgSurface->requestShowWindowMenu(m_seat, 20, QPoint(30, 40)); QVERIFY(windowMenuSpy.wait()); QCOMPARE(windowMenuSpy.count(), 1); QCOMPARE(windowMenuSpy.first().at(0).value(), m_seatInterface); QCOMPARE(windowMenuSpy.first().at(1).value(), 20u); QCOMPARE(windowMenuSpy.first().at(2).toPoint(), QPoint(30, 40)); } void XdgShellTest::testMove() { qRegisterMetaType(); // this test verifies that the move request works SURFACE QSignalSpy moveSpy(serverXdgSurface, &XdgShellSurfaceInterface::moveRequested); QVERIFY(moveSpy.isValid()); // TODO: the serial needs to be a proper one xdgSurface->requestMove(m_seat, 50); QVERIFY(moveSpy.wait()); QCOMPARE(moveSpy.count(), 1); QCOMPARE(moveSpy.first().at(0).value(), m_seatInterface); QCOMPARE(moveSpy.first().at(1).value(), 50u); } void XdgShellTest::testResize_data() { QTest::addColumn("edges"); QTest::newRow("none") << Qt::Edges(); QTest::newRow("top") << Qt::Edges(Qt::TopEdge); QTest::newRow("bottom") << Qt::Edges(Qt::BottomEdge); QTest::newRow("left") << Qt::Edges(Qt::LeftEdge); QTest::newRow("top left") << Qt::Edges(Qt::TopEdge | Qt::LeftEdge); QTest::newRow("bottom left") << Qt::Edges(Qt::BottomEdge | Qt::LeftEdge); QTest::newRow("right") << Qt::Edges(Qt::RightEdge); QTest::newRow("top right") << Qt::Edges(Qt::TopEdge | Qt::RightEdge); QTest::newRow("bottom right") << Qt::Edges(Qt::BottomEdge | Qt::RightEdge); } void XdgShellTest::testResize() { qRegisterMetaType(); // this test verifies that the resize request works SURFACE QSignalSpy resizeSpy(serverXdgSurface, &XdgShellSurfaceInterface::resizeRequested); QVERIFY(resizeSpy.isValid()); // TODO: the serial needs to be a proper one QFETCH(Qt::Edges, edges); xdgSurface->requestResize(m_seat, 60, edges); QVERIFY(resizeSpy.wait()); QCOMPARE(resizeSpy.count(), 1); QCOMPARE(resizeSpy.first().at(0).value(), m_seatInterface); QCOMPARE(resizeSpy.first().at(1).value(), 60u); QCOMPARE(resizeSpy.first().at(2).value(), edges); } void XdgShellTest::testTransient() { // this test verifies that setting the transient for works SURFACE QScopedPointer surface2(m_compositor->createSurface()); QScopedPointer xdgSurface2(m_xdgShell->createSurface(surface2.data())); QVERIFY(xdgSurfaceCreatedSpy.wait()); auto serverXdgSurface2 = xdgSurfaceCreatedSpy.last().first().value(); QVERIFY(serverXdgSurface2); QVERIFY(!serverXdgSurface->isTransient()); QVERIFY(!serverXdgSurface2->isTransient()); // now make xdsgSurface2 a transient for xdgSurface QSignalSpy transientForSpy(serverXdgSurface2, &XdgShellSurfaceInterface::transientForChanged); QVERIFY(transientForSpy.isValid()); xdgSurface2->setTransientFor(xdgSurface.data()); QVERIFY(transientForSpy.wait()); QCOMPARE(transientForSpy.count(), 1); QVERIFY(serverXdgSurface2->isTransient()); QCOMPARE(serverXdgSurface2->transientFor().data(), serverXdgSurface); QVERIFY(!serverXdgSurface->isTransient()); // unset the transient for xdgSurface2->setTransientFor(nullptr); QVERIFY(transientForSpy.wait()); QCOMPARE(transientForSpy.count(), 2); QVERIFY(!serverXdgSurface2->isTransient()); QVERIFY(serverXdgSurface2->transientFor().isNull()); QVERIFY(!serverXdgSurface->isTransient()); } void XdgShellTest::testClose() { // this test verifies that a close request is sent to the client SURFACE QSignalSpy closeSpy(xdgSurface.data(), &XdgShellSurface::closeRequested); QVERIFY(closeSpy.isValid()); serverXdgSurface->close(); QVERIFY(closeSpy.wait()); QCOMPARE(closeSpy.count(), 1); QSignalSpy destroyedSpy(serverXdgSurface, &XdgShellSurfaceInterface::destroyed); QVERIFY(destroyedSpy.isValid()); xdgSurface.reset(); QVERIFY(destroyedSpy.wait()); } void XdgShellTest::testConfigureStates_data() { QTest::addColumn("serverStates"); QTest::addColumn("clientStates"); const auto sa = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Activated); const auto sm = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Maximized); const auto sf = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Fullscreen); const auto sr = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Resizing); const auto ca = XdgShellSurface::States(XdgShellSurface::State::Activated); const auto cm = XdgShellSurface::States(XdgShellSurface::State::Maximized); const auto cf = XdgShellSurface::States(XdgShellSurface::State::Fullscreen); const auto cr = XdgShellSurface::States(XdgShellSurface::State::Resizing); QTest::newRow("none") << XdgShellSurfaceInterface::States() << XdgShellSurface::States(); QTest::newRow("Active") << sa << ca; QTest::newRow("Maximize") << sm << cm; QTest::newRow("Fullscreen") << sf << cf; QTest::newRow("Resizing") << sr << cr; QTest::newRow("Active/Maximize") << (sa | sm) << (ca | cm); QTest::newRow("Active/Fullscreen") << (sa | sf) << (ca | cf); QTest::newRow("Active/Resizing") << (sa | sr) << (ca | cr); QTest::newRow("Maximize/Fullscreen") << (sm | sf) << (cm | cf); QTest::newRow("Maximize/Resizing") << (sm | sr) << (cm | cr); QTest::newRow("Fullscreen/Resizing") << (sf | sr) << (cf | cr); QTest::newRow("Active/Maximize/Fullscreen") << (sa | sm | sf) << (ca | cm | cf); QTest::newRow("Active/Maximize/Resizing") << (sa | sm | sr) << (ca | cm | cr); QTest::newRow("Maximize/Fullscreen|Resizing") << (sm | sf | sr) << (cm | cf | cr); QTest::newRow("Active/Maximize/Fullscreen/Resizing") << (sa | sm | sf | sr) << (ca | cm | cf | cr); } void XdgShellTest::testConfigureStates() { qRegisterMetaType(); // this test verifies that configure states works SURFACE QSignalSpy configureSpy(xdgSurface.data(), &XdgShellSurface::configureRequested); QVERIFY(configureSpy.isValid()); QFETCH(XdgShellSurfaceInterface::States, serverStates); serverXdgSurface->configure(serverStates); QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 1); QCOMPARE(configureSpy.first().at(0).toSize(), QSize(0, 0)); QTEST(configureSpy.first().at(1).value(), "clientStates"); QCOMPARE(configureSpy.first().at(2).value(), m_display->serial()); QSignalSpy ackSpy(serverXdgSurface, &XdgShellSurfaceInterface::configureAcknowledged); QVERIFY(ackSpy.isValid()); xdgSurface->ackConfigure(configureSpy.first().at(2).value()); QVERIFY(ackSpy.wait()); QCOMPARE(ackSpy.count(), 1); QCOMPARE(ackSpy.first().first().value(), configureSpy.first().at(2).value()); } void XdgShellTest::testConfigureMultipleAcks() { qRegisterMetaType(); // this test verifies that with multiple configure requests the last acknowledged one acknowledges all SURFACE QSignalSpy configureSpy(xdgSurface.data(), &XdgShellSurface::configureRequested); QVERIFY(configureSpy.isValid()); QSignalSpy sizeChangedSpy(xdgSurface.data(), &XdgShellSurface::sizeChanged); QVERIFY(sizeChangedSpy.isValid()); QSignalSpy ackSpy(serverXdgSurface, &XdgShellSurfaceInterface::configureAcknowledged); QVERIFY(ackSpy.isValid()); serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(10, 20)); const quint32 serial1 = m_display->serial(); serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(20, 30)); const quint32 serial2 = m_display->serial(); QVERIFY(serial1 != serial2); serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(30, 40)); const quint32 serial3 = m_display->serial(); QVERIFY(serial1 != serial3); QVERIFY(serial2 != serial3); QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 3); QCOMPARE(configureSpy.at(0).at(0).toSize(), QSize(10, 20)); QCOMPARE(configureSpy.at(0).at(1).value(), XdgShellSurface::States()); QCOMPARE(configureSpy.at(0).at(2).value(), serial1); QCOMPARE(configureSpy.at(1).at(0).toSize(), QSize(20, 30)); QCOMPARE(configureSpy.at(1).at(1).value(), XdgShellSurface::States()); QCOMPARE(configureSpy.at(1).at(2).value(), serial2); QCOMPARE(configureSpy.at(2).at(0).toSize(), QSize(30, 40)); QCOMPARE(configureSpy.at(2).at(1).value(), XdgShellSurface::States()); QCOMPARE(configureSpy.at(2).at(2).value(), serial3); QCOMPARE(sizeChangedSpy.count(), 3); QCOMPARE(sizeChangedSpy.at(0).at(0).toSize(), QSize(10, 20)); QCOMPARE(sizeChangedSpy.at(1).at(0).toSize(), QSize(20, 30)); QCOMPARE(sizeChangedSpy.at(2).at(0).toSize(), QSize(30, 40)); QCOMPARE(xdgSurface->size(), QSize(30, 40)); xdgSurface->ackConfigure(serial3); QVERIFY(ackSpy.wait()); QCOMPARE(ackSpy.count(), 3); QCOMPARE(ackSpy.at(0).first().value(), serial1); QCOMPARE(ackSpy.at(1).first().value(), serial2); QCOMPARE(ackSpy.at(2).first().value(), serial3); // configure once more with a null size serverXdgSurface->configure(XdgShellSurfaceInterface::States()); // should not change size QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 4); QCOMPARE(sizeChangedSpy.count(), 3); QCOMPARE(xdgSurface->size(), QSize(30, 40)); } void XdgShellTest::testPopup() { // this test verifies that the creation of popups works correctly SURFACE QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); QSignalSpy xdgPopupSpy(m_xdgShellInterface, &XdgShellInterface::popupCreated); QVERIFY(xdgPopupSpy.isValid()); QScopedPointer popupSurface(m_compositor->createSurface()); QVERIFY(surfaceCreatedSpy.wait()); // TODO: proper serial QScopedPointer xdgPopup(m_xdgShell->createPopup(popupSurface.data(), surface.data(), m_seat, 120, QPoint(10, 20))); QVERIFY(xdgPopupSpy.wait()); QCOMPARE(xdgPopupSpy.count(), 1); QCOMPARE(xdgPopupSpy.first().at(1).value(), m_seatInterface); QCOMPARE(xdgPopupSpy.first().at(2).value(), 120u); auto serverXdgPopup = xdgPopupSpy.first().first().value(); QVERIFY(serverXdgPopup); QCOMPARE(serverXdgPopup->surface(), surfaceCreatedSpy.first().first().value()); QCOMPARE(serverXdgPopup->transientFor().data(), serverXdgSurface->surface()); QCOMPARE(serverXdgPopup->transientOffset(), QPoint(10, 20)); // now also a popup for the popup QScopedPointer popup2Surface(m_compositor->createSurface()); QScopedPointer xdgPopup2(m_xdgShell->createPopup(popup2Surface.data(), popupSurface.data(), m_seat, 121, QPoint(5, 7))); QVERIFY(xdgPopupSpy.wait()); QCOMPARE(xdgPopupSpy.count(), 2); QCOMPARE(xdgPopupSpy.last().at(1).value(), m_seatInterface); QCOMPARE(xdgPopupSpy.last().at(2).value(), 121u); auto serverXdgPopup2 = xdgPopupSpy.last().first().value(); QVERIFY(serverXdgPopup2); QCOMPARE(serverXdgPopup2->surface(), surfaceCreatedSpy.last().first().value()); QCOMPARE(serverXdgPopup2->transientFor().data(), serverXdgPopup->surface()); QCOMPARE(serverXdgPopup2->transientOffset(), QPoint(5, 7)); QSignalSpy popup2DoneSpy(xdgPopup2.data(), &XdgShellPopup::popupDone); QVERIFY(popup2DoneSpy.isValid()); serverXdgPopup2->popupDone(); QVERIFY(popup2DoneSpy.wait()); // TODO: test that this sends also the done to all parents } -QTEST_GUILESS_MAIN(XdgShellTest) #include "test_xdg_shell.moc" diff --git a/autotests/client/test_xdg_shell_v5.cpp b/autotests/client/test_xdg_shell_v5.cpp new file mode 100644 index 0000000..ab865ea --- /dev/null +++ b/autotests/client/test_xdg_shell_v5.cpp @@ -0,0 +1,13 @@ +#include "test_xdg_shell.cpp" + +class XdgShellTestV5 : public XdgShellTest { + Q_OBJECT +public: + XdgShellTestV5() : + XdgShellTest(KWayland::Server::XdgShellInterfaceVersion::UnstableV5) {} +}; + +QTEST_GUILESS_MAIN(XdgShellTestV5) + +#include "test_xdg_shell_v5.moc" +