File indexing completed on 2024-11-10 04:56:09

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "kwin_wayland_test.h"
0010 
0011 #include "main.h"
0012 #include "utils/xcbutils.h"
0013 #include "virtualdesktops.h"
0014 #include "wayland_server.h"
0015 #include "window.h"
0016 #include "workspace.h"
0017 
0018 #include <KWayland/Client/surface.h>
0019 
0020 using namespace KWin;
0021 
0022 static const QString s_socketName = QStringLiteral("wayland_test_kwin_virtualdesktop-0");
0023 
0024 class VirtualDesktopTest : public QObject
0025 {
0026     Q_OBJECT
0027 private Q_SLOTS:
0028     void initTestCase();
0029     void init();
0030     void cleanup();
0031 
0032     void testNetCurrentDesktop();
0033     void testLastDesktopRemoved();
0034     void testWindowOnMultipleDesktops();
0035     void testRemoveDesktopWithWindow();
0036 };
0037 
0038 void VirtualDesktopTest::initTestCase()
0039 {
0040     qRegisterMetaType<KWin::Window *>();
0041     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0042     QVERIFY(waylandServer()->init(s_socketName));
0043     Test::setOutputConfig({
0044         QRect(0, 0, 1280, 1024),
0045         QRect(1280, 0, 1280, 1024),
0046     });
0047 
0048     kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
0049     qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1");
0050     qputenv("XKB_DEFAULT_RULES", "evdev");
0051 
0052     kwinApp()->start();
0053     QVERIFY(applicationStartedSpy.wait());
0054 
0055     if (kwinApp()->x11Connection()) {
0056         // verify the current desktop x11 property on startup, see BUG: 391034
0057         Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP");
0058         QVERIFY(currentDesktopAtom.isValid());
0059         Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
0060         bool ok = true;
0061         QCOMPARE(currentDesktop.value(0, &ok), 0);
0062         QVERIFY(ok);
0063     }
0064 }
0065 
0066 void VirtualDesktopTest::init()
0067 {
0068     QVERIFY(Test::setupWaylandConnection());
0069     workspace()->setActiveOutput(QPoint(640, 512));
0070     VirtualDesktopManager::self()->setCount(1);
0071 }
0072 
0073 void VirtualDesktopTest::cleanup()
0074 {
0075     Test::destroyWaylandConnection();
0076 }
0077 
0078 void VirtualDesktopTest::testNetCurrentDesktop()
0079 {
0080     if (!kwinApp()->x11Connection()) {
0081         QSKIP("Skipped on Wayland only");
0082     }
0083     QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
0084     VirtualDesktopManager::self()->setCount(4);
0085     QCOMPARE(VirtualDesktopManager::self()->count(), 4u);
0086 
0087     Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP");
0088     QVERIFY(currentDesktopAtom.isValid());
0089     Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
0090     bool ok = true;
0091     QCOMPARE(currentDesktop.value(0, &ok), 0);
0092     QVERIFY(ok);
0093 
0094     // go to desktop 2
0095     VirtualDesktopManager::self()->setCurrent(2);
0096     currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
0097     QCOMPARE(currentDesktop.value(0, &ok), 1);
0098     QVERIFY(ok);
0099 
0100     // go to desktop 3
0101     VirtualDesktopManager::self()->setCurrent(3);
0102     currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
0103     QCOMPARE(currentDesktop.value(0, &ok), 2);
0104     QVERIFY(ok);
0105 
0106     // go to desktop 4
0107     VirtualDesktopManager::self()->setCurrent(4);
0108     currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
0109     QCOMPARE(currentDesktop.value(0, &ok), 3);
0110     QVERIFY(ok);
0111 
0112     // and back to first
0113     VirtualDesktopManager::self()->setCurrent(1);
0114     currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1);
0115     QCOMPARE(currentDesktop.value(0, &ok), 0);
0116     QVERIFY(ok);
0117 }
0118 
0119 void VirtualDesktopTest::testLastDesktopRemoved()
0120 {
0121     // first create a new desktop
0122     QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
0123     VirtualDesktopManager::self()->setCount(2);
0124     QCOMPARE(VirtualDesktopManager::self()->count(), 2u);
0125 
0126     // switch to last desktop
0127     VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last());
0128     QCOMPARE(VirtualDesktopManager::self()->current(), 2u);
0129 
0130     // now create a window on this desktop
0131     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0132     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0133     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0134 
0135     QVERIFY(window);
0136     QCOMPARE(window->desktops().count(), 1u);
0137     QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first());
0138 
0139     // and remove last desktop
0140     VirtualDesktopManager::self()->setCount(1);
0141     QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
0142     // now the window should be moved as well
0143     QCOMPARE(window->desktops().count(), 1u);
0144     QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first());
0145 }
0146 
0147 void VirtualDesktopTest::testWindowOnMultipleDesktops()
0148 {
0149     // first create two new desktops
0150     QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
0151     VirtualDesktopManager::self()->setCount(3);
0152     QCOMPARE(VirtualDesktopManager::self()->count(), 3u);
0153 
0154     // switch to last desktop
0155     const auto desktops = VirtualDesktopManager::self()->desktops();
0156     VirtualDesktopManager::self()->setCurrent(desktops.at(2));
0157 
0158     // now create a window on this desktop
0159     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0160     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0161     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0162     QVERIFY(window);
0163     QCOMPARE(window->desktops(), (QList<VirtualDesktop *>{desktops.at(2)}));
0164 
0165     // Set the window on desktop 2 as well
0166     window->enterDesktop(VirtualDesktopManager::self()->desktopForX11Id(2));
0167     QCOMPARE(window->desktops().count(), 2u);
0168     QCOMPARE(window->desktops()[0], desktops.at(2));
0169     QCOMPARE(window->desktops()[1], desktops.at(1));
0170 
0171     // leave desktop 3
0172     window->leaveDesktop(desktops.at(2));
0173     QCOMPARE(window->desktops(), (QList<VirtualDesktop *>{desktops.at(1)}));
0174     // leave desktop 2
0175     window->leaveDesktop(desktops.at(1));
0176     QCOMPARE(window->desktops(), QList<VirtualDesktop *>{});
0177     // we should be on all desktops now
0178     QVERIFY(window->isOnAllDesktops());
0179     // put on desktop 1
0180     window->enterDesktop(desktops.at(0));
0181     QVERIFY(window->isOnDesktop(desktops.at(0)));
0182     QVERIFY(!window->isOnDesktop(desktops.at(1)));
0183     QVERIFY(!window->isOnDesktop(desktops.at(2)));
0184     QCOMPARE(window->desktops().count(), 1u);
0185     // put on desktop 2
0186     window->enterDesktop(desktops.at(1));
0187     QVERIFY(window->isOnDesktop(desktops.at(0)));
0188     QVERIFY(window->isOnDesktop(desktops.at(1)));
0189     QVERIFY(!window->isOnDesktop(desktops.at(2)));
0190     QCOMPARE(window->desktops().count(), 2u);
0191     // put on desktop 3
0192     window->enterDesktop(desktops.at(2));
0193     QVERIFY(window->isOnDesktop(desktops.at(0)));
0194     QVERIFY(window->isOnDesktop(desktops.at(1)));
0195     QVERIFY(window->isOnDesktop(desktops.at(2)));
0196     QCOMPARE(window->desktops().count(), 3u);
0197 
0198     // entering twice dooes nothing
0199     window->enterDesktop(desktops.at(2));
0200     QCOMPARE(window->desktops().count(), 3u);
0201 
0202     // adding to "all desktops" results in just that one desktop
0203     window->setOnAllDesktops(true);
0204     QCOMPARE(window->desktops().count(), 0u);
0205     window->enterDesktop(desktops.at(2));
0206     QVERIFY(window->isOnDesktop(desktops.at(2)));
0207     QCOMPARE(window->desktops().count(), 1u);
0208 
0209     // leaving a desktop on "all desktops" puts on everything else
0210     window->setOnAllDesktops(true);
0211     QCOMPARE(window->desktops().count(), 0u);
0212     window->leaveDesktop(desktops.at(2));
0213     QVERIFY(window->isOnDesktop(desktops.at(0)));
0214     QVERIFY(window->isOnDesktop(desktops.at(1)));
0215     QCOMPARE(window->desktops().count(), 2u);
0216 }
0217 
0218 void VirtualDesktopTest::testRemoveDesktopWithWindow()
0219 {
0220     // first create two new desktops
0221     QCOMPARE(VirtualDesktopManager::self()->count(), 1u);
0222     VirtualDesktopManager::self()->setCount(3);
0223     QCOMPARE(VirtualDesktopManager::self()->count(), 3u);
0224 
0225     // switch to last desktop
0226     VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().last());
0227     QCOMPARE(VirtualDesktopManager::self()->current(), 3u);
0228 
0229     // now create a window on this desktop
0230     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0231     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0232     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0233 
0234     QVERIFY(window);
0235 
0236     QCOMPARE(window->desktops().count(), 1u);
0237     QCOMPARE(VirtualDesktopManager::self()->currentDesktop(), window->desktops().first());
0238 
0239     // Set the window on desktop 2 as well
0240     window->enterDesktop(VirtualDesktopManager::self()->desktops()[1]);
0241     QCOMPARE(window->desktops().count(), 2u);
0242     QCOMPARE(VirtualDesktopManager::self()->desktops()[2], window->desktops()[0]);
0243     QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[1]);
0244 
0245     // remove desktop 3
0246     VirtualDesktopManager::self()->setCount(2);
0247     QCOMPARE(window->desktops().count(), 1u);
0248     // window is only on desktop 2
0249     QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[0]);
0250 
0251     // Again 3 desktops
0252     VirtualDesktopManager::self()->setCount(3);
0253     // move window to be only on desktop 3
0254     window->enterDesktop(VirtualDesktopManager::self()->desktops()[2]);
0255     window->leaveDesktop(VirtualDesktopManager::self()->desktops()[1]);
0256     QCOMPARE(window->desktops().count(), 1u);
0257     // window is only on desktop 3
0258     QCOMPARE(VirtualDesktopManager::self()->desktops()[2], window->desktops()[0]);
0259 
0260     // remove desktop 3
0261     VirtualDesktopManager::self()->setCount(2);
0262     QCOMPARE(window->desktops().count(), 1u);
0263     // window is only on desktop 2
0264     QCOMPARE(VirtualDesktopManager::self()->desktops()[1], window->desktops()[0]);
0265 }
0266 
0267 WAYLANDTEST_MAIN(VirtualDesktopTest)
0268 #include "virtual_desktop_test.moc"