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

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "kwin_wayland_test.h"
0010 
0011 #include "effect/effectloader.h"
0012 #include "pointer_input.h"
0013 #include "scripting/scripting.h"
0014 #include "wayland_server.h"
0015 #include "workspace.h"
0016 
0017 #define private public
0018 #include "screenedge.h"
0019 #undef private
0020 
0021 #include <KConfigGroup>
0022 
0023 Q_DECLARE_METATYPE(KWin::ElectricBorder)
0024 
0025 using namespace KWin;
0026 
0027 static const QString s_socketName = QStringLiteral("wayland_test_kwin_scripting_screenedge-0");
0028 
0029 class ScreenEdgeTest : public QObject
0030 {
0031     Q_OBJECT
0032 private Q_SLOTS:
0033     void initTestCase();
0034     void init();
0035     void cleanup();
0036 
0037     void testEdge_data();
0038     void testEdge();
0039     void testTouchEdge_data();
0040     void testTouchEdge();
0041     void testEdgeUnregister();
0042     void testDeclarativeTouchEdge();
0043 
0044 private:
0045     void triggerConfigReload();
0046 };
0047 
0048 void ScreenEdgeTest::initTestCase()
0049 {
0050     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0051     QVERIFY(waylandServer()->init(s_socketName));
0052     Test::setOutputConfig({QRect(0, 0, 1280, 1024)});
0053 
0054     // empty config to have defaults
0055     auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig);
0056 
0057     // disable all effects to prevent them grabbing edges
0058     KConfigGroup plugins(config, QStringLiteral("Plugins"));
0059     const auto builtinNames = EffectLoader().listOfKnownEffects();
0060     for (QString name : builtinNames) {
0061         plugins.writeEntry(name + QStringLiteral("Enabled"), false);
0062     }
0063 
0064     // disable electric border pushback
0065     config->group(QStringLiteral("Windows")).writeEntry("ElectricBorderPushbackPixels", 0);
0066     config->group(QStringLiteral("TabBox")).writeEntry("TouchBorderActivate", int(ElectricNone));
0067 
0068     config->sync();
0069     kwinApp()->setConfig(config);
0070 
0071     kwinApp()->start();
0072     QVERIFY(applicationStartedSpy.wait());
0073     QVERIFY(Scripting::self());
0074 
0075     workspace()->screenEdges()->setTimeThreshold(0);
0076     workspace()->screenEdges()->setReActivationThreshold(0);
0077 }
0078 
0079 void ScreenEdgeTest::init()
0080 {
0081     KWin::input()->pointer()->warp(QPointF(640, 512));
0082     if (workspace()->showingDesktop()) {
0083         workspace()->slotToggleShowDesktop();
0084     }
0085     QVERIFY(!workspace()->showingDesktop());
0086 }
0087 
0088 void ScreenEdgeTest::cleanup()
0089 {
0090     // try to unload the script
0091     const QStringList scripts = {QFINDTESTDATA("./scripts/screenedge.js"), QFINDTESTDATA("./scripts/screenedgeunregister.js"), QFINDTESTDATA("./scripts/touchScreenedge.js")};
0092     for (const QString &script : scripts) {
0093         if (!script.isEmpty()) {
0094             if (Scripting::self()->isScriptLoaded(script)) {
0095                 QVERIFY(Scripting::self()->unloadScript(script));
0096                 QTRY_VERIFY(!Scripting::self()->isScriptLoaded(script));
0097             }
0098         }
0099     }
0100 }
0101 
0102 void ScreenEdgeTest::testEdge_data()
0103 {
0104     QTest::addColumn<KWin::ElectricBorder>("edge");
0105     QTest::addColumn<QPoint>("triggerPos");
0106 
0107     QTest::newRow("Top") << KWin::ElectricTop << QPoint(512, 0);
0108     QTest::newRow("TopRight") << KWin::ElectricTopRight << QPoint(1279, 0);
0109     QTest::newRow("Right") << KWin::ElectricRight << QPoint(1279, 512);
0110     QTest::newRow("BottomRight") << KWin::ElectricBottomRight << QPoint(1279, 1023);
0111     QTest::newRow("Bottom") << KWin::ElectricBottom << QPoint(512, 1023);
0112     QTest::newRow("BottomLeft") << KWin::ElectricBottomLeft << QPoint(0, 1023);
0113     QTest::newRow("Left") << KWin::ElectricLeft << QPoint(0, 512);
0114     QTest::newRow("TopLeft") << KWin::ElectricTopLeft << QPoint(0, 0);
0115 
0116     // repeat a row to show previously unloading and re-registering works
0117     QTest::newRow("Top") << KWin::ElectricTop << QPoint(512, 0);
0118 }
0119 
0120 void ScreenEdgeTest::testEdge()
0121 {
0122     const QString scriptToLoad = QFINDTESTDATA("./scripts/screenedge.js");
0123     QVERIFY(!scriptToLoad.isEmpty());
0124 
0125     // mock the config
0126     auto config = kwinApp()->config();
0127     QFETCH(KWin::ElectricBorder, edge);
0128     config->group(QLatin1String("Script-") + scriptToLoad).writeEntry("Edge", int(edge));
0129     config->sync();
0130 
0131     QVERIFY(!Scripting::self()->isScriptLoaded(scriptToLoad));
0132     const int id = Scripting::self()->loadScript(scriptToLoad);
0133     QVERIFY(id != -1);
0134     QVERIFY(Scripting::self()->isScriptLoaded(scriptToLoad));
0135     auto s = Scripting::self()->findScript(scriptToLoad);
0136     QVERIFY(s);
0137     QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
0138     s->run();
0139     QVERIFY(runningChangedSpy.wait());
0140     QCOMPARE(runningChangedSpy.count(), 1);
0141     QCOMPARE(runningChangedSpy.first().first().toBool(), true);
0142     // triggering the edge will result in show desktop being triggered
0143     QSignalSpy showDesktopSpy(workspace(), &Workspace::showingDesktopChanged);
0144 
0145     // trigger the edge
0146     QFETCH(QPoint, triggerPos);
0147     KWin::input()->pointer()->warp(triggerPos);
0148     QCOMPARE(showDesktopSpy.count(), 1);
0149     QVERIFY(workspace()->showingDesktop());
0150 }
0151 
0152 void ScreenEdgeTest::testTouchEdge_data()
0153 {
0154     QTest::addColumn<KWin::ElectricBorder>("edge");
0155     QTest::addColumn<QPoint>("triggerPos");
0156     QTest::addColumn<QPoint>("motionPos");
0157 
0158     QTest::newRow("Top") << KWin::ElectricTop << QPoint(50, 0) << QPoint(50, 500);
0159     QTest::newRow("Right") << KWin::ElectricRight << QPoint(1279, 50) << QPoint(500, 50);
0160     QTest::newRow("Bottom") << KWin::ElectricBottom << QPoint(512, 1023) << QPoint(512, 500);
0161     QTest::newRow("Left") << KWin::ElectricLeft << QPoint(0, 50) << QPoint(500, 50);
0162 
0163     // repeat a row to show previously unloading and re-registering works
0164     QTest::newRow("Top") << KWin::ElectricTop << QPoint(512, 0) << QPoint(512, 500);
0165 }
0166 
0167 void ScreenEdgeTest::testTouchEdge()
0168 {
0169     const QString scriptToLoad = QFINDTESTDATA("./scripts/touchScreenedge.js");
0170     QVERIFY(!scriptToLoad.isEmpty());
0171 
0172     // mock the config
0173     auto config = kwinApp()->config();
0174     QFETCH(KWin::ElectricBorder, edge);
0175     config->group(QLatin1String("Script-") + scriptToLoad).writeEntry("Edge", int(edge));
0176     config->sync();
0177 
0178     QVERIFY(!Scripting::self()->isScriptLoaded(scriptToLoad));
0179     const int id = Scripting::self()->loadScript(scriptToLoad);
0180     QVERIFY(id != -1);
0181     QVERIFY(Scripting::self()->isScriptLoaded(scriptToLoad));
0182     auto s = Scripting::self()->findScript(scriptToLoad);
0183     QVERIFY(s);
0184     QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
0185     s->run();
0186     QVERIFY(runningChangedSpy.wait());
0187     QCOMPARE(runningChangedSpy.count(), 1);
0188     QCOMPARE(runningChangedSpy.first().first().toBool(), true);
0189     // triggering the edge will result in show desktop being triggered
0190     QSignalSpy showDesktopSpy(workspace(), &Workspace::showingDesktopChanged);
0191 
0192     // trigger the edge
0193     QFETCH(QPoint, triggerPos);
0194     quint32 timestamp = 0;
0195     Test::touchDown(0, triggerPos, timestamp++);
0196     QFETCH(QPoint, motionPos);
0197     Test::touchMotion(0, motionPos, timestamp++);
0198     Test::touchUp(0, timestamp++);
0199     QVERIFY(showDesktopSpy.wait());
0200     QCOMPARE(showDesktopSpy.count(), 1);
0201     QVERIFY(workspace()->showingDesktop());
0202 }
0203 
0204 void ScreenEdgeTest::triggerConfigReload()
0205 {
0206     workspace()->slotReconfigure();
0207 }
0208 
0209 void ScreenEdgeTest::testEdgeUnregister()
0210 {
0211     const QString scriptToLoad = QFINDTESTDATA("./scripts/screenedgeunregister.js");
0212     QVERIFY(!scriptToLoad.isEmpty());
0213 
0214     Scripting::self()->loadScript(scriptToLoad);
0215     auto s = Scripting::self()->findScript(scriptToLoad);
0216     auto configGroup = s->config();
0217     configGroup.writeEntry("Edge", int(KWin::ElectricLeft));
0218     configGroup.sync();
0219     const QPoint triggerPos = QPoint(0, 512);
0220 
0221     QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
0222     s->run();
0223     QVERIFY(runningChangedSpy.wait());
0224 
0225     QSignalSpy showDesktopSpy(workspace(), &Workspace::showingDesktopChanged);
0226 
0227     // trigger the edge
0228     KWin::input()->pointer()->warp(triggerPos);
0229     QCOMPARE(showDesktopSpy.count(), 1);
0230 
0231     // reset
0232     KWin::input()->pointer()->warp(QPointF(500, 500));
0233     workspace()->slotToggleShowDesktop();
0234     showDesktopSpy.clear();
0235 
0236     // trigger again, to show that retriggering works
0237     KWin::input()->pointer()->warp(triggerPos);
0238     QCOMPARE(showDesktopSpy.count(), 1);
0239 
0240     // reset
0241     KWin::input()->pointer()->warp(QPointF(500, 500));
0242     workspace()->slotToggleShowDesktop();
0243     showDesktopSpy.clear();
0244 
0245     // make the script unregister the edge
0246     configGroup.writeEntry("mode", "unregister");
0247     triggerConfigReload();
0248     KWin::input()->pointer()->warp(triggerPos);
0249     QCOMPARE(showDesktopSpy.count(), 0); // not triggered
0250 
0251     // force the script to unregister a non-registered edge to prove it doesn't explode
0252     triggerConfigReload();
0253 }
0254 
0255 void ScreenEdgeTest::testDeclarativeTouchEdge()
0256 {
0257     const QString scriptToLoad = QFINDTESTDATA("./scripts/screenedgetouch.qml");
0258     QVERIFY(!scriptToLoad.isEmpty());
0259     QVERIFY(Scripting::self()->loadDeclarativeScript(scriptToLoad) != -1);
0260     QVERIFY(Scripting::self()->isScriptLoaded(scriptToLoad));
0261 
0262     auto s = Scripting::self()->findScript(scriptToLoad);
0263     QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged);
0264     s->run();
0265     QTRY_COMPARE(runningChangedSpy.count(), 1);
0266 
0267     QSignalSpy showDesktopSpy(workspace(), &Workspace::showingDesktopChanged);
0268 
0269     // Trigger the edge through touch
0270     quint32 timestamp = 0;
0271     Test::touchDown(0, QPointF(0, 50), timestamp++);
0272     Test::touchMotion(0, QPointF(500, 50), timestamp++);
0273     Test::touchUp(0, timestamp++);
0274 
0275     QVERIFY(showDesktopSpy.wait());
0276 }
0277 
0278 WAYLANDTEST_MAIN(ScreenEdgeTest)
0279 #include "screenedge_test.moc"