scripting: Port Script to QJSEngine
QtScript is not well maintained and deprecated in favor of QJSEngine.icc-effect-5.26.4
parent
28d2650f24
commit
566d4aa27b
|
@ -1 +1 @@
|
|||
registerScreenEdge(readConfig("Edge", 1), function() { workspace.slotToggleShowDesktop(); });
|
||||
registerScreenEdge(readConfig("Edge", 1), () => workspace.slotToggleShowDesktop());
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
function init() {
|
||||
var edge = readConfig("Edge", 1);
|
||||
let edge = readConfig("Edge", 1);
|
||||
if (readConfig("mode", "") == "unregister") {
|
||||
unregisterScreenEdge(edge);
|
||||
} else {
|
||||
registerScreenEdge(edge, function() { workspace.slotToggleShowDesktop(); });
|
||||
registerScreenEdge(edge, () => workspace.slotToggleShowDesktop());
|
||||
}
|
||||
}
|
||||
options.configChanged.connect(init);
|
||||
|
|
|
@ -1 +1 @@
|
|||
registerTouchScreenEdge(readConfig("Edge", 1), function() { workspace.slotToggleShowDesktop(); });
|
||||
registerTouchScreenEdge(readConfig("Edge", 1), () => workspace.slotToggleShowDesktop());
|
||||
|
|
|
@ -106,7 +106,6 @@ set(kwin_SRCS
|
|||
scripting/scripting_logging.cpp
|
||||
scripting/scripting_model.cpp
|
||||
scripting/scriptingutils.cpp
|
||||
scripting/timer.cpp
|
||||
scripting/workspace_wrapper.cpp
|
||||
shadow.cpp
|
||||
sm.cpp
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "dbuscall.h"
|
||||
#include "scriptingutils.h"
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
|
@ -35,7 +36,11 @@ void DBusCall::call()
|
|||
emit failed();
|
||||
return;
|
||||
}
|
||||
emit finished(watcher->reply().arguments());
|
||||
QVariantList reply = watcher->reply().arguments();
|
||||
std::for_each(reply.begin(), reply.end(), [](QVariant &variant) {
|
||||
variant = dbusToVariant(variant);
|
||||
});
|
||||
emit finished(reply);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
*/
|
||||
|
||||
#include "meta.h"
|
||||
#include "x11client.h"
|
||||
|
||||
#include <QRect>
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
using namespace KWin::MetaScripting;
|
||||
|
@ -85,161 +85,12 @@ void Rect::fromScriptValue(const QScriptValue& obj, QRect &rect)
|
|||
}
|
||||
// End of meta for QRect object
|
||||
|
||||
QScriptValue AbstractClient::toScriptValue(QScriptEngine *engine, const KAbstractClientRef &client)
|
||||
{
|
||||
return engine->newQObject(client, QScriptEngine::QtOwnership,
|
||||
QScriptEngine::ExcludeChildObjects |
|
||||
QScriptEngine::ExcludeDeleteLater |
|
||||
QScriptEngine::PreferExistingWrapperObject |
|
||||
QScriptEngine::AutoCreateDynamicProperties);
|
||||
}
|
||||
|
||||
void AbstractClient::fromScriptValue(const QScriptValue &value, KWin::AbstractClient *&client)
|
||||
{
|
||||
client = qobject_cast<KWin::AbstractClient *>(value.toQObject());
|
||||
}
|
||||
|
||||
QScriptValue X11Client::toScriptValue(QScriptEngine *eng, const KClientRef &client)
|
||||
{
|
||||
return eng->newQObject(client, QScriptEngine::QtOwnership,
|
||||
QScriptEngine::ExcludeChildObjects |
|
||||
QScriptEngine::ExcludeDeleteLater |
|
||||
QScriptEngine::PreferExistingWrapperObject |
|
||||
QScriptEngine::AutoCreateDynamicProperties);
|
||||
}
|
||||
|
||||
void X11Client::fromScriptValue(const QScriptValue &value, KWin::X11Client *&client)
|
||||
{
|
||||
client = qobject_cast<KWin::X11Client *>(value.toQObject());
|
||||
}
|
||||
|
||||
QScriptValue Toplevel::toScriptValue(QScriptEngine *eng, const KToplevelRef &client)
|
||||
{
|
||||
return eng->newQObject(client, QScriptEngine::QtOwnership,
|
||||
QScriptEngine::ExcludeChildObjects |
|
||||
QScriptEngine::ExcludeDeleteLater |
|
||||
QScriptEngine::PreferExistingWrapperObject |
|
||||
QScriptEngine::AutoCreateDynamicProperties);
|
||||
}
|
||||
|
||||
void Toplevel::fromScriptValue(const QScriptValue &value, KToplevelRef &client)
|
||||
{
|
||||
client = qobject_cast<KWin::Toplevel*>(value.toQObject());
|
||||
}
|
||||
|
||||
// Other helper functions
|
||||
void KWin::MetaScripting::registration(QScriptEngine* eng)
|
||||
{
|
||||
qScriptRegisterMetaType<QPoint>(eng, Point::toScriptValue, Point::fromScriptValue);
|
||||
qScriptRegisterMetaType<QSize>(eng, Size::toScriptValue, Size::fromScriptValue);
|
||||
qScriptRegisterMetaType<QRect>(eng, Rect::toScriptValue, Rect::fromScriptValue);
|
||||
qScriptRegisterMetaType<KAbstractClientRef>(eng, AbstractClient::toScriptValue, AbstractClient::fromScriptValue);
|
||||
qScriptRegisterMetaType<KClientRef>(eng, X11Client::toScriptValue, X11Client::fromScriptValue);
|
||||
qScriptRegisterMetaType<KToplevelRef>(eng, Toplevel::toScriptValue, Toplevel::fromScriptValue);
|
||||
|
||||
qScriptRegisterSequenceMetaType<QStringList>(eng);
|
||||
qScriptRegisterSequenceMetaType< QList<KWin::AbstractClient*> >(eng);
|
||||
qScriptRegisterSequenceMetaType< QList<KWin::X11Client *> >(eng);
|
||||
}
|
||||
|
||||
QScriptValue KWin::MetaScripting::configExists(QScriptContext* ctx, QScriptEngine* eng)
|
||||
{
|
||||
QHash<QString, QVariant> scriptConfig = (((ctx->thisObject()).data()).toVariant()).toHash();
|
||||
QVariant val = scriptConfig.value((ctx->argument(0)).toString(), QVariant());
|
||||
|
||||
return eng->toScriptValue<bool>(val.isValid());
|
||||
}
|
||||
|
||||
QScriptValue KWin::MetaScripting::getConfigValue(QScriptContext* ctx, QScriptEngine* eng)
|
||||
{
|
||||
int num = ctx->argumentCount();
|
||||
QHash<QString, QVariant> scriptConfig = (((ctx->thisObject()).data()).toVariant()).toHash();
|
||||
|
||||
/*
|
||||
* Handle config.get() separately. Compute and return immediately.
|
||||
*/
|
||||
if (num == 0) {
|
||||
QHash<QString, QVariant>::const_iterator i;
|
||||
QScriptValue ret = eng->newArray();
|
||||
|
||||
for (i = scriptConfig.constBegin(); i != scriptConfig.constEnd(); ++i) {
|
||||
ret.setProperty(i.key(), eng->newVariant(i.value()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((num == 1) && !((ctx->argument(0)).isArray())) {
|
||||
QVariant val = scriptConfig.value((ctx->argument(0)).toString(), QVariant());
|
||||
|
||||
if (val.isValid()) {
|
||||
return eng->newVariant(val);
|
||||
} else {
|
||||
return QScriptValue();
|
||||
}
|
||||
} else {
|
||||
QScriptValue ret = eng->newArray();
|
||||
int j = 0;
|
||||
|
||||
if ((ctx->argument(0)).isArray()) {
|
||||
bool simple = (num == 1) ? 0 : (ctx->argument(1)).toBool();
|
||||
QScriptValue array = (ctx->argument(0));
|
||||
int len = (array.property(QStringLiteral("length")).isValid()) ? array.property(QStringLiteral("length")).toNumber() : 0;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
QVariant val = scriptConfig.value(array.property(i).toString(), QVariant());
|
||||
|
||||
if (val.isValid()) {
|
||||
if (simple) {
|
||||
ret.setProperty(j, eng->newVariant(val));
|
||||
} else {
|
||||
ret.setProperty(array.property(i).toString(), eng->newVariant(val));
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < num; i++) {
|
||||
QVariant val = scriptConfig.value((ctx->argument(i)).toString(), QVariant());
|
||||
|
||||
if (val.isValid()) {
|
||||
ret.setProperty((ctx->argument(i)).toString(), eng->newVariant(val));
|
||||
j = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (j == 0) {
|
||||
return QScriptValue();
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KWin::MetaScripting::supplyConfig(QScriptEngine* eng, const QVariant& scriptConfig)
|
||||
{
|
||||
QScriptValue configObject = eng->newObject();
|
||||
configObject.setData(eng->newVariant(scriptConfig));
|
||||
configObject.setProperty(QStringLiteral("get"), eng->newFunction(getConfigValue, 0), QScriptValue::Undeletable);
|
||||
configObject.setProperty(QStringLiteral("exists"), eng->newFunction(configExists, 0), QScriptValue::Undeletable);
|
||||
configObject.setProperty(QStringLiteral("loaded"), ((scriptConfig.toHash().empty()) ? eng->newVariant((bool)0) : eng->newVariant((bool)1)), QScriptValue::Undeletable);
|
||||
(eng->globalObject()).setProperty(QStringLiteral("config"), configObject);
|
||||
}
|
||||
|
||||
void KWin::MetaScripting::supplyConfig(QScriptEngine* eng)
|
||||
{
|
||||
KWin::MetaScripting::supplyConfig(eng, QVariant(QHash<QString, QVariant>()));
|
||||
}
|
||||
|
||||
void KWin::MetaScripting::valueMerge(QScriptValue& first, QScriptValue second)
|
||||
{
|
||||
QScriptValueIterator value_it(second);
|
||||
|
||||
while (value_it.hasNext()) {
|
||||
value_it.next();
|
||||
first.setProperty(value_it.name(), value_it.value());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,19 +15,8 @@
|
|||
// forward declarations
|
||||
class QPoint;
|
||||
class QRect;
|
||||
class QScriptContext;
|
||||
class QSize;
|
||||
|
||||
namespace KWin {
|
||||
class AbstractClient;
|
||||
class Toplevel;
|
||||
class X11Client;
|
||||
}
|
||||
|
||||
typedef KWin::AbstractClient *KAbstractClientRef;
|
||||
typedef KWin::X11Client *KClientRef;
|
||||
typedef KWin::Toplevel* KToplevelRef;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
namespace MetaScripting
|
||||
|
@ -66,59 +55,12 @@ QScriptValue toScriptValue(QScriptEngine*, const QRect&);
|
|||
void fromScriptValue(const QScriptValue&, QRect&);
|
||||
}
|
||||
|
||||
namespace AbstractClient
|
||||
{
|
||||
QScriptValue toScriptValue(QScriptEngine *engine, const KAbstractClientRef &client);
|
||||
void fromScriptValue(const QScriptValue &value, KAbstractClientRef &client);
|
||||
}
|
||||
|
||||
namespace X11Client
|
||||
{
|
||||
QScriptValue toScriptValue(QScriptEngine *eng, const KClientRef &client);
|
||||
void fromScriptValue(const QScriptValue &value, KClientRef& client);
|
||||
}
|
||||
|
||||
namespace Toplevel
|
||||
{
|
||||
QScriptValue toScriptValue(QScriptEngine *eng, const KToplevelRef &client);
|
||||
void fromScriptValue(const QScriptValue &value, KToplevelRef& client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the second QScriptValue in the first one.
|
||||
*/
|
||||
void valueMerge(QScriptValue&, QScriptValue);
|
||||
|
||||
/**
|
||||
* Registers all the meta conversion to the provided QScriptEngine
|
||||
*/
|
||||
void registration(QScriptEngine* eng);
|
||||
|
||||
/**
|
||||
* Functions for the JS function objects, config.exists and config.get.
|
||||
* Read scripting/IMPLIST for details on how they work
|
||||
*/
|
||||
QScriptValue configExists(QScriptContext*, QScriptEngine*);
|
||||
QScriptValue getConfigValue(QScriptContext*, QScriptEngine*);
|
||||
|
||||
/**
|
||||
* Provide a config object to the given QScriptEngine depending
|
||||
* on the keys provided in the QVariant. The provided QVariant
|
||||
* MUST returns (true) on isHash()
|
||||
*/
|
||||
void supplyConfig(QScriptEngine*, const QVariant&);
|
||||
|
||||
/**
|
||||
* For engines whose scripts have no associated configuration.
|
||||
*/
|
||||
void supplyConfig(QScriptEngine*);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Code linked from plasma for QTimer.
|
||||
*/
|
||||
QScriptValue constructTimerClass(QScriptEngine *eng);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
SPDX-FileCopyrightText: 2010 Rohan Prabhu <rohan@rohanprabhu.com>
|
||||
SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
@ -11,7 +12,6 @@
|
|||
#include "scripting.h"
|
||||
// own
|
||||
#include "dbuscall.h"
|
||||
#include "meta.h"
|
||||
#include "scriptingutils.h"
|
||||
#include "workspace_wrapper.h"
|
||||
#include "screenedgeitem.h"
|
||||
|
@ -36,184 +36,27 @@
|
|||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlExpression>
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtScript/QScriptValue>
|
||||
#include <QStandardPaths>
|
||||
#include <QQuickWindow>
|
||||
|
||||
QScriptValue kwinScriptPrint(QScriptContext *context, QScriptEngine *engine)
|
||||
static QRect scriptValueToRect(const QJSValue &value)
|
||||
{
|
||||
KWin::AbstractScript *script = qobject_cast<KWin::Script*>(context->callee().data().toQObject());
|
||||
if (!script) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
QString result;
|
||||
QTextStream stream(&result);
|
||||
for (int i = 0; i < context->argumentCount(); ++i) {
|
||||
if (i > 0) {
|
||||
stream << " ";
|
||||
}
|
||||
QScriptValue argument = context->argument(i);
|
||||
if (KWin::AbstractClient *client = qscriptvalue_cast<KWin::AbstractClient *>(argument)) {
|
||||
stream << client;
|
||||
} else {
|
||||
stream << argument.toString();
|
||||
}
|
||||
}
|
||||
script->printMessage(result);
|
||||
|
||||
return engine->undefinedValue();
|
||||
return QRect(value.property(QStringLiteral("x")).toInt(),
|
||||
value.property(QStringLiteral("y")).toInt(),
|
||||
value.property(QStringLiteral("width")).toInt(),
|
||||
value.property(QStringLiteral("height")).toInt());
|
||||
}
|
||||
|
||||
QScriptValue kwinScriptReadConfig(QScriptContext *context, QScriptEngine *engine)
|
||||
static QPoint scriptValueToPoint(const QJSValue &value)
|
||||
{
|
||||
KWin::AbstractScript *script = qobject_cast<KWin::AbstractScript*>(context->callee().data().toQObject());
|
||||
if (!script) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (context->argumentCount() < 1 || context->argumentCount() > 2) {
|
||||
qCDebug(KWIN_SCRIPTING) << "Incorrect number of arguments";
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
const QString key = context->argument(0).toString();
|
||||
QVariant defaultValue;
|
||||
if (context->argumentCount() == 2) {
|
||||
defaultValue = context->argument(1).toVariant();
|
||||
}
|
||||
return engine->newVariant(script->config().readEntry(key, defaultValue));
|
||||
return QPoint(value.property(QStringLiteral("x")).toInt(),
|
||||
value.property(QStringLiteral("y")).toInt());
|
||||
}
|
||||
|
||||
QScriptValue kwinScriptGlobalShortcut(QScriptContext *context, QScriptEngine *engine)
|
||||
static QSize scriptValueToSize(const QJSValue &value)
|
||||
{
|
||||
return KWin::globalShortcut<KWin::AbstractScript*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue kwinAssertTrue(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::scriptingAssert<bool>(context, engine, 1, 2, true);
|
||||
}
|
||||
|
||||
QScriptValue kwinAssertFalse(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::scriptingAssert<bool>(context, engine, 1, 2, false);
|
||||
}
|
||||
|
||||
QScriptValue kwinAssertEquals(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::scriptingAssert<QVariant>(context, engine, 2, 3);
|
||||
}
|
||||
|
||||
QScriptValue kwinAssertNull(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
if (!KWin::validateParameters(context, 1, 2)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!context->argument(0).isNull()) {
|
||||
if (context->argumentCount() == 2) {
|
||||
context->throwError(QScriptContext::UnknownError, context->argument(1).toString());
|
||||
} else {
|
||||
context->throwError(QScriptContext::UnknownError,
|
||||
i18nc("Assertion failed in KWin script with given value",
|
||||
"Assertion failed: %1 is not null", context->argument(0).toString()));
|
||||
}
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QScriptValue kwinAssertNotNull(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
if (!KWin::validateParameters(context, 1, 2)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (context->argument(0).isNull()) {
|
||||
if (context->argumentCount() == 2) {
|
||||
context->throwError(QScriptContext::UnknownError, context->argument(1).toString());
|
||||
} else {
|
||||
context->throwError(QScriptContext::UnknownError,
|
||||
i18nc("Assertion failed in KWin script",
|
||||
"Assertion failed: argument is null"));
|
||||
}
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QScriptValue kwinRegisterScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::registerScreenEdge<KWin::AbstractScript*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue kwinUnregisterScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::unregisterScreenEdge<KWin::AbstractScript*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue kwinRegisterTouchScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::registerTouchScreenEdge<KWin::Script*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue kwinUnregisterTouchScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::unregisterTouchScreenEdge<KWin::Script*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue kwinRegisterUserActionsMenu(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
return KWin::registerUserActionsMenu<KWin::AbstractScript*>(context, engine);
|
||||
}
|
||||
|
||||
QScriptValue kwinCallDBus(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
KWin::AbstractScript *script = qobject_cast<KWin::AbstractScript*>(context->callee().data().toQObject());
|
||||
if (!script) {
|
||||
context->throwError(QScriptContext::UnknownError, QStringLiteral("Internal Error: script not registered"));
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (context->argumentCount() < 4) {
|
||||
context->throwError(QScriptContext::SyntaxError,
|
||||
i18nc("Error in KWin Script",
|
||||
"Invalid number of arguments. At least service, path, interface and method need to be provided"));
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!KWin::validateArgumentType<QString, QString, QString, QString>(context)) {
|
||||
context->throwError(QScriptContext::SyntaxError,
|
||||
i18nc("Error in KWin Script",
|
||||
"Invalid type. Service, path, interface and method need to be string values"));
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
const QString service = context->argument(0).toString();
|
||||
const QString path = context->argument(1).toString();
|
||||
const QString interface = context->argument(2).toString();
|
||||
const QString method = context->argument(3).toString();
|
||||
int argumentsCount = context->argumentCount();
|
||||
if (context->argument(argumentsCount-1).isFunction()) {
|
||||
--argumentsCount;
|
||||
}
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(service, path, interface, method);
|
||||
QVariantList arguments;
|
||||
for (int i=4; i<argumentsCount; ++i) {
|
||||
if (context->argument(i).isArray()) {
|
||||
QStringList stringArray = engine->fromScriptValue<QStringList>(context->argument(i));
|
||||
arguments << QVariant::fromValue(stringArray);
|
||||
} else {
|
||||
arguments << context->argument(i).toVariant();
|
||||
}
|
||||
}
|
||||
if (!arguments.isEmpty()) {
|
||||
msg.setArguments(arguments);
|
||||
}
|
||||
if (argumentsCount == context->argumentCount()) {
|
||||
// no callback, just fire and forget
|
||||
QDBusConnection::sessionBus().asyncCall(msg);
|
||||
} else {
|
||||
// with a callback
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(msg), script);
|
||||
watcher->setProperty("callback", script->registerCallback(context->argument(context->argumentCount()-1)));
|
||||
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, script, &KWin::AbstractScript::slotPendingDBusCall);
|
||||
}
|
||||
return engine->undefinedValue();
|
||||
return QSize(value.property(QStringLiteral("width")).toInt(),
|
||||
value.property(QStringLiteral("height")).toInt());
|
||||
}
|
||||
|
||||
KWin::AbstractScript::AbstractScript(int id, QString scriptName, QString pluginName, QObject *parent)
|
||||
|
@ -242,205 +85,24 @@ void KWin::AbstractScript::stop()
|
|||
deleteLater();
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::printMessage(const QString &message)
|
||||
{
|
||||
qCDebug(KWIN_SCRIPTING) << fileName() << ":" << message;
|
||||
emit print(message);
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::registerShortcut(QAction *a, QScriptValue callback)
|
||||
{
|
||||
m_shortcutCallbacks.insert(a, callback);
|
||||
connect(a, &QAction::triggered, this, &AbstractScript::globalShortcutTriggered);
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::globalShortcutTriggered()
|
||||
{
|
||||
callGlobalShortcutCallback<KWin::AbstractScript*>(this, sender());
|
||||
}
|
||||
|
||||
bool KWin::AbstractScript::borderActivated(KWin::ElectricBorder edge)
|
||||
{
|
||||
screenEdgeActivated(this, edge);
|
||||
return true;
|
||||
}
|
||||
|
||||
void KWin::Script::installScriptFunctions(QScriptEngine* engine)
|
||||
{
|
||||
// add our print
|
||||
QScriptValue printFunc = engine->newFunction(kwinScriptPrint);
|
||||
printFunc.setData(engine->newQObject(this));
|
||||
engine->globalObject().setProperty(QStringLiteral("print"), printFunc);
|
||||
// add read config
|
||||
QScriptValue configFunc = engine->newFunction(kwinScriptReadConfig);
|
||||
configFunc.setData(engine->newQObject(this));
|
||||
engine->globalObject().setProperty(QStringLiteral("readConfig"), configFunc);
|
||||
QScriptValue dbusCallFunc = engine->newFunction(kwinCallDBus);
|
||||
dbusCallFunc.setData(engine->newQObject(this));
|
||||
engine->globalObject().setProperty(QStringLiteral("callDBus"), dbusCallFunc);
|
||||
// add global Shortcut
|
||||
registerGlobalShortcutFunction(this, engine, kwinScriptGlobalShortcut);
|
||||
// add screen edge
|
||||
registerScreenEdgeFunction(this, engine, kwinRegisterScreenEdge);
|
||||
unregisterScreenEdgeFunction(this, engine, kwinUnregisterScreenEdge);
|
||||
registerTouchScreenEdgeFunction(this, engine, kwinRegisterTouchScreenEdge);
|
||||
unregisterTouchScreenEdgeFunction(this, engine, kwinUnregisterTouchScreenEdge);
|
||||
|
||||
// add user actions menu register function
|
||||
registerUserActionsMenuFunction(this, engine, kwinRegisterUserActionsMenu);
|
||||
// add assertions
|
||||
QScriptValue assertTrueFunc = engine->newFunction(kwinAssertTrue);
|
||||
engine->globalObject().setProperty(QStringLiteral("assertTrue"), assertTrueFunc);
|
||||
engine->globalObject().setProperty(QStringLiteral("assert"), assertTrueFunc);
|
||||
QScriptValue assertFalseFunc = engine->newFunction(kwinAssertFalse);
|
||||
engine->globalObject().setProperty(QStringLiteral("assertFalse"), assertFalseFunc);
|
||||
QScriptValue assertEqualsFunc = engine->newFunction(kwinAssertEquals);
|
||||
engine->globalObject().setProperty(QStringLiteral("assertEquals"), assertEqualsFunc);
|
||||
QScriptValue assertNullFunc = engine->newFunction(kwinAssertNull);
|
||||
engine->globalObject().setProperty(QStringLiteral("assertNull"), assertNullFunc);
|
||||
engine->globalObject().setProperty(QStringLiteral("assertEquals"), assertEqualsFunc);
|
||||
QScriptValue assertNotNullFunc = engine->newFunction(kwinAssertNotNull);
|
||||
engine->globalObject().setProperty(QStringLiteral("assertNotNull"), assertNotNullFunc);
|
||||
// global properties
|
||||
engine->globalObject().setProperty(QStringLiteral("KWin"), engine->newQMetaObject(&QtScriptWorkspaceWrapper::staticMetaObject));
|
||||
QScriptValue workspace = engine->newQObject(Scripting::self()->workspaceWrapper(), QScriptEngine::QtOwnership,
|
||||
QScriptEngine::ExcludeDeleteLater);
|
||||
engine->globalObject().setProperty(QStringLiteral("workspace"), workspace, QScriptValue::Undeletable);
|
||||
// install meta functions
|
||||
KWin::MetaScripting::registration(engine);
|
||||
}
|
||||
|
||||
int KWin::AbstractScript::registerCallback(QScriptValue value)
|
||||
{
|
||||
int id = m_callbacks.size();
|
||||
m_callbacks.insert(id, value);
|
||||
return id;
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::slotPendingDBusCall(QDBusPendingCallWatcher* watcher)
|
||||
{
|
||||
if (watcher->isError()) {
|
||||
qCDebug(KWIN_SCRIPTING) << "Received D-Bus message is error";
|
||||
watcher->deleteLater();
|
||||
return;
|
||||
}
|
||||
const int id = watcher->property("callback").toInt();
|
||||
QDBusMessage reply = watcher->reply();
|
||||
QScriptValue callback (m_callbacks.value(id));
|
||||
QScriptValueList arguments;
|
||||
foreach (const QVariant &argument, reply.arguments()) {
|
||||
arguments << callback.engine()->newVariant(argument);
|
||||
}
|
||||
callback.call(QScriptValue(), arguments);
|
||||
m_callbacks.remove(id);
|
||||
watcher->deleteLater();
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::registerUseractionsMenuCallback(QScriptValue callback)
|
||||
{
|
||||
m_userActionsMenuCallbacks.append(callback);
|
||||
}
|
||||
|
||||
QList< QAction * > KWin::AbstractScript::actionsForUserActionMenu(KWin::AbstractClient *c, QMenu *parent)
|
||||
{
|
||||
QList<QAction*> returnActions;
|
||||
for (QList<QScriptValue>::const_iterator it = m_userActionsMenuCallbacks.constBegin(); it != m_userActionsMenuCallbacks.constEnd(); ++it) {
|
||||
QScriptValue callback(*it);
|
||||
QScriptValueList arguments;
|
||||
arguments << callback.engine()->newQObject(c);
|
||||
QScriptValue actions = callback.call(QScriptValue(), arguments);
|
||||
if (!actions.isValid() || actions.isUndefined() || actions.isNull()) {
|
||||
// script does not want to handle this Client
|
||||
continue;
|
||||
}
|
||||
if (actions.isObject()) {
|
||||
QAction *a = scriptValueToAction(actions, parent);
|
||||
if (a) {
|
||||
returnActions << a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnActions;
|
||||
}
|
||||
|
||||
QAction *KWin::AbstractScript::scriptValueToAction(QScriptValue &value, QMenu *parent)
|
||||
{
|
||||
QScriptValue titleValue = value.property(QStringLiteral("text"));
|
||||
QScriptValue checkableValue = value.property(QStringLiteral("checkable"));
|
||||
QScriptValue checkedValue = value.property(QStringLiteral("checked"));
|
||||
QScriptValue itemsValue = value.property(QStringLiteral("items"));
|
||||
QScriptValue triggeredValue = value.property(QStringLiteral("triggered"));
|
||||
|
||||
if (!titleValue.isValid()) {
|
||||
// title not specified - does not make any sense to include
|
||||
return nullptr;
|
||||
}
|
||||
const QString title = titleValue.toString();
|
||||
const bool checkable = checkableValue.isValid() && checkableValue.toBool();
|
||||
const bool checked = checkable && checkedValue.isValid() && checkedValue.toBool();
|
||||
// either a menu or a menu item
|
||||
if (itemsValue.isValid()) {
|
||||
if (!itemsValue.isArray()) {
|
||||
// not an array, so cannot be a menu
|
||||
return nullptr;
|
||||
}
|
||||
QScriptValue lengthValue = itemsValue.property(QStringLiteral("length"));
|
||||
if (!lengthValue.isValid() || !lengthValue.isNumber() || lengthValue.toInteger() == 0) {
|
||||
// length property missing
|
||||
return nullptr;
|
||||
}
|
||||
return createMenu(title, itemsValue, parent);
|
||||
} else if (triggeredValue.isValid()) {
|
||||
// normal item
|
||||
return createAction(title, checkable, checked, triggeredValue, parent);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QAction *KWin::AbstractScript::createAction(const QString &title, bool checkable, bool checked, QScriptValue &callback, QMenu *parent)
|
||||
{
|
||||
QAction *action = new QAction(title, parent);
|
||||
action->setCheckable(checkable);
|
||||
action->setChecked(checked);
|
||||
// TODO: rename m_shortcutCallbacks
|
||||
m_shortcutCallbacks.insert(action, callback);
|
||||
connect(action, &QAction::triggered, this, &AbstractScript::globalShortcutTriggered);
|
||||
connect(action, &QObject::destroyed, this, &AbstractScript::actionDestroyed);
|
||||
return action;
|
||||
}
|
||||
|
||||
QAction *KWin::AbstractScript::createMenu(const QString &title, QScriptValue &items, QMenu *parent)
|
||||
{
|
||||
QMenu *menu = new QMenu(title, parent);
|
||||
const int length = static_cast<int>(items.property(QStringLiteral("length")).toInteger());
|
||||
for (int i=0; i<length; ++i) {
|
||||
QScriptValue value = items.property(QString::number(i));
|
||||
if (!value.isValid()) {
|
||||
continue;
|
||||
}
|
||||
if (value.isObject()) {
|
||||
QAction *a = scriptValueToAction(value, menu);
|
||||
if (a) {
|
||||
menu->addAction(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return menu->menuAction();
|
||||
}
|
||||
|
||||
void KWin::AbstractScript::actionDestroyed(QObject *object)
|
||||
{
|
||||
// TODO: Qt 5 - change to lambda function
|
||||
m_shortcutCallbacks.remove(static_cast<QAction*>(object));
|
||||
}
|
||||
|
||||
KWin::Script::Script(int id, QString scriptName, QString pluginName, QObject* parent)
|
||||
: AbstractScript(id, scriptName, pluginName, parent)
|
||||
, m_engine(new QScriptEngine(this))
|
||||
, m_engine(new QJSEngine(this))
|
||||
, m_starting(false)
|
||||
, m_agent(new ScriptUnloaderAgent(this))
|
||||
{
|
||||
// TODO: Remove in kwin 6. We have these converters only for compatibility reasons.
|
||||
if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QRect>()) {
|
||||
QMetaType::registerConverter<QJSValue, QRect>(scriptValueToRect);
|
||||
}
|
||||
if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QPoint>()) {
|
||||
QMetaType::registerConverter<QJSValue, QPoint>(scriptValueToPoint);
|
||||
}
|
||||
if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QSize>()) {
|
||||
QMetaType::registerConverter<QJSValue, QSize>(scriptValueToSize);
|
||||
}
|
||||
|
||||
qRegisterMetaType<QList<KWin::AbstractClient *>>();
|
||||
|
||||
QDBusConnection::sessionBus().registerObject(QLatin1Char('/') + QString::number(scriptId()), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables);
|
||||
}
|
||||
|
||||
|
@ -497,18 +159,74 @@ void KWin::Script::slotScriptLoadedFromFile()
|
|||
return;
|
||||
}
|
||||
|
||||
QScriptValue optionsValue = m_engine->newQObject(options, QScriptEngine::QtOwnership,
|
||||
QScriptEngine::ExcludeSuperClassContents | QScriptEngine::ExcludeDeleteLater);
|
||||
m_engine->globalObject().setProperty(QStringLiteral("options"), optionsValue, QScriptValue::Undeletable);
|
||||
m_engine->globalObject().setProperty(QStringLiteral("QTimer"), constructTimerClass(m_engine));
|
||||
QObject::connect(m_engine, &QScriptEngine::signalHandlerException, this, &Script::sigException);
|
||||
KWin::MetaScripting::supplyConfig(m_engine);
|
||||
installScriptFunctions(m_engine);
|
||||
// Install console functions (e.g. console.assert(), console.log(), etc).
|
||||
m_engine->installExtensions(QJSEngine::ConsoleExtension);
|
||||
|
||||
QScriptValue ret = m_engine->evaluate(QString::fromUtf8(watcher->result()));
|
||||
// Make the timer visible to QJSEngine.
|
||||
QJSValue timerMetaObject = m_engine->newQMetaObject(&QTimer::staticMetaObject);
|
||||
m_engine->globalObject().setProperty("QTimer", timerMetaObject);
|
||||
|
||||
if (ret.isError()) {
|
||||
sigException(ret);
|
||||
// Expose enums.
|
||||
m_engine->globalObject().setProperty(QStringLiteral("KWin"), m_engine->newQMetaObject(&QtScriptWorkspaceWrapper::staticMetaObject));
|
||||
|
||||
// Make the options object visible to QJSEngine.
|
||||
QJSValue optionsObject = m_engine->newQObject(options);
|
||||
QQmlEngine::setObjectOwnership(options, QQmlEngine::CppOwnership);
|
||||
m_engine->globalObject().setProperty(QStringLiteral("options"), optionsObject);
|
||||
|
||||
// Make the workspace visible to QJSEngine.
|
||||
QJSValue workspaceObject = m_engine->newQObject(Scripting::self()->workspaceWrapper());
|
||||
QQmlEngine::setObjectOwnership(Scripting::self()->workspaceWrapper(), QQmlEngine::CppOwnership);
|
||||
m_engine->globalObject().setProperty(QStringLiteral("workspace"), workspaceObject);
|
||||
|
||||
QJSValue self = m_engine->newQObject(this);
|
||||
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
|
||||
static const QStringList globalProperties {
|
||||
QStringLiteral("readConfig"),
|
||||
QStringLiteral("callDBus"),
|
||||
|
||||
QStringLiteral("registerShortcut"),
|
||||
QStringLiteral("registerScreenEdge"),
|
||||
QStringLiteral("unregisterScreenEdge"),
|
||||
QStringLiteral("registerTouchScreenEdge"),
|
||||
QStringLiteral("unregisterTouchScreenEdge"),
|
||||
QStringLiteral("registerUserActionsMenu"),
|
||||
};
|
||||
|
||||
for (const QString &propertyName : globalProperties) {
|
||||
m_engine->globalObject().setProperty(propertyName, self.property(propertyName));
|
||||
}
|
||||
|
||||
// Inject assertion functions. It would be better to create a module with all
|
||||
// this assert functions or just deprecate them in favor of console.assert().
|
||||
QJSValue result = m_engine->evaluate(QStringLiteral(R"(
|
||||
function assert(condition, message) {
|
||||
console.assert(condition, message || 'Assertion failed');
|
||||
}
|
||||
function assertTrue(condition, message) {
|
||||
console.assert(condition, message || 'Assertion failed');
|
||||
}
|
||||
function assertFalse(condition, message) {
|
||||
console.assert(!condition, message || 'Assertion failed');
|
||||
}
|
||||
function assertNull(value, message) {
|
||||
console.assert(value === null, message || 'Assertion failed');
|
||||
}
|
||||
function assertNotNull(value, message) {
|
||||
console.assert(value !== null, message || 'Assertion failed');
|
||||
}
|
||||
function assertEquals(expected, actual, message) {
|
||||
console.assert(expected === actual, message || 'Assertion failed');
|
||||
}
|
||||
)"));
|
||||
Q_ASSERT(!result.isError());
|
||||
|
||||
result = m_engine->evaluate(QString::fromUtf8(watcher->result()), fileName());
|
||||
if (result.isError()) {
|
||||
qCWarning(KWIN_SCRIPTING, "%s:%d: error: %s", qPrintable(fileName()),
|
||||
result.property(QStringLiteral("lineNumber")).toInt(),
|
||||
qPrintable(result.property(QStringLiteral("message")).toString()));
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
@ -523,63 +241,274 @@ void KWin::Script::slotScriptLoadedFromFile()
|
|||
m_starting = false;
|
||||
}
|
||||
|
||||
void KWin::Script::sigException(const QScriptValue& exception)
|
||||
QVariant KWin::Script::readConfig(const QString &key, const QVariant &defaultValue)
|
||||
{
|
||||
QScriptValue ret = exception;
|
||||
if (ret.isError()) {
|
||||
qCDebug(KWIN_SCRIPTING) << "defaultscript encountered an error at [Line " << m_engine->uncaughtExceptionLineNumber() << "]";
|
||||
qCDebug(KWIN_SCRIPTING) << "Message: " << ret.toString();
|
||||
qCDebug(KWIN_SCRIPTING) << "-----------------";
|
||||
|
||||
QScriptValueIterator iter(ret);
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
qCDebug(KWIN_SCRIPTING) << " " << iter.name() << ": " << iter.value().toString();
|
||||
}
|
||||
}
|
||||
emit printError(exception.toString());
|
||||
stop();
|
||||
return config().readEntry(key, defaultValue);
|
||||
}
|
||||
|
||||
bool KWin::Script::registerTouchScreenCallback(int edge, QScriptValue callback)
|
||||
void KWin::Script::callDBus(const QString &service, const QString &path, const QString &interface,
|
||||
const QString &method, const QJSValue &arg1, const QJSValue &arg2,
|
||||
const QJSValue &arg3, const QJSValue &arg4, const QJSValue &arg5,
|
||||
const QJSValue &arg6, const QJSValue &arg7, const QJSValue &arg8,
|
||||
const QJSValue &arg9)
|
||||
{
|
||||
if (m_touchScreenEdgeCallbacks.constFind(edge) != m_touchScreenEdgeCallbacks.constEnd()) {
|
||||
QJSValueList jsArguments;
|
||||
jsArguments.reserve(9);
|
||||
|
||||
if (!arg1.isUndefined()) {
|
||||
jsArguments << arg1;
|
||||
}
|
||||
if (!arg2.isUndefined()) {
|
||||
jsArguments << arg2;
|
||||
}
|
||||
if (!arg3.isUndefined()) {
|
||||
jsArguments << arg3;
|
||||
}
|
||||
if (!arg4.isUndefined()) {
|
||||
jsArguments << arg4;
|
||||
}
|
||||
if (!arg5.isUndefined()) {
|
||||
jsArguments << arg5;
|
||||
}
|
||||
if (!arg6.isUndefined()) {
|
||||
jsArguments << arg6;
|
||||
}
|
||||
if (!arg7.isUndefined()) {
|
||||
jsArguments << arg7;
|
||||
}
|
||||
if (!arg8.isUndefined()) {
|
||||
jsArguments << arg8;
|
||||
}
|
||||
if (!arg9.isUndefined()) {
|
||||
jsArguments << arg9;
|
||||
}
|
||||
|
||||
QJSValue callback;
|
||||
if (!jsArguments.isEmpty() && jsArguments.last().isCallable()) {
|
||||
callback = jsArguments.takeLast();
|
||||
}
|
||||
|
||||
QVariantList dbusArguments;
|
||||
dbusArguments.reserve(jsArguments.count());
|
||||
for (const QJSValue &jsArgument : qAsConst(jsArguments)) {
|
||||
dbusArguments << jsArgument.toVariant();
|
||||
}
|
||||
|
||||
QDBusMessage message = QDBusMessage::createMethodCall(service, path, interface, method);
|
||||
message.setArguments(dbusArguments);
|
||||
|
||||
const QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(message);
|
||||
if (callback.isUndefined()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, callback](QDBusPendingCallWatcher *self) {
|
||||
self->deleteLater();
|
||||
|
||||
if (self->isError()) {
|
||||
qCDebug(KWIN_SCRIPTING) << "Received D-Bus message is error";
|
||||
return;
|
||||
}
|
||||
|
||||
QJSValueList arguments;
|
||||
const QVariantList reply = self->reply().arguments();
|
||||
for (const QVariant &variant : reply) {
|
||||
arguments << m_engine->toScriptValue(dbusToVariant(variant));
|
||||
}
|
||||
|
||||
QJSValue(callback).call(arguments);
|
||||
});
|
||||
}
|
||||
|
||||
bool KWin::Script::registerShortcut(const QString &objectName, const QString &text, const QString &keySequence, const QJSValue &callback)
|
||||
{
|
||||
if (!callback.isCallable()) {
|
||||
m_engine->throwError(QStringLiteral("Shortcut handler must be callable"));
|
||||
return false;
|
||||
}
|
||||
|
||||
QAction *action = new QAction(this);
|
||||
connect(action, &QAction::triggered, this,
|
||||
[callback] {
|
||||
QScriptValue invoke(callback);
|
||||
invoke.call();
|
||||
}
|
||||
);
|
||||
ScreenEdges::self()->reserveTouch(KWin::ElectricBorder(edge), action);
|
||||
m_touchScreenEdgeCallbacks.insert(edge, action);
|
||||
action->setObjectName(objectName);
|
||||
action->setText(text);
|
||||
|
||||
const QKeySequence shortcut = keySequence;
|
||||
KGlobalAccel::self()->setShortcut(action, { shortcut });
|
||||
input()->registerShortcut(shortcut, action);
|
||||
|
||||
connect(action, &QAction::triggered, this, [this, action, callback]() {
|
||||
QJSValue(callback).call({ m_engine->toScriptValue(action) });
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KWin::Script::unregisterTouchScreenCallback(int edge)
|
||||
bool KWin::Script::registerScreenEdge(int edge, const QJSValue &callback)
|
||||
{
|
||||
if (!callback.isCallable()) {
|
||||
m_engine->throwError(QStringLiteral("Screen edge handler must be callable"));
|
||||
return false;
|
||||
}
|
||||
|
||||
QJSValueList &callbacks = m_screenEdgeCallbacks[edge];
|
||||
if (callbacks.isEmpty()) {
|
||||
ScreenEdges::self()->reserve(static_cast<KWin::ElectricBorder>(edge), this, "slotBorderActivated");
|
||||
}
|
||||
|
||||
callbacks << callback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KWin::Script::unregisterScreenEdge(int edge)
|
||||
{
|
||||
auto it = m_screenEdgeCallbacks.find(edge);
|
||||
if (it == m_screenEdgeCallbacks.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScreenEdges::self()->unreserve(static_cast<KWin::ElectricBorder>(edge), this);
|
||||
m_screenEdgeCallbacks.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KWin::Script::registerTouchScreenEdge(int edge, const QJSValue &callback)
|
||||
{
|
||||
if (!callback.isCallable()) {
|
||||
m_engine->throwError(QStringLiteral("Touch screen edge handler must be callable"));
|
||||
return false;
|
||||
}
|
||||
if (m_touchScreenEdgeCallbacks.contains(edge)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QAction *action = new QAction(this);
|
||||
ScreenEdges::self()->reserveTouch(KWin::ElectricBorder(edge), action);
|
||||
m_touchScreenEdgeCallbacks.insert(edge, action);
|
||||
|
||||
connect(action, &QAction::triggered, this, [callback]() {
|
||||
QJSValue(callback).call();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KWin::Script::unregisterTouchScreenEdge(int edge)
|
||||
{
|
||||
auto it = m_touchScreenEdgeCallbacks.find(edge);
|
||||
if (it == m_touchScreenEdgeCallbacks.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delete it.value();
|
||||
m_touchScreenEdgeCallbacks.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
KWin::ScriptUnloaderAgent::ScriptUnloaderAgent(KWin::Script *script)
|
||||
: QScriptEngineAgent(script->engine())
|
||||
, m_script(script)
|
||||
void KWin::Script::registerUserActionsMenu(const QJSValue &callback)
|
||||
{
|
||||
script->engine()->setAgent(this);
|
||||
if (!callback.isCallable()) {
|
||||
m_engine->throwError(QStringLiteral("User action handler must be callable"));
|
||||
return;
|
||||
}
|
||||
m_userActionsMenuCallbacks.append(callback);
|
||||
}
|
||||
|
||||
void KWin::ScriptUnloaderAgent::scriptUnload(qint64 id)
|
||||
QList<QAction *> KWin::Script::actionsForUserActionMenu(KWin::AbstractClient *client, QMenu *parent)
|
||||
{
|
||||
Q_UNUSED(id)
|
||||
m_script->stop();
|
||||
QList<QAction *> actions;
|
||||
actions.reserve(m_userActionsMenuCallbacks.count());
|
||||
|
||||
for (QJSValue callback : m_userActionsMenuCallbacks) {
|
||||
QJSValue result = callback.call({ m_engine->toScriptValue(client) });
|
||||
if (result.isError()) {
|
||||
continue;
|
||||
}
|
||||
if (!result.isObject()) {
|
||||
continue;
|
||||
}
|
||||
if (QAction *action = scriptValueToAction(result, parent)) {
|
||||
actions << action;
|
||||
}
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
bool KWin::Script::slotBorderActivated(ElectricBorder border)
|
||||
{
|
||||
const QJSValueList callbacks = m_screenEdgeCallbacks.value(border);
|
||||
if (callbacks.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
std::for_each(callbacks.begin(), callbacks.end(), [](QJSValue callback) {
|
||||
callback.call();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
QAction *KWin::Script::scriptValueToAction(const QJSValue &value, QMenu *parent)
|
||||
{
|
||||
const QString title = value.property(QStringLiteral("text")).toString();
|
||||
if (title.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Either a menu or a menu item.
|
||||
const QJSValue itemsValue = value.property(QStringLiteral("items"));
|
||||
if (!itemsValue.isUndefined()) {
|
||||
return createMenu(title, itemsValue, parent);
|
||||
}
|
||||
|
||||
return createAction(title, value, parent);
|
||||
}
|
||||
|
||||
QAction *KWin::Script::createAction(const QString &title, const QJSValue &item, QMenu *parent)
|
||||
{
|
||||
const QJSValue callback = item.property(QStringLiteral("triggered"));
|
||||
if (!callback.isCallable()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const bool checkable = item.property(QStringLiteral("checkable")).toBool();
|
||||
const bool checked = item.property(QStringLiteral("checked")).toBool();
|
||||
|
||||
QAction *action = new QAction(title, parent);
|
||||
action->setCheckable(checkable);
|
||||
action->setChecked(checked);
|
||||
|
||||
connect(action, &QAction::triggered, this, [this, action, callback]() {
|
||||
QJSValue(callback).call({ m_engine->toScriptValue(action) });
|
||||
});
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
QAction *KWin::Script::createMenu(const QString &title, const QJSValue &items, QMenu *parent)
|
||||
{
|
||||
if (!items.isArray()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int length = items.property(QStringLiteral("length")).toInt();
|
||||
if (!length) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMenu *menu = new QMenu(title, parent);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
const QJSValue value = items.property(QString::number(i));
|
||||
if (!value.isObject()) {
|
||||
continue;
|
||||
}
|
||||
if (QAction *action = scriptValueToAction(value, menu)) {
|
||||
menu->addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
return menu->menuAction();
|
||||
}
|
||||
|
||||
KWin::DeclarativeScript::DeclarativeScript(int id, QString scriptName, QString pluginName, QObject* parent)
|
||||
|
@ -880,8 +809,11 @@ KWin::Scripting::~Scripting()
|
|||
QList< QAction * > KWin::Scripting::actionsForUserActionMenu(KWin::AbstractClient *c, QMenu *parent)
|
||||
{
|
||||
QList<QAction*> actions;
|
||||
foreach (AbstractScript *script, scripts) {
|
||||
actions << script->actionsForUserActionMenu(c, parent);
|
||||
for (AbstractScript *s : scripts) {
|
||||
// TODO: Allow declarative scripts to add their own user actions.
|
||||
if (Script *script = qobject_cast<Script *>(s)) {
|
||||
actions << script->actionsForUserActionMenu(c, parent);
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
SPDX-FileCopyrightText: 2010 Rohan Prabhu <rohan@rohanprabhu.com>
|
||||
SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
@ -13,10 +14,9 @@
|
|||
|
||||
#include <kwinglobals.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QStringList>
|
||||
#include <QtScript/QScriptEngineAgent>
|
||||
#include <QJSEngine>
|
||||
#include <QJSValue>
|
||||
|
||||
#include <QDBusContext>
|
||||
|
@ -26,12 +26,8 @@ class QQmlComponent;
|
|||
class QQmlContext;
|
||||
class QQmlEngine;
|
||||
class QAction;
|
||||
class QDBusPendingCallWatcher;
|
||||
class QGraphicsScene;
|
||||
class QMenu;
|
||||
class QMutex;
|
||||
class QScriptEngine;
|
||||
class QScriptValue;
|
||||
class QQuickWindow;
|
||||
class KConfigGroup;
|
||||
|
||||
|
@ -41,9 +37,7 @@ typedef QList< QPair<bool, QPair<QString, QString > > > LoadScriptList;
|
|||
namespace KWin
|
||||
{
|
||||
class AbstractClient;
|
||||
class ScriptUnloaderAgent;
|
||||
class QtScriptWorkspaceWrapper;
|
||||
class X11Client;
|
||||
|
||||
class KWIN_EXPORT AbstractScript : public QObject
|
||||
{
|
||||
|
@ -51,15 +45,76 @@ class KWIN_EXPORT AbstractScript : public QObject
|
|||
public:
|
||||
AbstractScript(int id, QString scriptName, QString pluginName, QObject *parent = nullptr);
|
||||
~AbstractScript() override;
|
||||
int scriptId() const {
|
||||
return m_scriptId;
|
||||
}
|
||||
QString fileName() const {
|
||||
return m_fileName;
|
||||
}
|
||||
const QString &pluginName() {
|
||||
return m_pluginName;
|
||||
}
|
||||
bool running() const {
|
||||
return m_running;
|
||||
}
|
||||
|
||||
KConfigGroup config() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void stop();
|
||||
virtual void run() = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
void runningChanged(bool);
|
||||
|
||||
protected:
|
||||
void setRunning(bool running) {
|
||||
if (m_running == running) {
|
||||
return;
|
||||
}
|
||||
m_running = running;
|
||||
emit runningChanged(m_running);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_scriptId;
|
||||
QString m_fileName;
|
||||
QString m_pluginName;
|
||||
bool m_running;
|
||||
};
|
||||
|
||||
class Script : public AbstractScript, QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Scripting")
|
||||
|
||||
public:
|
||||
Script(int id, QString scriptName, QString pluginName, QObject *parent = nullptr);
|
||||
virtual ~Script();
|
||||
|
||||
Q_INVOKABLE QVariant readConfig(const QString &key, const QVariant &defaultValue = QVariant());
|
||||
|
||||
Q_INVOKABLE void callDBus(const QString &service, const QString &path,
|
||||
const QString &interface, const QString &method,
|
||||
const QJSValue &arg1 = QJSValue(),
|
||||
const QJSValue &arg2 = QJSValue(),
|
||||
const QJSValue &arg3 = QJSValue(),
|
||||
const QJSValue &arg4 = QJSValue(),
|
||||
const QJSValue &arg5 = QJSValue(),
|
||||
const QJSValue &arg6 = QJSValue(),
|
||||
const QJSValue &arg7 = QJSValue(),
|
||||
const QJSValue &arg8 = QJSValue(),
|
||||
const QJSValue &arg9 = QJSValue());
|
||||
|
||||
Q_INVOKABLE bool registerShortcut(const QString &objectName, const QString &text,
|
||||
const QString &keySequence, const QJSValue &callback);
|
||||
|
||||
Q_INVOKABLE bool registerScreenEdge(int edge, const QJSValue &callback);
|
||||
Q_INVOKABLE bool unregisterScreenEdge(int edge);
|
||||
|
||||
Q_INVOKABLE bool registerTouchScreenEdge(int edge, const QJSValue &callback);
|
||||
Q_INVOKABLE bool unregisterTouchScreenEdge(int edge);
|
||||
|
||||
void printMessage(const QString &message);
|
||||
void registerShortcut(QAction *a, QScriptValue callback);
|
||||
/**
|
||||
* @brief Registers the given @p callback to be invoked whenever the UserActionsMenu is about
|
||||
* to be showed. In the callback the script can create a further sub menu or menu entry to be
|
||||
|
@ -69,7 +124,8 @@ public:
|
|||
* @return void
|
||||
* @see actionsForUserActionMenu
|
||||
*/
|
||||
void registerUseractionsMenuCallback(QScriptValue callback);
|
||||
Q_INVOKABLE void registerUserActionsMenu(const QJSValue &callback);
|
||||
|
||||
/**
|
||||
* @brief Creates actions for the UserActionsMenu by invoking the registered callbacks.
|
||||
*
|
||||
|
@ -112,54 +168,29 @@ public:
|
|||
* @return QList< QAction* > List of QActions obtained from asking the registered callbacks
|
||||
* @see registerUseractionsMenuCallback
|
||||
*/
|
||||
QList<QAction*> actionsForUserActionMenu(AbstractClient *c, QMenu *parent);
|
||||
|
||||
KConfigGroup config() const;
|
||||
const QHash<QAction*, QScriptValue> &shortcutCallbacks() const {
|
||||
return m_shortcutCallbacks;
|
||||
}
|
||||
QHash<int, QList<QScriptValue > > &screenEdgeCallbacks() {
|
||||
return m_screenEdgeCallbacks;
|
||||
}
|
||||
|
||||
int registerCallback(QScriptValue value);
|
||||
QList<QAction *> actionsForUserActionMenu(AbstractClient *client, QMenu *parent);
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void stop();
|
||||
Q_SCRIPTABLE virtual void run() = 0;
|
||||
void slotPendingDBusCall(QDBusPendingCallWatcher *watcher);
|
||||
void run() override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void globalShortcutTriggered();
|
||||
bool borderActivated(ElectricBorder edge);
|
||||
/**
|
||||
* @brief Slot invoked when a menu action is destroyed. Used to remove the action and callback
|
||||
* from the map of actions.
|
||||
*
|
||||
* @param object The destroyed action
|
||||
* Callback for when loadScriptFromFile has finished.
|
||||
*/
|
||||
void actionDestroyed(QObject *object);
|
||||
void slotScriptLoadedFromFile();
|
||||
|
||||
Q_SIGNALS:
|
||||
Q_SCRIPTABLE void print(const QString &text);
|
||||
void runningChanged(bool);
|
||||
|
||||
protected:
|
||||
bool running() const {
|
||||
return m_running;
|
||||
}
|
||||
void setRunning(bool running) {
|
||||
if (m_running == running) {
|
||||
return;
|
||||
}
|
||||
m_running = running;
|
||||
emit runningChanged(m_running);
|
||||
}
|
||||
int scriptId() const {
|
||||
return m_scriptId;
|
||||
}
|
||||
/**
|
||||
* Called when any reserve screen edge is triggered.
|
||||
*/
|
||||
bool slotBorderActivated(ElectricBorder border);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Read the script from file into a byte array.
|
||||
* If file cannot be read an empty byte array is returned.
|
||||
*/
|
||||
QByteArray loadScriptFromFile(const QString &fileName);
|
||||
|
||||
/**
|
||||
* @brief Parses the @p value to either a QMenu or QAction.
|
||||
*
|
||||
|
@ -167,7 +198,8 @@ private:
|
|||
* @param parent The parent to use for the created menu or action
|
||||
* @return QAction* The parsed action or menu action, if parsing fails returns @c null.
|
||||
*/
|
||||
QAction *scriptValueToAction(QScriptValue &value, QMenu *parent);
|
||||
QAction *scriptValueToAction(const QJSValue &value, QMenu *parent);
|
||||
|
||||
/**
|
||||
* @brief Creates a new QAction from the provided data and registers it for invoking the
|
||||
* @p callback when the action is triggered.
|
||||
|
@ -182,7 +214,8 @@ private:
|
|||
* @param parent The parent to be used for the new created action
|
||||
* @return QAction* The created action
|
||||
*/
|
||||
QAction *createAction(const QString &title, bool checkable, bool checked, QScriptValue &callback, QMenu *parent);
|
||||
QAction *createAction(const QString &title, const QJSValue &item, QMenu *parent);
|
||||
|
||||
/**
|
||||
* @brief Parses the @p items and creates a QMenu from it.
|
||||
*
|
||||
|
@ -191,75 +224,14 @@ private:
|
|||
* @param parent The parent to use for the new created menu
|
||||
* @return QAction* The menu action for the new Menu
|
||||
*/
|
||||
QAction *createMenu(const QString &title, QScriptValue &items, QMenu *parent);
|
||||
int m_scriptId;
|
||||
QString m_fileName;
|
||||
QString m_pluginName;
|
||||
bool m_running;
|
||||
QHash<QAction*, QScriptValue> m_shortcutCallbacks;
|
||||
QHash<int, QList<QScriptValue> > m_screenEdgeCallbacks;
|
||||
QHash<int, QScriptValue> m_callbacks;
|
||||
/**
|
||||
* @brief List of registered functions to call when the UserActionsMenu is about to show
|
||||
* to add further entries.
|
||||
*/
|
||||
QList<QScriptValue> m_userActionsMenuCallbacks;
|
||||
};
|
||||
QAction *createMenu(const QString &title, const QJSValue &items, QMenu *parent);
|
||||
|
||||
class Script : public AbstractScript, QDBusContext
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Scripting")
|
||||
public:
|
||||
|
||||
Script(int id, QString scriptName, QString pluginName, QObject *parent = nullptr);
|
||||
~Script() override;
|
||||
QScriptEngine *engine() {
|
||||
return m_engine;
|
||||
}
|
||||
|
||||
bool registerTouchScreenCallback(int edge, QScriptValue callback);
|
||||
bool unregisterTouchScreenCallback(int edge);
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void run() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
Q_SCRIPTABLE void printError(const QString &text);
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* A nice clean way to handle exceptions in scripting.
|
||||
* TODO: Log to file, show from notifier..
|
||||
*/
|
||||
void sigException(const QScriptValue &exception);
|
||||
/**
|
||||
* Callback for when loadScriptFromFile has finished.
|
||||
*/
|
||||
void slotScriptLoadedFromFile();
|
||||
|
||||
private:
|
||||
void installScriptFunctions(QScriptEngine *engine);
|
||||
/**
|
||||
* Read the script from file into a byte array.
|
||||
* If file cannot be read an empty byte array is returned.
|
||||
*/
|
||||
QByteArray loadScriptFromFile(const QString &fileName);
|
||||
QScriptEngine *m_engine;
|
||||
QJSEngine *m_engine;
|
||||
QDBusMessage m_invocationContext;
|
||||
bool m_starting;
|
||||
QScopedPointer<ScriptUnloaderAgent> m_agent;
|
||||
QHash<int, QAction*> m_touchScreenEdgeCallbacks;
|
||||
};
|
||||
|
||||
class ScriptUnloaderAgent : public QScriptEngineAgent
|
||||
{
|
||||
public:
|
||||
explicit ScriptUnloaderAgent(Script *script);
|
||||
void scriptUnload(qint64 id) override;
|
||||
|
||||
private:
|
||||
Script *m_script;
|
||||
QHash<int, QJSValueList> m_screenEdgeCallbacks;
|
||||
QHash<int, QAction *> m_touchScreenEdgeCallbacks;
|
||||
QJSValueList m_userActionsMenuCallbacks;
|
||||
};
|
||||
|
||||
class DeclarativeScript : public AbstractScript
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
*/
|
||||
#include "scriptingutils.h"
|
||||
|
||||
#include <QDBusObjectPath>
|
||||
#include <QDBusSignature>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
bool validateParameters(QScriptContext *context, int min, int max)
|
||||
|
@ -32,4 +35,58 @@ bool validateArgumentType<QVariant>(QScriptContext *context, int argument)
|
|||
return result;
|
||||
}
|
||||
|
||||
QVariant dbusToVariant(const QVariant &variant)
|
||||
{
|
||||
if (variant.canConvert<QDBusArgument>()) {
|
||||
const QDBusArgument argument = variant.value<QDBusArgument>();
|
||||
switch (argument.currentType()) {
|
||||
case QDBusArgument::BasicType:
|
||||
return dbusToVariant(argument.asVariant());
|
||||
case QDBusArgument::VariantType:
|
||||
return dbusToVariant(argument.asVariant().value<QDBusVariant>().variant());
|
||||
case QDBusArgument::ArrayType: {
|
||||
QVariantList array;
|
||||
argument.beginArray();
|
||||
while (!argument.atEnd()) {
|
||||
const QVariant value = argument.asVariant();
|
||||
array.append(dbusToVariant(value));
|
||||
}
|
||||
argument.endArray();
|
||||
return array; }
|
||||
case QDBusArgument::StructureType: {
|
||||
QVariantList structure;
|
||||
argument.beginStructure();
|
||||
while (!argument.atEnd()) {
|
||||
const QVariant value = argument.asVariant();
|
||||
structure.append(dbusToVariant(value));
|
||||
}
|
||||
argument.endStructure();
|
||||
return structure; }
|
||||
case QDBusArgument::MapType: {
|
||||
QVariantMap map;
|
||||
argument.beginMap();
|
||||
while (!argument.atEnd()) {
|
||||
argument.beginMapEntry();
|
||||
const QVariant key = argument.asVariant();
|
||||
const QVariant value = argument.asVariant();
|
||||
argument.endMapEntry();
|
||||
map.insert(key.toString(), dbusToVariant(value));
|
||||
}
|
||||
argument.endMap();
|
||||
return map; }
|
||||
default:
|
||||
qCWarning(KWIN_SCRIPTING) << "Couldn't unwrap QDBusArgument of type" << argument.currentType();
|
||||
return variant;
|
||||
}
|
||||
} else if (variant.canConvert<QDBusObjectPath>()) {
|
||||
return variant.value<QDBusObjectPath>().path();
|
||||
} else if (variant.canConvert<QDBusSignature>()) {
|
||||
return variant.value<QDBusSignature>().signature();
|
||||
} else if (variant.canConvert<QDBusVariant>()) {
|
||||
return dbusToVariant(variant.value<QDBusVariant>().variant());
|
||||
}
|
||||
|
||||
return variant;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -159,31 +159,6 @@ QScriptValue registerScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
|||
return engine->newVariant(true);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
QScriptValue unregisterScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
T script = qobject_cast<T>(context->callee().data().toQObject());
|
||||
if (!script) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!validateParameters(context, 1, 1)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!validateArgumentType<int>(context)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
|
||||
const int edge = context->argument(0).toVariant().toInt();
|
||||
QHash<int, QList<QScriptValue> >::iterator it = script->screenEdgeCallbacks().find(edge);
|
||||
if (it == script->screenEdgeCallbacks().end()) {
|
||||
//not previously registered
|
||||
return engine->newVariant(false);
|
||||
}
|
||||
ScreenEdges::self()->unreserve(static_cast<KWin::ElectricBorder>(edge), script);
|
||||
script->screenEdgeCallbacks().erase(it);
|
||||
return engine->newVariant(true);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
QScriptValue registerTouchScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
|
@ -224,25 +199,6 @@ QScriptValue unregisterTouchScreenEdge(QScriptContext *context, QScriptEngine *e
|
|||
return engine->newVariant(ret);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
QScriptValue registerUserActionsMenu(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
T script = qobject_cast<T>(context->callee().data().toQObject());
|
||||
if (!script) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!validateParameters(context, 1, 1)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
if (!context->argument(0).isFunction()) {
|
||||
context->throwError(QScriptContext::SyntaxError, i18nc("KWin Scripting error thrown due to incorrect argument",
|
||||
"Argument for registerUserActionsMenu needs to be a callback"));
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
script->registerUseractionsMenuCallback(context->argument(0));
|
||||
return engine->newVariant(true);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void screenEdgeActivated(T *script, int edge)
|
||||
{
|
||||
|
@ -255,62 +211,6 @@ void screenEdgeActivated(T *script, int edge)
|
|||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
QScriptValue scriptingAssert(QScriptContext *context, QScriptEngine *engine, int min, int max, T defaultVal = T())
|
||||
{
|
||||
if (!validateParameters(context, min, max)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
switch (context->argumentCount()) {
|
||||
case 1:
|
||||
if (!validateArgumentType<T>(context)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (max == 2) {
|
||||
if (!validateArgumentType<T, QString>(context)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
} else {
|
||||
if (!validateArgumentType<T, T>(context)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!validateArgumentType<T, T, QString>(context)) {
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (max == 2) {
|
||||
if (context->argument(0).toVariant().value<T>() != defaultVal) {
|
||||
if (context->argumentCount() == max) {
|
||||
context->throwError(QScriptContext::UnknownError, context->argument(max - 1).toString());
|
||||
} else {
|
||||
context->throwError(QScriptContext::UnknownError,
|
||||
i18nc("Assertion failed in KWin script with given value",
|
||||
"Assertion failed: %1", context->argument(0).toString()));
|
||||
}
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
} else {
|
||||
if (context->argument(0).toVariant().value<T>() != context->argument(1).toVariant().value<T>()) {
|
||||
if (context->argumentCount() == max) {
|
||||
context->throwError(QScriptContext::UnknownError, context->argument(max - 1).toString());
|
||||
} else {
|
||||
context->throwError(QScriptContext::UnknownError,
|
||||
i18nc("Assertion failed in KWin script with expected value and actual value",
|
||||
"Assertion failed: Expected %1, got %2",
|
||||
context->argument(0).toString(), context->argument(1).toString()));
|
||||
}
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
}
|
||||
return engine->newVariant(true);
|
||||
}
|
||||
|
||||
inline void registerGlobalShortcutFunction(QObject *parent, QScriptEngine *engine, QScriptEngine::FunctionSignature function)
|
||||
{
|
||||
QScriptValue shortcutFunc = engine->newFunction(function);
|
||||
|
@ -325,13 +225,6 @@ 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 registerTouchScreenEdgeFunction(QObject *parent, QScriptEngine *engine, QScriptEngine::FunctionSignature function)
|
||||
{
|
||||
QScriptValue touchScreenFunc = engine->newFunction(function);
|
||||
|
@ -346,12 +239,7 @@ inline void unregisterTouchScreenEdgeFunction(QObject *parent, QScriptEngine *en
|
|||
engine->globalObject().setProperty(QStringLiteral("unregisterTouchScreenEdge"), touchScreenFunc);
|
||||
}
|
||||
|
||||
inline void registerUserActionsMenuFunction(QObject *parent, QScriptEngine *engine, QScriptEngine::FunctionSignature function)
|
||||
{
|
||||
QScriptValue shortcutFunc = engine->newFunction(function);
|
||||
shortcutFunc.setData(engine->newQObject(parent));
|
||||
engine->globalObject().setProperty(QStringLiteral("registerUserActionsMenu"), shortcutFunc);
|
||||
}
|
||||
QVariant dbusToVariant(const QVariant &variant);
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2007 Richard J. Moore <rich@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <QtScript/QScriptValue>
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtScript/QScriptContext>
|
||||
#include <QtScript/QScriptable>
|
||||
#include <QTimer>
|
||||
|
||||
Q_DECLARE_METATYPE(QTimer*)
|
||||
|
||||
static QScriptValue newTimer(QScriptEngine *eng, QTimer *timer)
|
||||
{
|
||||
return eng->newQObject(timer, QScriptEngine::AutoOwnership);
|
||||
}
|
||||
|
||||
static QScriptValue ctor(QScriptContext *ctx, QScriptEngine *eng)
|
||||
{
|
||||
return newTimer(eng, new QTimer(qscriptvalue_cast<QObject*>(ctx->argument(0))));
|
||||
}
|
||||
|
||||
QScriptValue constructTimerClass(QScriptEngine *eng)
|
||||
{
|
||||
QScriptValue proto = newTimer(eng, new QTimer());
|
||||
eng->setDefaultPrototype(qMetaTypeId<QTimer*>(), proto);
|
||||
|
||||
return eng->newFunction(ctor, proto);
|
||||
}
|
Loading…
Reference in New Issue