Support declarative KWin scripts

For this the Script class is slightly refactored to have a common
base for JavaScript and QML based scripts.

Why QML bindings? This allows to use QML for example for the
desktop change OSD or for fullscreen effects like Present Windows.
icc-effect-5.14.5
Martin Gräßlin 2012-02-19 15:43:24 +01:00
parent f9ad0621d5
commit 6a8b79f699
2 changed files with 142 additions and 27 deletions

View File

@ -23,15 +23,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// own
#include "meta.h"
#include "workspace_wrapper.h"
#include "../thumbnailitem.h"
// KDE
#include <kstandarddirs.h>
#include <KDE/KConfigGroup>
#include <KDE/KDebug>
#include <KDE/KPluginInfo>
#include <KDE/KServiceTypeTrader>
#include <kdeclarative.h>
// Qt
#include <QtDBus/QDBusConnection>
#include <QtCore/QSettings>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/qdeclarative.h>
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValue>
@ -50,36 +56,49 @@ QScriptValue kwinScriptPrint(QScriptContext *context, QScriptEngine *engine)
return engine->undefinedValue();
}
KWin::Script::Script(int scriptId, QString scriptName, QObject *parent)
KWin::AbstractScript::AbstractScript (int id, QString scriptName, QObject *parent)
: QObject(parent)
, m_scriptId(scriptId)
, m_engine(new QScriptEngine(this))
, m_workspace(new WorkspaceWrapper(m_engine))
, m_scriptId(id)
, m_running(false)
, m_workspace(new WorkspaceWrapper(this))
{
m_scriptFile.setFileName(scriptName);
QDBusConnection::sessionBus().registerObject('/' + QString::number(m_scriptId), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables);
}
KWin::AbstractScript::~AbstractScript()
{
}
void KWin::AbstractScript::stop()
{
deleteLater();
}
KWin::Script::Script(int id, QString scriptName, QObject *parent)
: AbstractScript(id, scriptName, parent)
, m_engine(new QScriptEngine(this))
{
QDBusConnection::sessionBus().registerObject('/' + QString::number(scriptId()), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportScriptableInvokables);
}
KWin::Script::~Script()
{
QDBusConnection::sessionBus().unregisterObject('/' + QString::number(m_scriptId));
QDBusConnection::sessionBus().unregisterObject('/' + QString::number(scriptId()));
}
void KWin::Script::printMessage(const QString &message)
{
kDebug(1212) << m_scriptFile.fileName() << ":" << message;
kDebug(1212) << scriptFile().fileName() << ":" << message;
emit print(message);
}
void KWin::Script::run()
{
if (m_running) {
if (running()) {
return;
}
if (m_scriptFile.open(QIODevice::ReadOnly)) {
QScriptValue workspace = m_engine->newQObject(m_workspace, QScriptEngine::QtOwnership,
if (scriptFile().open(QIODevice::ReadOnly)) {
QScriptValue workspace = m_engine->newQObject(AbstractScript::workspace(), QScriptEngine::QtOwnership,
QScriptEngine::ExcludeSuperClassContents | QScriptEngine::ExcludeDeleteLater);
m_engine->globalObject().setProperty("workspace", workspace, QScriptValue::Undeletable);
m_engine->globalObject().setProperty("QTimer", constructTimerClass(m_engine));
@ -92,14 +111,14 @@ void KWin::Script::run()
printFunc.setData(m_engine->newQObject(this));
m_engine->globalObject().setProperty("print", printFunc);
QScriptValue ret = m_engine->evaluate(m_scriptFile.readAll());
QScriptValue ret = m_engine->evaluate(scriptFile().readAll());
if (ret.isError()) {
sigException(ret);
deleteLater();
}
}
m_running = true;
setRunning(true);
}
void KWin::Script::sigException(const QScriptValue& exception)
@ -119,11 +138,44 @@ void KWin::Script::sigException(const QScriptValue& exception)
emit printError(exception.toString());
}
void KWin::Script::stop()
KWin::DeclarativeScript::DeclarativeScript(int id, QString scriptName, QObject *parent)
: AbstractScript(id, scriptName, parent)
, m_view(new QDeclarativeView())
{
deleteLater();
}
KWin::DeclarativeScript::~DeclarativeScript()
{
}
void KWin::DeclarativeScript::run()
{
if (running()) {
return;
}
m_view->setAttribute(Qt::WA_TranslucentBackground);
m_view->setWindowFlags(Qt::X11BypassWindowManagerHint);
m_view->setResizeMode(QDeclarativeView::SizeViewToRootObject);
QPalette pal = m_view->palette();
pal.setColor(m_view->backgroundRole(), Qt::transparent);
m_view->setPalette(pal);
foreach (const QString &importPath, KGlobal::dirs()->findDirs("module", "imports")) {
m_view->engine()->addImportPath(importPath);
}
KDeclarative kdeclarative;
kdeclarative.setDeclarativeEngine(m_view->engine());
kdeclarative.initialize();
kdeclarative.setupBindings();
qmlRegisterType<ThumbnailItem>("org.kde.kwin", 0, 1, "ThumbnailItem");
qmlRegisterType<WorkspaceWrapper>("org.kde.kwin", 0, 1, "KWin");
m_view->rootContext()->setContextProperty("workspace", workspace());
m_view->setSource(QUrl::fromLocalFile(scriptFile().fileName()));
setRunning(true);
}
KWin::Scripting::Scripting(QObject *parent)
: QObject(parent)
@ -142,7 +194,9 @@ void KWin::Scripting::start()
foreach (const KService::Ptr & service, offers) {
KPluginInfo plugininfo(service);
plugininfo.load(conf);
if (service->property("X-Plasma-API").toString() != "javascript") {
const bool javaScript = service->property("X-Plasma-API").toString() == "javascript";
const bool declarativeScript = service->property("X-Plasma-API").toString() == "declarativescript";
if (!javaScript && !declarativeScript) {
continue;
}
@ -156,7 +210,11 @@ void KWin::Scripting::start()
kDebug(1212) << "Could not find script file for " << pluginName;
continue;
}
loadScript(file);
if (javaScript) {
loadScript(file);
} else if (declarativeScript) {
loadDeclarativeScript(file);
}
}
runScripts();
@ -183,6 +241,15 @@ int KWin::Scripting::loadScript(const QString &filePath)
return id;
}
int KWin::Scripting::loadDeclarativeScript(const QString &filePath)
{
const int id = scripts.size();
KWin::DeclarativeScript *script = new KWin::DeclarativeScript(id, filePath, this);
connect(script, SIGNAL(destroyed(QObject*)), SLOT(scriptDestroyed(QObject*)));
scripts.append(script);
return id;
}
KWin::Scripting::~Scripting()
{
QDBusConnection::sessionBus().unregisterObject("/Scripting");

View File

@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QtCore/QFile>
#include <QtCore/QStringList>
class QDeclarativeView;
class QScriptEngine;
class QScriptValue;
@ -32,7 +33,46 @@ namespace KWin
{
class WorkspaceWrapper;
class Script : public QObject
class AbstractScript : public QObject
{
Q_OBJECT
public:
AbstractScript(int id, QString scriptName, QObject *parent = NULL);
~AbstractScript();
QString fileName() const {
return m_scriptFile.fileName();
}
public Q_SLOTS:
Q_SCRIPTABLE void stop();
Q_SCRIPTABLE virtual void run() = 0;
protected:
QFile &scriptFile() {
return m_scriptFile;
}
bool running() const {
return m_running;
}
void setRunning(bool running) {
m_running = running;
}
int scriptId() const {
return m_scriptId;
}
WorkspaceWrapper *workspace() {
return m_workspace;
}
private:
int m_scriptId;
QFile m_scriptFile;
bool m_running;
WorkspaceWrapper *m_workspace;
};
class Script : public AbstractScript
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Scripting")
@ -40,14 +80,10 @@ public:
Script(int id, QString scriptName, QObject *parent = NULL);
virtual ~Script();
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:
@ -62,11 +98,22 @@ private slots:
void sigException(const QScriptValue &exception);
private:
int m_scriptId;
QScriptEngine *m_engine;
QFile m_scriptFile;
WorkspaceWrapper *m_workspace;
bool m_running;
};
class DeclarativeScript : public AbstractScript
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Scripting")
public:
explicit DeclarativeScript(int id, QString scriptName, QObject *parent = 0);
virtual ~DeclarativeScript();
public Q_SLOTS:
Q_SCRIPTABLE void run();
private:
QDeclarativeView *m_view;
};
/**
@ -78,7 +125,7 @@ class Scripting : public QObject
Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Scripting")
private:
QStringList scriptList;
QList<KWin::Script*> scripts;
QList<KWin::AbstractScript*> scripts;
// Preferably call ONLY at load time
void runScripts();
@ -92,6 +139,7 @@ public:
void start();
~Scripting();
Q_SCRIPTABLE Q_INVOKABLE int loadScript(const QString &filePath);
Q_SCRIPTABLE Q_INVOKABLE int loadDeclarativeScript(const QString &filePath);
public Q_SLOTS:
void scriptDestroyed(QObject *object);