/* KWin - the KDE window manager This file is part of the KDE project. SPDX-FileCopyrightText: 2017 Martin Flöser SPDX-License-Identifier: GPL-2.0-or-later */ #include "kwin_wayland_test.h" #include "core/outputbackend.h" #include "main.h" #include "virtualdesktops.h" #include "wayland_server.h" #include "window.h" #include "workspace.h" #include using namespace KWin; static const QString s_socketName = QStringLiteral("wayland_test_kwin_virtualdesktop-0"); class VirtualDesktopTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase(); void init(); void cleanup(); void testNetCurrentDesktop(); void testLastDesktopRemoved(); void testWindowOnMultipleDesktops(); void testRemoveDesktopWithWindow(); }; void VirtualDesktopTest::initTestCase() { qRegisterMetaType(); QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); QVERIFY(waylandServer()->init(s_socketName)); QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector, QVector() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024))); kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)); qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1"); qputenv("XKB_DEFAULT_RULES", "evdev"); kwinApp()->start(); QVERIFY(applicationStartedSpy.wait()); if (kwinApp()->x11Connection()) { // verify the current desktop x11 property on startup, see BUG: 391034 Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP"); QVERIFY(currentDesktopAtom.isValid()); Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); bool ok = true; QCOMPARE(currentDesktop.value(0, &ok), 0); QVERIFY(ok); } } void VirtualDesktopTest::init() { QVERIFY(Test::setupWaylandConnection()); workspace()->setActiveOutput(QPoint(640, 512)); VirtualDesktopManager::self()->setCount(1); } void VirtualDesktopTest::cleanup() { Test::destroyWaylandConnection(); } void VirtualDesktopTest::testNetCurrentDesktop() { if (!kwinApp()->x11Connection()) { QSKIP("Skipped on Wayland only"); } QCOMPARE(VirtualDesktopManager::self()->count(), 1u); VirtualDesktopManager::self()->setCount(4); QCOMPARE(VirtualDesktopManager::self()->count(), 4u); Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP"); QVERIFY(currentDesktopAtom.isValid()); Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); bool ok = true; QCOMPARE(currentDesktop.value(0, &ok), 0); QVERIFY(ok); // go to desktop 2 VirtualDesktopManager::self()->setCurrent(2); currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); QCOMPARE(currentDesktop.value(0, &ok), 1); QVERIFY(ok); // go to desktop 3 VirtualDesktopManager::self()->setCurrent(3); currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); QCOMPARE(currentDesktop.value(0, &ok), 2); QVERIFY(ok); // go to desktop 4 VirtualDesktopManager::self()->setCurrent(4); currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); QCOMPARE(currentDesktop.value(0, &ok), 3); QVERIFY(ok); // and back to first VirtualDesktopManager::self()->setCurrent(1); currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); QCOMPARE(currentDesktop.value(0, &ok), 0); QVERIFY(ok); } void VirtualDesktopTest::testLastDesktopRemoved() { // first create a new desktop QCOMPARE(VirtualDesktopManager::self()->count(), 1u); VirtualDesktopManager::self()->setCount(2); QCOMPARE(VirtualDesktopManager::self()->count(), 2u); // switch to last desktop VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last()); QCOMPARE(VirtualDesktopManager::self()->current(), 2u); // now create a window on this desktop std::unique_ptr surface(Test::createSurface()); std::unique_ptr shellSurface(Test::createXdgToplevelSurface(surface.get())); auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); QVERIFY(window); QCOMPARE(window->desktop(), 2); QSignalSpy desktopPresenceChangedSpy(window, &Window::desktopPresenceChanged); QCOMPARE(window->desktops().count(), 1u); QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first()); // and remove last desktop VirtualDesktopManager::self()->setCount(1); QCOMPARE(VirtualDesktopManager::self()->count(), 1u); // now the window should be moved as well QTRY_COMPARE(desktopPresenceChangedSpy.count(), 1); QCOMPARE(window->desktop(), 1); QCOMPARE(window->desktops().count(), 1u); QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first()); } void VirtualDesktopTest::testWindowOnMultipleDesktops() { // first create two new desktops QCOMPARE(VirtualDesktopManager::self()->count(), 1u); VirtualDesktopManager::self()->setCount(3); QCOMPARE(VirtualDesktopManager::self()->count(), 3u); // switch to last desktop VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last()); QCOMPARE(VirtualDesktopManager::self()->current(), 3u); // now create a window on this desktop std::unique_ptr surface(Test::createSurface()); std::unique_ptr shellSurface(Test::createXdgToplevelSurface(surface.get())); auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); QVERIFY(window); QCOMPARE(window->desktop(), 3u); QSignalSpy desktopPresenceChangedSpy(window, &Window::desktopPresenceChanged); QCOMPARE(window->desktops().count(), 1u); QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first()); // Set the window on desktop 2 as well window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(2)); QCOMPARE(window->desktops().count(), 2u); QCOMPARE(VirtualDesktopManager::self()->desktops()[2], window->desktops()[0]); QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[1]); QVERIFY(window->isOnDesktop(2)); QVERIFY(window->isOnDesktop(3)); // leave desktop 3 window->leaveDesktop(VirtualDesktopManager::self()->desktopForX11Id(3)); QCOMPARE(window->desktops().count(), 1u); // leave desktop 2 window->leaveDesktop(VirtualDesktopManager::self()->desktopForX11Id(2)); QCOMPARE(window->desktops().count(), 0u); // we should be on all desktops now QVERIFY(window->isOnAllDesktops()); // put on desktop 1 window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(1)); QVERIFY(window->isOnDesktop(1)); QVERIFY(!window->isOnDesktop(2)); QVERIFY(!window->isOnDesktop(3)); QCOMPARE(window->desktops().count(), 1u); // put on desktop 2 window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(2)); QVERIFY(window->isOnDesktop(1)); QVERIFY(window->isOnDesktop(2)); QVERIFY(!window->isOnDesktop(3)); QCOMPARE(window->desktops().count(), 2u); // put on desktop 3 window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(3)); QVERIFY(window->isOnDesktop(1)); QVERIFY(window->isOnDesktop(2)); QVERIFY(window->isOnDesktop(3)); QCOMPARE(window->desktops().count(), 3u); // entering twice dooes nothing window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(3)); QCOMPARE(window->desktops().count(), 3u); // adding to "all desktops" results in just that one desktop window->setOnAllDesktops(true); QCOMPARE(window->desktops().count(), 0u); window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(3)); QVERIFY(window->isOnDesktop(3)); QCOMPARE(window->desktops().count(), 1u); // leaving a desktop on "all desktops" puts on everything else window->setOnAllDesktops(true); QCOMPARE(window->desktops().count(), 0u); window->leaveDesktop(VirtualDesktopManager::self()->desktopForX11Id(3)); QVERIFY(window->isOnDesktop(1)); QVERIFY(window->isOnDesktop(2)); QCOMPARE(window->desktops().count(), 2u); } void VirtualDesktopTest::testRemoveDesktopWithWindow() { // first create two new desktops QCOMPARE(VirtualDesktopManager::self()->count(), 1u); VirtualDesktopManager::self()->setCount(3); QCOMPARE(VirtualDesktopManager::self()->count(), 3u); // switch to last desktop VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last()); QCOMPARE(VirtualDesktopManager::self()->current(), 3u); // now create a window on this desktop std::unique_ptr surface(Test::createSurface()); std::unique_ptr shellSurface(Test::createXdgToplevelSurface(surface.get())); auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue); QVERIFY(window); QCOMPARE(window->desktop(), 3u); QSignalSpy desktopPresenceChangedSpy(window, &Window::desktopPresenceChanged); QCOMPARE(window->desktops().count(), 1u); QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first()); // Set the window on desktop 2 as well window->enterDesktop(VirtualDesktopManager::self()->desktops()[1]); QCOMPARE(window->desktops().count(), 2u); QCOMPARE(VirtualDesktopManager::self()->desktops()[2], window->desktops()[0]); QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[1]); QVERIFY(window->isOnDesktop(2)); QVERIFY(window->isOnDesktop(3)); // remove desktop 3 VirtualDesktopManager::self()->setCount(2); QCOMPARE(window->desktops().count(), 1u); // window is only on desktop 2 QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[0]); // Again 3 desktops VirtualDesktopManager::self()->setCount(3); // move window to be only on desktop 3 window->enterDesktop(VirtualDesktopManager::self()->desktops()[2]); window->leaveDesktop(VirtualDesktopManager::self()->desktops()[1]); QCOMPARE(window->desktops().count(), 1u); // window is only on desktop 3 QCOMPARE(VirtualDesktopManager::self()->desktops()[2], window->desktops()[0]); // remove desktop 3 VirtualDesktopManager::self()->setCount(2); QCOMPARE(window->desktops().count(), 1u); // window is only on desktop 2 QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[0]); } WAYLANDTEST_MAIN(VirtualDesktopTest) #include "virtual_desktop_test.moc"