Support for calling D-Bus methods from scripts
A new global method is exported to perform a remote method call through D-Bus. The call is always performed async invoking a callback once the call completed passing through the arguments received from D-Bus. Possible code looks like the following: callDBus("org.kde.kwin", "/KWin", "org.kde.KWin", "currentDesktop", function (desktop) { print("Current Desktop through D-Bus: ", desktop); }); REVIEW: 105396
This commit is contained in:
parent
6e6ac5a26b
commit
d2a9199cd9
3 changed files with 91 additions and 0 deletions
|
@ -105,6 +105,14 @@
|
|||
<read></read>
|
||||
<detaileddescription>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.</detaileddescription>
|
||||
</memberdef>
|
||||
<memberdef kind="function">
|
||||
<type>Q_SCRIPTABLE void</type>
|
||||
<definition>void KWin::Scripting::callDBus</definition>
|
||||
<argsstring>(QString service, QString path, QString interface, QString method, QVariant arg..., QScriptValue callback = QScriptValue())</argsstring>
|
||||
<name>callDBus</name>
|
||||
<read></read>
|
||||
<detaileddescription>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.</detaileddescription>
|
||||
</memberdef>
|
||||
</sectiondef>
|
||||
</compounddef>
|
||||
</doxygen>
|
||||
|
|
|
@ -37,6 +37,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <kdeclarative.h>
|
||||
// Qt
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusMessage>
|
||||
#include <QtDBus/QDBusPendingCallWatcher>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QtConcurrentRun>
|
||||
|
@ -144,6 +146,53 @@ QScriptValue kwinRegisterScreenEdge(QScriptContext *context, QScriptEngine *engi
|
|||
return KWin::registerScreenEdge<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, "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) {
|
||||
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, 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))
|
||||
|
|
|
@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
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<QAction*, QScriptValue> m_shortcutCallbacks;
|
||||
QHash<int, QList<QScriptValue> > m_screenEdgeCallbacks;
|
||||
QHash<int, QScriptValue> m_callbacks;
|
||||
};
|
||||
|
||||
class Script : public AbstractScript
|
||||
|
|
Loading…
Reference in a new issue