JavaScript bindings for KWin effects

Scripted effects follow the Plamsoid package structure and the effect
loader recognizes a scripted effect at the according line in the desktop
file. If it is a scripted effect a different loader is used which
instantiates an object of the ScriptedEffect class. This class inherits
the AnimationEffect and exports the animate method and the EffectsHandler.
This commit is contained in:
Martin Gräßlin 2012-01-29 17:32:56 +01:00
parent 2007a7eab8
commit 5592dffb48
6 changed files with 275 additions and 1 deletions

View file

@ -122,6 +122,7 @@ if(KWIN_BUILD_SCRIPTING)
scripting/scripting.cpp
scripting/workspace_wrapper.cpp
scripting/meta.cpp
scripting/scriptedeffect.cpp
scripting/timer.cpp
)
endif(KWIN_BUILD_SCRIPTING)

View file

@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef KWIN_BUILD_TABBOX
#include "tabbox.h"
#endif
#include "scripting/scriptedeffect.h"
#include "thumbnailitem.h"
#include "workspace.h"
#include "kwinglutils.h"
@ -1139,6 +1140,11 @@ bool EffectsHandlerImpl::loadEffect(const QString& name, bool checkDefault)
}
KService::Ptr service = offers.first();
if (service->property("X-Plasma-API").toString() == "javascript") {
// this is a scripted effect - use different loader
return loadScriptedEffect(name, service.data());
}
KLibrary* library = findEffectLibrary(service.data());
if (!library) {
return false;
@ -1222,6 +1228,28 @@ bool EffectsHandlerImpl::loadEffect(const QString& name, bool checkDefault)
return true;
}
bool EffectsHandlerImpl::loadScriptedEffect(const QString& name, KService *service)
{
const KDesktopFile df("services", service->entryPath());
const QString scriptName = df.desktopGroup().readEntry<QString>("X-Plasma-MainScript", "");
if (scriptName.isEmpty()) {
kDebug(1212) << "X-Plasma-MainScript not set";
return false;
}
const QString scriptFile = KStandardDirs::locateLocal("data", "kwin/effects/" + name + '/' + scriptName);
if (scriptFile.isNull()) {
kDebug(1212) << "Could not locate the effect script";
return false;
}
ScriptedEffect *effect = ScriptedEffect::create(scriptFile);
if (!effect) {
return false;
}
effect_order.insert(service->property("X-KDE-Ordering").toInt(), EffectPair(name, effect));
effectsChanged();
return true;
}
void EffectsHandlerImpl::unloadEffect(const QString& name)
{
Workspace::self()->addRepaintFull();
@ -1235,7 +1263,9 @@ void EffectsHandlerImpl::unloadEffect(const QString& name)
delete it.value().second;
effect_order.erase(it);
effectsChanged();
effect_libraries[ name ]->unload();
if (effect_libraries.contains(name)) {
effect_libraries[ name ]->unload();
}
return;
}
}

View file

@ -202,6 +202,7 @@ protected Q_SLOTS:
void slotPropertyNotify(long atom);
protected:
bool loadScriptedEffect(const QString &name, KService *service);
KLibrary* findEffectLibrary(KService* service);
void effectsChanged();
void setupClientConnections(KWin::Client *c);

View file

@ -90,6 +90,9 @@ class AnimationEffectPrivate;
class KWIN_EXPORT AnimationEffect : public Effect
{
Q_OBJECT
Q_ENUMS(Anchor)
Q_ENUMS(Attribute)
Q_ENUMS(MetaType)
public:
enum Anchor { Left = 1<<0, Top = 1<<1, Right = 1<<2, Bottom = 1<<3,
Horizontal = Left|Right, Vertical = Top|Bottom, Mouse = 1<<4 };

View file

@ -0,0 +1,174 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2012 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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "scriptedeffect.h"
#include "meta.h"
// KDE
#include <KDE/KDebug>
// Qt
#include <QtCore/QFile>
#include <QtScript/QScriptEngine>
#include <QtScript/QScriptValueIterator>
typedef KWin::EffectWindow* KEffectWindowRef;
namespace KWin
{
QScriptValue kwinEffectScriptPrint(QScriptContext *context, QScriptEngine *engine)
{
ScriptedEffect *script = qobject_cast<ScriptedEffect*>(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());
}
kDebug(1212) << script->scriptFile() << ":" << result;
return engine->undefinedValue();
}
QScriptValue effectWindowToScriptValue(QScriptEngine *eng, const KEffectWindowRef &window)
{
return eng->newQObject(window, QScriptEngine::QtOwnership,
QScriptEngine::ExcludeChildObjects | QScriptEngine::ExcludeDeleteLater | QScriptEngine::PreferExistingWrapperObject);
}
void effectWindowFromScriptValue(const QScriptValue &value, EffectWindow* &window)
{
window = qobject_cast<EffectWindow*>(value.toQObject());
}
ScriptedEffect *ScriptedEffect::create(const QString &pathToScript)
{
ScriptedEffect *effect = new ScriptedEffect();
if (!effect->init(pathToScript)) {
delete effect;
return NULL;
}
return effect;
}
ScriptedEffect::ScriptedEffect()
: AnimationEffect()
, m_engine(new QScriptEngine(this))
{
connect(m_engine, SIGNAL(signalHandlerException(QScriptValue)), SLOT(signalHandlerException(QScriptValue)));
}
bool ScriptedEffect::init(const QString &pathToScript)
{
QFile scriptFile(pathToScript);
if (!scriptFile.open(QIODevice::ReadOnly)) {
return false;
}
m_scriptFile = pathToScript;
QScriptValue effectsObject = m_engine->newQObject(effects, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater);
m_engine->globalObject().setProperty("effects", effectsObject, QScriptValue::Undeletable);
m_engine->globalObject().setProperty("Effect", m_engine->newQMetaObject(&AnimationEffect::staticMetaObject));
m_engine->globalObject().setProperty("effect", m_engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater), QScriptValue::Undeletable);
MetaScripting::registration(m_engine);
qScriptRegisterMetaType<KEffectWindowRef>(m_engine, effectWindowToScriptValue, effectWindowFromScriptValue);
// add our print
QScriptValue printFunc = m_engine->newFunction(kwinEffectScriptPrint);
printFunc.setData(m_engine->newQObject(this));
m_engine->globalObject().setProperty("print", printFunc);
QScriptValue ret = m_engine->evaluate(scriptFile.readAll());
if (ret.isError()) {
signalHandlerException(ret);
return false;
}
scriptFile.close();
return true;
}
void ScriptedEffect::signalHandlerException(const QScriptValue &value)
{
if (value.isError()) {
kDebug(1212) << "KWin Effect script encountered an error at [Line " << m_engine->uncaughtExceptionLineNumber() << "]";
kDebug(1212) << "Message: " << value.toString();
QScriptValueIterator iter(value);
while (iter.hasNext()) {
iter.next();
kDebug(1212) << " " << iter.name() << ": " << iter.value().toString();
}
}
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, float to, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay);
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QPoint to, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay);
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QPointF to, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay);
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QSize to, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay);
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QSizeF to, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay);
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, float to, float from, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay, FPx2(from));
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, float to, float to2, float from, float from2, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to, to2), curve, delay, FPx2(from, from2));
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QPoint to, QPoint from, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay, FPx2(from));
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QPointF to, QPointF from, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay, FPx2(from));
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QSize to, QSize from, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay, FPx2(from));
}
void ScriptedEffect::animate(EffectWindow *w, Attribute a, int ms, QSizeF to, QSizeF from, uint meta, QEasingCurve curve, int delay)
{
AnimationEffect::animate(w, a, meta, ms, FPx2(to), curve, delay, FPx2(from));
}
} // namespace

View file

@ -0,0 +1,65 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2012 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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_SCRIPTEDEFFECT_H
#define KWIN_SCRIPTEDEFFECT_H
#include <kwinanimationeffect.h>
class QScriptEngine;
class QScriptValue;
namespace KWin
{
class ScriptedEffect : public KWin::AnimationEffect
{
Q_OBJECT
public:
const QString &scriptFile() const {
return m_scriptFile;
}
static ScriptedEffect *create(const QString &pathToScript);
public Q_SLOTS:
void animate(KWin::EffectWindow *w, Attribute a, int ms, float to, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QPoint to, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QPointF to, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QSize to, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QSizeF to, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, float to, float from, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, float to, float to2, float from, float from2, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QPoint to, QPoint from, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QPointF to, QPointF from, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QSize to, QSize from, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
void animate(KWin::EffectWindow *w, Attribute a, int ms, QSizeF to, QSizeF from, uint meta = 0, QEasingCurve curve = QEasingCurve(), int delay = 0);
private Q_SLOTS:
void signalHandlerException(const QScriptValue &value);
private:
ScriptedEffect();
bool init(const QString &pathToScript);
QScriptEngine *m_engine;
QString m_scriptFile;
};
}
#endif // KWIN_SCRIPTEDEFFECT_H