diff --git a/scripting/documentation-global.xml b/scripting/documentation-global.xml
index cfe6355829..0b1c05869e 100644
--- a/scripting/documentation-global.xml
+++ b/scripting/documentation-global.xml
@@ -105,6 +105,14 @@
Aborts the execution of the script if value is null. If message is provided an error is thrown with the given message, if not provided an error with default message is thrown.
+
+ Q_SCRIPTABLE void
+ void KWin::Scripting::callDBus
+ (QString service, QString path, QString interface, QString method, QVariant arg..., QScriptValue callback = QScriptValue())
+ callDBus
+
+ Call a D-Bus method at (service, path, interface and method). A variable number of arguments can be added to the method call. The D-Bus call is always performed in an async way invoking the callback provided as the last (optional) argument. The reply values of the D-Bus method call are passed to the callback.
+
diff --git a/scripting/scripting.cpp b/scripting/scripting.cpp
index b81b6a17cc..96f7cd7b4f 100644
--- a/scripting/scripting.cpp
+++ b/scripting/scripting.cpp
@@ -37,6 +37,8 @@ along with this program. If not, see .
#include
// Qt
#include
+#include
+#include
#include
#include
#include
@@ -144,6 +146,53 @@ QScriptValue kwinRegisterScreenEdge(QScriptContext *context, QScriptEngine *engi
return KWin::registerScreenEdge(context, engine);
}
+QScriptValue kwinCallDBus(QScriptContext *context, QScriptEngine *engine)
+{
+ KWin::AbstractScript *script = qobject_cast(context->callee().data().toQObject());
+ if (!script) {
+ context->throwError(QScriptContext::UnknownError, "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(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; iargument(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, SIGNAL(finished(QDBusPendingCallWatcher*)), script, SLOT(slotPendingDBusCall(QDBusPendingCallWatcher*)));
+ }
+ return engine->undefinedValue();
+}
+
KWin::AbstractScript::AbstractScript(int id, QString scriptName, QString pluginName, QObject *parent)
: QObject(parent)
, m_scriptId(id)
@@ -213,6 +262,9 @@ void KWin::AbstractScript::installScriptFunctions(QScriptEngine* engine)
QScriptValue configFunc = engine->newFunction(kwinScriptReadConfig);
configFunc.setData(engine->newQObject(this));
engine->globalObject().setProperty("readConfig", configFunc);
+ QScriptValue dbusCallFunc = engine->newFunction(kwinCallDBus);
+ dbusCallFunc.setData(engine->newQObject(this));
+ engine->globalObject().setProperty("callDBus", dbusCallFunc);
// add global Shortcut
registerGlobalShortcutFunction(this, engine, kwinScriptGlobalShortcut);
// add screen edge
@@ -239,6 +291,32 @@ void KWin::AbstractScript::installScriptFunctions(QScriptEngine* engine)
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()) {
+ kDebug(1212) << "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();
+}
+
KWin::Script::Script(int id, QString scriptName, QString pluginName, QObject* parent)
: AbstractScript(id, scriptName, pluginName, parent)
, m_engine(new QScriptEngine(this))
diff --git a/scripting/scripting.h b/scripting/scripting.h
index 9d728df456..d6d56db20c 100644
--- a/scripting/scripting.h
+++ b/scripting/scripting.h
@@ -31,6 +31,7 @@ along with this program. If not, see .
class QAction;
class QDeclarativeView;
+class QDBusPendingCallWatcher;
class QMutex;
class QScriptEngine;
class QScriptValue;
@@ -68,9 +69,12 @@ public:
return m_screenEdgeCallbacks;
}
+ int registerCallback(QScriptValue value);
+
public Q_SLOTS:
Q_SCRIPTABLE void stop();
Q_SCRIPTABLE virtual void run() = 0;
+ void slotPendingDBusCall(QDBusPendingCallWatcher *watcher);
private Q_SLOTS:
void globalShortcutTriggered();
@@ -107,6 +111,7 @@ private:
WorkspaceWrapper *m_workspace;
QHash m_shortcutCallbacks;
QHash > m_screenEdgeCallbacks;
+ QHash m_callbacks;
};
class Script : public AbstractScript