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"