Scripting meets D-Bus
Each KWin Script is also exported as a D-Bus object and can be stopped (destroyed) and started through D-Bus. Output and errors are emitted as D-Bus signals. That allows external applications (e.g. Plasma desktop scripting console) to load a script and print out the output. The general interface is exported as /Scripting and allows to load a new script by file. The script is not directly executed but only loaded. To execute it the run method on the script object has to be invoked.
This commit is contained in:
parent
0420ecd649
commit
ab253cd178
2 changed files with 99 additions and 24 deletions
|
@ -3,6 +3,7 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2010 Rohan Prabhu <rohan@rohanprabhu.com>
|
||||
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,25 +20,63 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*********************************************************************/
|
||||
|
||||
#include "scripting.h"
|
||||
// own
|
||||
#include "chelate.h"
|
||||
#include "meta.h"
|
||||
#include "s_clientgroup.h"
|
||||
// KDE
|
||||
#include <kstandarddirs.h>
|
||||
// Qt
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtScript/QScriptValue>
|
||||
|
||||
QScriptValue kwinScriptPrint(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
KWin::Script *script = qobject_cast<KWin::Script*>(context->callee().data().toQObject());
|
||||
QString result;
|
||||
for (int i = 0; i < context->argumentCount(); ++i) {
|
||||
if (i > 0) {
|
||||
result.append(" ");
|
||||
}
|
||||
result.append(context->argument(i).toString());
|
||||
}
|
||||
script->printMessage(result);
|
||||
|
||||
return engine->undefinedValue();
|
||||
}
|
||||
|
||||
|
||||
KWin::Script::Script(QString scriptName, QDir dir, QObject *parent)
|
||||
KWin::Script::Script(int scriptId, QString scriptName, QDir dir, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_scriptId(scriptId)
|
||||
, m_engine(new QScriptEngine(this))
|
||||
, m_scriptDir(dir)
|
||||
, m_configFile(QFileInfo(m_scriptFile).completeBaseName() + QString(".kwscfg"))
|
||||
, m_workspace(new SWrapper::Workspace(m_engine))
|
||||
, m_running(false)
|
||||
{
|
||||
m_scriptFile.setFileName(dir.filePath(scriptName));
|
||||
QDBusConnection::sessionBus().registerObject("/" + QString::number(m_scriptId), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables);
|
||||
}
|
||||
|
||||
KWin::Script::~Script()
|
||||
{
|
||||
QDBusConnection::sessionBus().unregisterObject("/" + QString::number(m_scriptId));
|
||||
}
|
||||
|
||||
void KWin::Script::printMessage(const QString &message)
|
||||
{
|
||||
kDebug(1212) << m_scriptFile.fileName() << ":" << message;
|
||||
emit print(message);
|
||||
}
|
||||
|
||||
void KWin::Script::run()
|
||||
{
|
||||
if (m_running) {
|
||||
return;
|
||||
}
|
||||
if (m_scriptFile.open(QIODevice::ReadOnly)) {
|
||||
m_workspace->attach(m_engine);
|
||||
m_engine->globalObject().setProperty("QTimer", constructTimerClass(m_engine));
|
||||
|
@ -60,13 +99,19 @@ void KWin::Script::run()
|
|||
} else {
|
||||
KWin::MetaScripting::supplyConfig(m_engine);
|
||||
}
|
||||
// add our print
|
||||
QScriptValue printFunc = m_engine->newFunction(kwinScriptPrint);
|
||||
printFunc.setData(m_engine->newQObject(this));
|
||||
m_engine->globalObject().setProperty("print", printFunc);
|
||||
|
||||
QScriptValue ret = m_engine->evaluate(m_scriptFile.readAll());
|
||||
|
||||
if (ret.isError()) {
|
||||
sigException(ret);
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
void KWin::Script::sigException(const QScriptValue& exception)
|
||||
|
@ -83,12 +128,20 @@ void KWin::Script::sigException(const QScriptValue& exception)
|
|||
qDebug() << " " << iter.name() << ": " << iter.value().toString();
|
||||
}
|
||||
}
|
||||
emit printError(exception.toString());
|
||||
}
|
||||
|
||||
void KWin::Script::stop()
|
||||
{
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
||||
KWin::Scripting::Scripting(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QDBusConnection::sessionBus().registerObject("/Scripting", this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables);
|
||||
QDBusConnection::sessionBus().registerService("org.kde.kwin.Scripting");
|
||||
}
|
||||
|
||||
void KWin::Scripting::start()
|
||||
|
@ -106,7 +159,7 @@ void KWin::Scripting::start()
|
|||
scriptList = scriptsDir.entryList(scriptFilters, QDir::Files | QDir::Readable | QDir::Executable);
|
||||
|
||||
for (int i = 0; i < scriptList.size(); i++) {
|
||||
scripts.append(new KWin::Script(scriptsDir.filePath(scriptList.at(i)), scriptsDir, this));
|
||||
loadScript(scriptsDir.filePath(scriptList.at(i)));
|
||||
}
|
||||
|
||||
// Initialize singletons. Currently, only KWin::Workspace.
|
||||
|
@ -122,6 +175,24 @@ void KWin::Scripting::runScripts()
|
|||
}
|
||||
}
|
||||
|
||||
void KWin::Scripting::scriptDestroyed(QObject *object)
|
||||
{
|
||||
scripts.removeAll(static_cast<KWin::Script*>(object));
|
||||
}
|
||||
|
||||
int KWin::Scripting::loadScript(const QString &filePath)
|
||||
{
|
||||
const int id = scripts.size();
|
||||
KWin::Script *script = new KWin::Script(id, filePath, scriptsDir, this);
|
||||
connect(script, SIGNAL(destroyed(QObject*)), SLOT(scriptDestroyed(QObject*)));
|
||||
scripts.append(script);
|
||||
return id;
|
||||
}
|
||||
|
||||
KWin::Scripting::~Scripting()
|
||||
{
|
||||
QDBusConnection::sessionBus().unregisterObject("/Scripting");
|
||||
QDBusConnection::sessionBus().unregisterService("org.kde.kwin.Scripting");
|
||||
}
|
||||
|
||||
#include "scripting.moc"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2010 Rohan Prabhu <rohan@rohanprabhu.com>
|
||||
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -21,37 +22,38 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifndef KWIN_SCRIPTING_H
|
||||
#define KWIN_SCRIPTING_H
|
||||
|
||||
#include <QScriptClass>
|
||||
#include <QScriptEngine>
|
||||
#include <QDir>
|
||||
#include <QVector>
|
||||
#include <QSettings>
|
||||
#include <QVariant>
|
||||
|
||||
#include "chelate.h"
|
||||
#include "workspace.h"
|
||||
#include "workspaceproxy.h"
|
||||
#include "s_clientgroup.h"
|
||||
|
||||
#include "./../workspace.h"
|
||||
|
||||
#include "meta.h"
|
||||
class QScriptEngine;
|
||||
class QScriptValue;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
/** This mostly behaves like a struct. Is used to store
|
||||
* the scriptfile, the configfile and the QScriptEngine
|
||||
* that will run this script
|
||||
*/
|
||||
class Script : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Scripting")
|
||||
public:
|
||||
|
||||
Script(QString scriptName, QDir dir, QObject *parent = NULL);
|
||||
Script(int id, QString scriptName, QDir dir, QObject *parent = NULL);
|
||||
virtual ~Script();
|
||||
void run();
|
||||
QString fileName() const {
|
||||
return m_scriptFile.fileName();
|
||||
}
|
||||
|
||||
void printMessage(const QString &message);
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void stop();
|
||||
Q_SCRIPTABLE void run();
|
||||
|
||||
Q_SIGNALS:
|
||||
Q_SCRIPTABLE void print(const QString &text);
|
||||
Q_SCRIPTABLE void printError(const QString &text);
|
||||
|
||||
private slots:
|
||||
/**
|
||||
|
@ -61,11 +63,13 @@ private slots:
|
|||
void sigException(const QScriptValue &exception);
|
||||
|
||||
private:
|
||||
int m_scriptId;
|
||||
QScriptEngine *m_engine;
|
||||
QDir m_scriptDir;
|
||||
QFile m_scriptFile;
|
||||
QString m_configFile;
|
||||
SWrapper::Workspace *m_workspace;
|
||||
bool m_running;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -74,19 +78,15 @@ private:
|
|||
class Scripting : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Scripting")
|
||||
private:
|
||||
QStringList scriptList;
|
||||
QDir scriptsDir;
|
||||
QVector<KWin::Script*> scripts;
|
||||
QList<KWin::Script*> scripts;
|
||||
|
||||
// Preferably call ONLY at load time
|
||||
void runScripts();
|
||||
|
||||
// NOTE: Runtime script running is not yet tested.
|
||||
// Proceed with caution.
|
||||
// An interface to run scripts at runtime
|
||||
void runScript(KWin::Script*);
|
||||
|
||||
public:
|
||||
Scripting(QObject *parent = NULL);
|
||||
/**
|
||||
|
@ -95,6 +95,10 @@ public:
|
|||
*/
|
||||
void start();
|
||||
~Scripting();
|
||||
Q_SCRIPTABLE Q_INVOKABLE int loadScript(const QString &filePath);
|
||||
|
||||
public Q_SLOTS:
|
||||
void scriptDestroyed(QObject *object);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue