diff --git a/autotests/integration/scripting/screenedge_test.cpp b/autotests/integration/scripting/screenedge_test.cpp index e828619320..7ca92b56ea 100644 --- a/autotests/integration/scripting/screenedge_test.cpp +++ b/autotests/integration/scripting/screenedge_test.cpp @@ -25,6 +25,11 @@ along with this program. If not, see . #include "workspace.h" #include "scripting/scripting.h" #include "effect_builtins.h" +#include "workspace.h" + +#define private public +#include "screenedge.h" +#undef private #include @@ -44,6 +49,10 @@ private Q_SLOTS: void testEdge_data(); void testEdge(); + void testEdgeUnregister(); + +private: + void triggerConfigReload(); }; void ScreenEdgeTest::initTestCase() @@ -64,7 +73,7 @@ void ScreenEdgeTest::initTestCase() plugins.writeEntry(name + QStringLiteral("Enabled"), false); } - // disable electric border pushaback + // disable electric border pushback config->group("Windows").writeEntry("ElectricBorderPushbackPixels", 0); config->sync(); @@ -73,6 +82,9 @@ void ScreenEdgeTest::initTestCase() kwinApp()->start(); QVERIFY(workspaceCreatedSpy.wait()); QVERIFY(Scripting::self()); + + ScreenEdges::self()->setTimeThreshold(0); + ScreenEdges::self()->setReActivationThreshold(0); } void ScreenEdgeTest::init() @@ -87,11 +99,13 @@ void ScreenEdgeTest::init() void ScreenEdgeTest::cleanup() { // try to unload the script - const QString scriptToLoad = QFINDTESTDATA("./scripts/screenedge.js"); - if (!scriptToLoad.isEmpty()) { - if (Scripting::self()->isScriptLoaded(scriptToLoad)) { - QVERIFY(Scripting::self()->unloadScript(scriptToLoad)); - QTRY_VERIFY(!Scripting::self()->isScriptLoaded(scriptToLoad)); + const QStringList scripts = {QFINDTESTDATA("./scripts/screenedge.js"), QFINDTESTDATA("./scripts/screenedgeunregister.js")}; + for (const QString &script: scripts) { + if (!script.isEmpty()) { + if (Scripting::self()->isScriptLoaded(script)) { + QVERIFY(Scripting::self()->unloadScript(script)); + QTRY_VERIFY(!Scripting::self()->isScriptLoaded(script)); + } } } } @@ -109,6 +123,9 @@ void ScreenEdgeTest::testEdge_data() QTest::newRow("BottomLeft") << KWin::ElectricBottomLeft << QPoint(0, 1023); QTest::newRow("Left") << KWin::ElectricLeft << QPoint(0, 512); QTest::newRow("TopLeft") << KWin::ElectricTopLeft << QPoint(0, 0); + + //repeat a row to show previously unloading and re-registering works + QTest::newRow("Top") << KWin::ElectricTop << QPoint(512, 0); } void ScreenEdgeTest::testEdge() @@ -145,5 +162,56 @@ void ScreenEdgeTest::testEdge() QVERIFY(workspace()->showingDesktop()); } +void ScreenEdgeTest::triggerConfigReload() { + workspace()->slotReconfigure(); +} + +void ScreenEdgeTest::testEdgeUnregister() +{ + const QString scriptToLoad = QFINDTESTDATA("./scripts/screenedgeunregister.js"); + QVERIFY(!scriptToLoad.isEmpty()); + + Scripting::self()->loadScript(scriptToLoad); + auto s = Scripting::self()->findScript(scriptToLoad); + auto configGroup = s->config(); + configGroup.writeEntry("Edge", int(KWin::ElectricLeft)); + configGroup.sync(); + const QPoint triggerPos = QPoint(0, 512); + + QSignalSpy runningChangedSpy(s, &AbstractScript::runningChanged); + s->run(); + QVERIFY(runningChangedSpy.wait()); + + QSignalSpy showDesktopSpy(workspace(), &Workspace::showingDesktopChanged); + QVERIFY(showDesktopSpy.isValid()); + + //trigger the edge + KWin::Cursor::setPos(triggerPos); + QCOMPARE(showDesktopSpy.count(), 1); + + //reset + KWin::Cursor::setPos(500,500); + workspace()->slotToggleShowDesktop(); + showDesktopSpy.clear(); + + //trigger again, to show that retriggering works + KWin::Cursor::setPos(triggerPos); + QCOMPARE(showDesktopSpy.count(), 1); + + //reset + KWin::Cursor::setPos(500,500); + workspace()->slotToggleShowDesktop(); + showDesktopSpy.clear(); + + //make the script unregister the edge + configGroup.writeEntry("mode", "unregister"); + triggerConfigReload(); + KWin::Cursor::setPos(triggerPos); + QCOMPARE(showDesktopSpy.count(), 0); //not triggered + + //force the script to unregister a non-registered edge to prove it doesn't explode + triggerConfigReload(); +} + WAYLANDTEST_MAIN(ScreenEdgeTest) #include "screenedge_test.moc" diff --git a/autotests/integration/scripting/scripts/screenedgeunregister.js b/autotests/integration/scripting/scripts/screenedgeunregister.js new file mode 100644 index 0000000000..a73b68e7f5 --- /dev/null +++ b/autotests/integration/scripting/scripts/screenedgeunregister.js @@ -0,0 +1,12 @@ +function init() { + var edge = readConfig("Edge", 1); + if (readConfig("mode", "") == "unregister") { + unregisterScreenEdge(edge); + } else { + registerScreenEdge(edge, function() { workspace.slotToggleShowDesktop(); }); + } +} +options.configChanged.connect(init); + +init(); + diff --git a/scripting/documentation-global.xml b/scripting/documentation-global.xml index 6ab70cd341..af4d9a0d5a 100644 --- a/scripting/documentation-global.xml +++ b/scripting/documentation-global.xml @@ -57,6 +57,14 @@ Registers the callback for the screen edge. When the mouse gets pushed against the given edge the callback will be invoked. + + Q_SCRIPTABLE bool + bool KWin::Scripting::unregisterScreenEdge + (ElectricBorder border) + unregisterScreenEdge + + Unregisters the callback for the screen edge. This will disconnect all callbacks from this script to that edge. + Q_SCRIPTABLE bool bool KWin::Scripting::registerShortcut diff --git a/scripting/scripting.cpp b/scripting/scripting.cpp index 7ce6d59fd7..b63bee6cb5 100644 --- a/scripting/scripting.cpp +++ b/scripting/scripting.cpp @@ -154,6 +154,12 @@ QScriptValue kwinRegisterScreenEdge(QScriptContext *context, QScriptEngine *engi return KWin::registerScreenEdge(context, engine); } +QScriptValue kwinUnregisterScreenEdge(QScriptContext *context, QScriptEngine *engine) +{ + return KWin::unregisterScreenEdge(context, engine); +} + + QScriptValue kwinRegisterUserActionsMenu(QScriptContext *context, QScriptEngine *engine) { return KWin::registerUserActionsMenu(context, engine); @@ -277,6 +283,8 @@ void KWin::Script::installScriptFunctions(QScriptEngine* engine) registerGlobalShortcutFunction(this, engine, kwinScriptGlobalShortcut); // add screen edge registerScreenEdgeFunction(this, engine, kwinRegisterScreenEdge); + unregisterScreenEdgeFunction(this, engine, kwinUnregisterScreenEdge); + // add user actions menu register function regesterUserActionsMenuFunction(this, engine, kwinRegisterUserActionsMenu); // add assertions diff --git a/scripting/scriptingutils.h b/scripting/scriptingutils.h index d1e74cd4af..2dc25d9837 100644 --- a/scripting/scriptingutils.h +++ b/scripting/scriptingutils.h @@ -170,6 +170,31 @@ QScriptValue registerScreenEdge(QScriptContext *context, QScriptEngine *engine) return engine->newVariant(true); } +template +QScriptValue unregisterScreenEdge(QScriptContext *context, QScriptEngine *engine) +{ + T script = qobject_cast(context->callee().data().toQObject()); + if (!script) { + return engine->undefinedValue(); + } + if (!validateParameters(context, 1, 1)) { + return engine->undefinedValue(); + } + if (!validateArgumentType(context)) { + return engine->undefinedValue(); + } + + const int edge = context->argument(0).toVariant().toInt(); + QHash >::iterator it = script->screenEdgeCallbacks().find(edge); + if (it == script->screenEdgeCallbacks().end()) { + //not previously registered + return engine->newVariant(false); + } + ScreenEdges::self()->unreserve(static_cast(edge), script); + script->screenEdgeCallbacks().erase(it); + return engine->newVariant(true); +} + template QScriptValue registerUserActionsMenu(QScriptContext *context, QScriptEngine *engine) { @@ -271,6 +296,13 @@ inline void registerScreenEdgeFunction(QObject *parent, QScriptEngine *engine, Q engine->globalObject().setProperty(QStringLiteral("registerScreenEdge"), shortcutFunc); } +inline void unregisterScreenEdgeFunction(QObject *parent, QScriptEngine *engine, QScriptEngine::FunctionSignature function) +{ + QScriptValue shortcutFunc = engine->newFunction(function); + shortcutFunc.setData(engine->newQObject(parent)); + engine->globalObject().setProperty(QStringLiteral("unregisterScreenEdge"), shortcutFunc); +} + inline void regesterUserActionsMenuFunction(QObject *parent, QScriptEngine *engine, QScriptEngine::FunctionSignature function) { QScriptValue shortcutFunc = engine->newFunction(function);