File indexing completed on 2024-05-12 05:30:35

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 "input.h"
0012 #include "pointer_input.h"
0013 #include "scripting/scripting.h"
0014 #include "useractions.h"
0015 #include "virtualdesktops.h"
0016 #include "wayland_server.h"
0017 #include "window.h"
0018 #include "workspace.h"
0019 
0020 #include <KWayland/Client/surface.h>
0021 
0022 #include <QDBusConnection>
0023 #include <QDBusMessage>
0024 #include <QDBusPendingReply>
0025 #include <QTemporaryFile>
0026 
0027 using namespace KWin;
0028 
0029 static const QString s_socketName = QStringLiteral("wayland_test_kwin_kwinbindings-0");
0030 
0031 class KWinBindingsTest : public QObject
0032 {
0033     Q_OBJECT
0034 private Q_SLOTS:
0035     void initTestCase();
0036     void init();
0037     void cleanup();
0038 
0039     void testSwitchWindow();
0040     void testSwitchWindowScript();
0041     void testWindowToDesktop_data();
0042     void testWindowToDesktop();
0043 };
0044 
0045 void KWinBindingsTest::initTestCase()
0046 {
0047     qRegisterMetaType<KWin::Window *>();
0048     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0049     QVERIFY(waylandServer()->init(s_socketName));
0050     Test::setOutputConfig({
0051         QRect(0, 0, 1280, 1024),
0052         QRect(1280, 0, 1280, 1024),
0053     });
0054 
0055     kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
0056 
0057     kwinApp()->start();
0058     QVERIFY(applicationStartedSpy.wait());
0059 }
0060 
0061 void KWinBindingsTest::init()
0062 {
0063     QVERIFY(Test::setupWaylandConnection());
0064     workspace()->setActiveOutput(QPoint(640, 512));
0065     KWin::input()->pointer()->warp(QPoint(640, 512));
0066 }
0067 
0068 void KWinBindingsTest::cleanup()
0069 {
0070     Test::destroyWaylandConnection();
0071 }
0072 
0073 void KWinBindingsTest::testSwitchWindow()
0074 {
0075     // first create windows
0076     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0077     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0078     auto c1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::blue);
0079     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0080     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0081     auto c2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
0082     std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
0083     std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
0084     auto c3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::blue);
0085     std::unique_ptr<KWayland::Client::Surface> surface4(Test::createSurface());
0086     std::unique_ptr<Test::XdgToplevel> shellSurface4(Test::createXdgToplevelSurface(surface4.get()));
0087     auto c4 = Test::renderAndWaitForShown(surface4.get(), QSize(100, 50), Qt::blue);
0088 
0089     QVERIFY(c4->isActive());
0090     QVERIFY(c4 != c3);
0091     QVERIFY(c3 != c2);
0092     QVERIFY(c2 != c1);
0093 
0094     // let's position all windows
0095     c1->move(QPoint(0, 0));
0096     c2->move(QPoint(200, 0));
0097     c3->move(QPoint(200, 200));
0098     c4->move(QPoint(0, 200));
0099 
0100     // now let's trigger the shortcuts
0101 
0102     // invoke global shortcut through dbus
0103     auto invokeShortcut = [](const QString &shortcut) {
0104         auto msg = QDBusMessage::createMethodCall(
0105             QStringLiteral("org.kde.kglobalaccel"),
0106             QStringLiteral("/component/kwin"),
0107             QStringLiteral("org.kde.kglobalaccel.Component"),
0108             QStringLiteral("invokeShortcut"));
0109         msg.setArguments(QList<QVariant>{shortcut});
0110         QDBusConnection::sessionBus().asyncCall(msg);
0111     };
0112     invokeShortcut(QStringLiteral("Switch Window Up"));
0113     QTRY_COMPARE(workspace()->activeWindow(), c1);
0114     invokeShortcut(QStringLiteral("Switch Window Right"));
0115     QTRY_COMPARE(workspace()->activeWindow(), c2);
0116     invokeShortcut(QStringLiteral("Switch Window Down"));
0117     QTRY_COMPARE(workspace()->activeWindow(), c3);
0118     invokeShortcut(QStringLiteral("Switch Window Left"));
0119     QTRY_COMPARE(workspace()->activeWindow(), c4);
0120     // test opposite direction
0121     invokeShortcut(QStringLiteral("Switch Window Left"));
0122     QTRY_COMPARE(workspace()->activeWindow(), c3);
0123     invokeShortcut(QStringLiteral("Switch Window Down"));
0124     QTRY_COMPARE(workspace()->activeWindow(), c2);
0125     invokeShortcut(QStringLiteral("Switch Window Right"));
0126     QTRY_COMPARE(workspace()->activeWindow(), c1);
0127     invokeShortcut(QStringLiteral("Switch Window Up"));
0128     QTRY_COMPARE(workspace()->activeWindow(), c4);
0129 }
0130 
0131 void KWinBindingsTest::testSwitchWindowScript()
0132 {
0133     QVERIFY(Scripting::self());
0134 
0135     // first create windows
0136     std::unique_ptr<KWayland::Client::Surface> surface1(Test::createSurface());
0137     std::unique_ptr<Test::XdgToplevel> shellSurface1(Test::createXdgToplevelSurface(surface1.get()));
0138     auto c1 = Test::renderAndWaitForShown(surface1.get(), QSize(100, 50), Qt::blue);
0139     std::unique_ptr<KWayland::Client::Surface> surface2(Test::createSurface());
0140     std::unique_ptr<Test::XdgToplevel> shellSurface2(Test::createXdgToplevelSurface(surface2.get()));
0141     auto c2 = Test::renderAndWaitForShown(surface2.get(), QSize(100, 50), Qt::blue);
0142     std::unique_ptr<KWayland::Client::Surface> surface3(Test::createSurface());
0143     std::unique_ptr<Test::XdgToplevel> shellSurface3(Test::createXdgToplevelSurface(surface3.get()));
0144     auto c3 = Test::renderAndWaitForShown(surface3.get(), QSize(100, 50), Qt::blue);
0145     std::unique_ptr<KWayland::Client::Surface> surface4(Test::createSurface());
0146     std::unique_ptr<Test::XdgToplevel> shellSurface4(Test::createXdgToplevelSurface(surface4.get()));
0147     auto c4 = Test::renderAndWaitForShown(surface4.get(), QSize(100, 50), Qt::blue);
0148 
0149     QVERIFY(c4->isActive());
0150     QVERIFY(c4 != c3);
0151     QVERIFY(c3 != c2);
0152     QVERIFY(c2 != c1);
0153 
0154     // let's position all windows
0155     c1->move(QPoint(0, 0));
0156     c2->move(QPoint(200, 0));
0157     c3->move(QPoint(200, 200));
0158     c4->move(QPoint(0, 200));
0159 
0160     auto runScript = [](const QString &slot) {
0161         QTemporaryFile tmpFile;
0162         QVERIFY(tmpFile.open());
0163         QTextStream out(&tmpFile);
0164         out << "workspace." << slot << "()";
0165         out.flush();
0166 
0167         const int id = Scripting::self()->loadScript(tmpFile.fileName());
0168         QVERIFY(id != -1);
0169         QVERIFY(Scripting::self()->isScriptLoaded(tmpFile.fileName()));
0170         auto s = Scripting::self()->findScript(tmpFile.fileName());
0171         QVERIFY(s);
0172         QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
0173         s->run();
0174         QTRY_COMPARE(runningChangedSpy.count(), 1);
0175     };
0176 
0177     runScript(QStringLiteral("slotSwitchWindowUp"));
0178     QTRY_COMPARE(workspace()->activeWindow(), c1);
0179     runScript(QStringLiteral("slotSwitchWindowRight"));
0180     QTRY_COMPARE(workspace()->activeWindow(), c2);
0181     runScript(QStringLiteral("slotSwitchWindowDown"));
0182     QTRY_COMPARE(workspace()->activeWindow(), c3);
0183     runScript(QStringLiteral("slotSwitchWindowLeft"));
0184     QTRY_COMPARE(workspace()->activeWindow(), c4);
0185 }
0186 
0187 void KWinBindingsTest::testWindowToDesktop_data()
0188 {
0189     QTest::addColumn<int>("desktop");
0190 
0191     QTest::newRow("2") << 2;
0192     QTest::newRow("3") << 3;
0193     QTest::newRow("4") << 4;
0194     QTest::newRow("5") << 5;
0195     QTest::newRow("6") << 6;
0196     QTest::newRow("7") << 7;
0197     QTest::newRow("8") << 8;
0198     QTest::newRow("9") << 9;
0199     QTest::newRow("10") << 10;
0200     QTest::newRow("11") << 11;
0201     QTest::newRow("12") << 12;
0202     QTest::newRow("13") << 13;
0203     QTest::newRow("14") << 14;
0204     QTest::newRow("15") << 15;
0205     QTest::newRow("16") << 16;
0206     QTest::newRow("17") << 17;
0207     QTest::newRow("18") << 18;
0208     QTest::newRow("19") << 19;
0209     QTest::newRow("20") << 20;
0210 }
0211 
0212 void KWinBindingsTest::testWindowToDesktop()
0213 {
0214     // first go to desktop one
0215     VirtualDesktopManager::self()->setCurrent(VirtualDesktopManager::self()->desktops().first());
0216 
0217     // now create a window
0218     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0219     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0220     auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
0221     QSignalSpy desktopsChangedSpy(window, &Window::desktopsChanged);
0222     QCOMPARE(workspace()->activeWindow(), window);
0223 
0224     QFETCH(int, desktop);
0225     VirtualDesktopManager::self()->setCount(desktop);
0226     const auto desktops = VirtualDesktopManager::self()->desktops();
0227 
0228     // now trigger the shortcut
0229     auto invokeShortcut = [](int desktop) {
0230         auto msg = QDBusMessage::createMethodCall(
0231             QStringLiteral("org.kde.kglobalaccel"),
0232             QStringLiteral("/component/kwin"),
0233             QStringLiteral("org.kde.kglobalaccel.Component"),
0234             QStringLiteral("invokeShortcut"));
0235         msg.setArguments(QList<QVariant>{QStringLiteral("Window to Desktop %1").arg(desktop)});
0236         QDBusConnection::sessionBus().asyncCall(msg);
0237     };
0238     invokeShortcut(desktop);
0239     QVERIFY(desktopsChangedSpy.wait());
0240     QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops.at(desktop - 1)});
0241     // back to desktop 1
0242     invokeShortcut(1);
0243     QVERIFY(desktopsChangedSpy.wait());
0244     QCOMPARE(window->desktops(), QList<VirtualDesktop *>{desktops.at(0)});
0245     // invoke with one desktop too many
0246     invokeShortcut(desktop + 1);
0247     // that should fail
0248     QVERIFY(!desktopsChangedSpy.wait(100));
0249 }
0250 
0251 WAYLANDTEST_MAIN(KWinBindingsTest)
0252 #include "kwinbindings_test.moc"