File indexing completed on 2024-11-10 04:56:00
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"