2012-01-29 16:32:56 +00:00
|
|
|
/********************************************************************
|
|
|
|
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"
|
2012-03-25 07:59:01 +00:00
|
|
|
#include "scriptingutils.h"
|
2012-05-10 14:09:36 +00:00
|
|
|
#include "workspace_wrapper.h"
|
2013-01-21 08:04:06 +00:00
|
|
|
#ifdef KWIN_BUILD_SCREENEDGES
|
|
|
|
#include "../screenedge.h"
|
|
|
|
#endif
|
2012-01-29 16:32:56 +00:00
|
|
|
// KDE
|
2014-03-17 15:24:10 +00:00
|
|
|
#include <KConfigGroup>
|
2013-12-16 08:27:19 +00:00
|
|
|
#include <kconfigloader.h>
|
2012-01-29 16:32:56 +00:00
|
|
|
// Qt
|
2013-09-02 11:14:39 +00:00
|
|
|
#include <QDebug>
|
2013-02-26 08:00:51 +00:00
|
|
|
#include <QFile>
|
2012-01-29 16:32:56 +00:00
|
|
|
#include <QtScript/QScriptEngine>
|
|
|
|
#include <QtScript/QScriptValueIterator>
|
2013-08-03 20:34:24 +00:00
|
|
|
#include <QtCore/QStandardPaths>
|
2012-01-29 16:32:56 +00:00
|
|
|
|
|
|
|
typedef KWin::EffectWindow* KEffectWindowRef;
|
2012-03-09 12:16:09 +00:00
|
|
|
|
|
|
|
Q_DECLARE_METATYPE(KWin::AnimationData*)
|
|
|
|
Q_SCRIPT_DECLARE_QMETAOBJECT(KWin::AnimationData, QObject*)
|
|
|
|
|
2012-01-29 16:32:56 +00:00
|
|
|
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) {
|
2013-07-23 05:02:52 +00:00
|
|
|
result.append(QStringLiteral(" "));
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
result.append(context->argument(i).toString());
|
|
|
|
}
|
2013-09-02 11:14:39 +00:00
|
|
|
qDebug() << script->scriptFile() << ":" << result;
|
2012-01-29 16:32:56 +00:00
|
|
|
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
2012-02-01 13:47:20 +00:00
|
|
|
QScriptValue kwinEffectScriptAnimationTime(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
if (context->argumentCount() != 1) {
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
if (!context->argument(0).isNumber()) {
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
return Effect::animationTime(context->argument(0).toInteger());
|
|
|
|
}
|
|
|
|
|
2012-02-02 13:34:12 +00:00
|
|
|
QScriptValue kwinEffectDisplayWidth(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
Q_UNUSED(context)
|
|
|
|
Q_UNUSED(engine)
|
2014-02-24 15:13:30 +00:00
|
|
|
return displayWidth();
|
2012-02-02 13:34:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QScriptValue kwinEffectDisplayHeight(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
Q_UNUSED(context)
|
|
|
|
Q_UNUSED(engine)
|
2014-02-24 15:13:30 +00:00
|
|
|
return displayHeight();
|
2012-02-02 13:34:12 +00:00
|
|
|
}
|
|
|
|
|
2012-03-25 07:59:01 +00:00
|
|
|
QScriptValue kwinScriptGlobalShortcut(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
return globalShortcut<KWin::ScriptedEffect*>(context, engine);
|
|
|
|
}
|
|
|
|
|
2012-05-10 14:09:36 +00:00
|
|
|
QScriptValue kwinScriptScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
return registerScreenEdge<KWin::ScriptedEffect*>(context, engine);
|
|
|
|
}
|
|
|
|
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
struct AnimationSettings {
|
2013-02-28 18:52:16 +00:00
|
|
|
enum { Type = 1<<0, Curve = 1<<1, Delay = 1<<2, Duration = 1<<3 };
|
|
|
|
AnimationEffect::Attribute type;
|
2012-11-09 14:36:44 +00:00
|
|
|
QEasingCurve::Type curve;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
FPx2 from;
|
|
|
|
FPx2 to;
|
|
|
|
int delay;
|
2013-02-28 18:52:16 +00:00
|
|
|
uint duration;
|
|
|
|
uint set;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
AnimationSettings animationSettingsFromObject(QScriptValue &object)
|
|
|
|
{
|
|
|
|
AnimationSettings settings;
|
2013-02-28 18:52:16 +00:00
|
|
|
settings.set = 0;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
|
2013-07-23 05:02:52 +00:00
|
|
|
settings.to = qscriptvalue_cast<FPx2>(object.property(QStringLiteral("to")));
|
|
|
|
settings.from = qscriptvalue_cast<FPx2>(object.property(QStringLiteral("from")));
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue duration = object.property(QStringLiteral("duration"));
|
2013-02-28 18:52:16 +00:00
|
|
|
if (duration.isValid() && duration.isNumber()) {
|
|
|
|
settings.duration = duration.toUInt32();
|
|
|
|
settings.set |= AnimationSettings::Duration;
|
|
|
|
} else {
|
|
|
|
settings.duration = 0;
|
|
|
|
}
|
|
|
|
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue delay = object.property(QStringLiteral("delay"));
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
if (delay.isValid() && delay.isNumber()) {
|
|
|
|
settings.delay = delay.toInt32();
|
2013-02-28 18:52:16 +00:00
|
|
|
settings.set |= AnimationSettings::Delay;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
} else {
|
|
|
|
settings.delay = 0;
|
|
|
|
}
|
|
|
|
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue curve = object.property(QStringLiteral("curve"));
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
if (curve.isValid() && curve.isNumber()) {
|
2012-11-09 14:36:44 +00:00
|
|
|
settings.curve = static_cast<QEasingCurve::Type>(curve.toInt32());
|
2013-02-28 18:52:16 +00:00
|
|
|
settings.set |= AnimationSettings::Curve;
|
|
|
|
} else {
|
|
|
|
settings.curve = QEasingCurve::Linear;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue type = object.property(QStringLiteral("type"));
|
2013-02-28 18:52:16 +00:00
|
|
|
if (type.isValid() && type.isNumber()) {
|
|
|
|
settings.type = static_cast<AnimationEffect::Attribute>(type.toInt32());
|
|
|
|
settings.set |= AnimationSettings::Type;
|
|
|
|
} else {
|
|
|
|
settings.type = static_cast<AnimationEffect::Attribute>(-1);
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
}
|
|
|
|
|
2013-02-28 18:52:16 +00:00
|
|
|
QList<AnimationSettings> animationSettings(QScriptContext *context, ScriptedEffect *effect, EffectWindow **window)
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
{
|
2013-02-28 18:52:16 +00:00
|
|
|
QList<AnimationSettings> settings;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
if (!effect) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::ReferenceError, QStringLiteral("Internal Scripted KWin Effect error"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return settings;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
if (context->argumentCount() != 1) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::SyntaxError, QStringLiteral("Exactly one argument expected"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return settings;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
if (!context->argument(0).isObject()) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Argument needs to be an object"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return settings;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
QScriptValue object = context->argument(0);
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue windowProperty = object.property(QStringLiteral("window"));
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
if (!windowProperty.isValid() || !windowProperty.isObject()) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Window property missing in animation options"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return settings;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
2013-02-28 18:52:16 +00:00
|
|
|
*window = qobject_cast<EffectWindow*>(windowProperty.toQObject());
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
|
2013-02-28 18:52:16 +00:00
|
|
|
settings << animationSettingsFromObject(object); // global
|
|
|
|
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue animations = object.property(QStringLiteral("animations")); // array
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
if (animations.isValid()) {
|
|
|
|
if (!animations.isArray()) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Animations provided but not an array"));
|
2013-02-28 18:52:16 +00:00
|
|
|
settings.clear();
|
|
|
|
return settings;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
2013-07-23 05:02:52 +00:00
|
|
|
const int length = static_cast<int>(animations.property(QStringLiteral("length")).toInteger());
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
for (int i=0; i<length; ++i) {
|
|
|
|
QScriptValue value = animations.property(QString::number(i));
|
|
|
|
if (!value.isValid()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (value.isObject()) {
|
|
|
|
AnimationSettings s = animationSettingsFromObject(value);
|
2013-02-28 18:52:16 +00:00
|
|
|
const uint set = s.set | settings.at(0).set;
|
2013-04-13 10:13:22 +00:00
|
|
|
// Catch show stoppers (incompletable animation)
|
2013-02-28 18:52:16 +00:00
|
|
|
if (!(set & AnimationSettings::Type)) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Type property missing in animation options"));
|
2013-02-28 18:52:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!(set & AnimationSettings::Duration)) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Duration property missing in animation options"));
|
2013-02-28 18:52:16 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-04-13 10:13:22 +00:00
|
|
|
// Complete local animations from global settings
|
|
|
|
if (!(s.set & AnimationSettings::Duration)) {
|
|
|
|
s.duration = settings.at(0).duration;
|
|
|
|
}
|
|
|
|
if (!(s.set & AnimationSettings::Curve)) {
|
2013-02-28 18:52:16 +00:00
|
|
|
s.curve = settings.at(0).curve;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
2013-04-13 10:13:22 +00:00
|
|
|
if (!(s.set & AnimationSettings::Delay)) {
|
2013-02-28 18:52:16 +00:00
|
|
|
s.delay = settings.at(0).delay;
|
|
|
|
}
|
|
|
|
settings << s;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 18:52:16 +00:00
|
|
|
if (settings.count() == 1) {
|
|
|
|
const uint set = settings.at(0).set;
|
|
|
|
if (!(set & AnimationSettings::Type)) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Type property missing in animation options"));
|
2013-02-28 18:52:16 +00:00
|
|
|
settings.clear();
|
|
|
|
}
|
|
|
|
if (!(set & AnimationSettings::Duration)) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Duration property missing in animation options"));
|
2013-02-28 18:52:16 +00:00
|
|
|
settings.clear();
|
|
|
|
}
|
2013-04-13 10:13:22 +00:00
|
|
|
} else if (!(settings.at(0).set & AnimationSettings::Type)) { // invalid global
|
|
|
|
settings.removeAt(0); // -> get rid of it, only used to complete the others
|
2013-02-28 18:52:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
}
|
|
|
|
|
|
|
|
QScriptValue kwinEffectAnimate(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
|
|
|
|
EffectWindow *window;
|
|
|
|
QList<AnimationSettings> settings = animationSettings(context, effect, &window);
|
|
|
|
if (settings.empty()) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("No animations provided"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
if (!window) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Window property does not contain an EffectWindow"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QVariant> animIds;
|
|
|
|
foreach (const AnimationSettings &setting, settings) {
|
|
|
|
animIds << QVariant(effect->animate(window,
|
|
|
|
setting.type,
|
|
|
|
setting.duration,
|
|
|
|
setting.to,
|
|
|
|
setting.from,
|
2014-02-24 15:33:40 +00:00
|
|
|
nullptr,
|
2013-02-28 18:52:16 +00:00
|
|
|
setting.curve,
|
|
|
|
setting.delay));
|
|
|
|
}
|
|
|
|
return engine->newVariant(animIds);
|
|
|
|
}
|
|
|
|
|
|
|
|
QScriptValue kwinEffectSet(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
|
|
|
|
|
|
|
|
EffectWindow *window;
|
|
|
|
QList<AnimationSettings> settings = animationSettings(context, effect, &window);
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
if (settings.empty()) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("No animations provided"));
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
2013-02-28 18:52:16 +00:00
|
|
|
if (!window) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Window property does not contain an EffectWindow"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
QList<QVariant> animIds;
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
foreach (const AnimationSettings &setting, settings) {
|
2013-02-28 18:52:16 +00:00
|
|
|
animIds << QVariant(effect->set(window,
|
|
|
|
setting.type,
|
|
|
|
setting.duration,
|
|
|
|
setting.to,
|
|
|
|
setting.from,
|
2014-02-24 15:33:40 +00:00
|
|
|
nullptr,
|
2013-02-28 18:52:16 +00:00
|
|
|
setting.curve,
|
|
|
|
setting.delay));
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
|
2013-02-28 18:52:16 +00:00
|
|
|
return engine->newVariant(animIds);
|
|
|
|
}
|
|
|
|
|
|
|
|
QScriptValue kwinEffectCancel(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
|
|
|
|
if (context->argumentCount() != 1) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::SyntaxError, QStringLiteral("Exactly one argument expected"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
QVariant v = context->argument(0).toVariant();
|
|
|
|
QList<quint64> animIds;
|
|
|
|
bool ok = false;
|
|
|
|
if (v.isValid()) {
|
|
|
|
quint64 animId = v.toULongLong(&ok);
|
|
|
|
if (ok)
|
|
|
|
animIds << animId;
|
|
|
|
}
|
|
|
|
if (!ok) { // may still be a variantlist of variants being quint64
|
|
|
|
QList<QVariant> list = v.toList();
|
|
|
|
if (!list.isEmpty()) {
|
|
|
|
foreach (const QVariant &vv, list) {
|
|
|
|
quint64 animId = vv.toULongLong(&ok);
|
|
|
|
if (ok)
|
|
|
|
animIds << animId;
|
|
|
|
}
|
|
|
|
ok = !animIds.isEmpty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ok) {
|
2013-07-23 05:02:52 +00:00
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Argument needs to be one or several quint64"));
|
2013-02-28 18:52:16 +00:00
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const quint64 &animId, animIds) {
|
|
|
|
ok |= engine->newVariant(effect->cancel(animId)).toBool();
|
|
|
|
}
|
|
|
|
|
|
|
|
return engine->newVariant(ok);
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
}
|
|
|
|
|
2012-01-29 16:32:56 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2012-01-30 09:21:32 +00:00
|
|
|
QScriptValue fpx2ToScriptValue(QScriptEngine *eng, const KWin::FPx2 &fpx2)
|
|
|
|
{
|
|
|
|
QScriptValue val = eng->newObject();
|
2013-07-23 05:02:52 +00:00
|
|
|
val.setProperty(QStringLiteral("value1"), fpx2[0]);
|
|
|
|
val.setProperty(QStringLiteral("value2"), fpx2[1]);
|
2012-01-30 09:21:32 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fpx2FromScriptValue(const QScriptValue &value, KWin::FPx2 &fpx2)
|
|
|
|
{
|
|
|
|
if (value.isNull()) {
|
|
|
|
fpx2 = FPx2();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value.isNumber()) {
|
|
|
|
fpx2 = FPx2(value.toNumber());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value.isObject()) {
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue value1 = value.property(QStringLiteral("value1"));
|
|
|
|
QScriptValue value2 = value.property(QStringLiteral("value2"));
|
2012-01-30 09:21:32 +00:00
|
|
|
if (!value1.isValid() || !value2.isValid() || !value1.isNumber() || !value2.isNumber()) {
|
2013-09-02 11:14:39 +00:00
|
|
|
qDebug() << "Cannot cast scripted FPx2 to C++";
|
2012-01-30 09:21:32 +00:00
|
|
|
fpx2 = FPx2();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fpx2 = FPx2(value1.toNumber(), value2.toNumber());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-24 10:02:28 +00:00
|
|
|
ScriptedEffect *ScriptedEffect::create(KService::Ptr effect)
|
|
|
|
{
|
|
|
|
const QString name = effect->property(QStringLiteral("X-KDE-PluginInfo-Name")).toString();
|
|
|
|
const QString scriptName = effect->property(QStringLiteral("X-Plasma-MainScript")).toString();
|
|
|
|
if (scriptName.isEmpty()) {
|
|
|
|
qDebug() << "X-Plasma-MainScript not set";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
const QString scriptFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
|
|
|
QStringLiteral(KWIN_NAME) + QStringLiteral("/effects/") + name + QStringLiteral("/contents/") + scriptName);
|
|
|
|
if (scriptFile.isNull()) {
|
|
|
|
qDebug() << "Could not locate the effect script";
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-03-24 10:50:09 +00:00
|
|
|
return ScriptedEffect::create(name, scriptFile, effect->property(QStringLiteral("X-KDE-Ordering")).toInt());
|
2014-03-24 10:02:28 +00:00
|
|
|
}
|
|
|
|
|
2014-03-24 10:50:09 +00:00
|
|
|
ScriptedEffect *ScriptedEffect::create(const QString& effectName, const QString& pathToScript, int chainPosition)
|
2012-01-29 16:32:56 +00:00
|
|
|
{
|
|
|
|
ScriptedEffect *effect = new ScriptedEffect();
|
2012-02-01 13:26:54 +00:00
|
|
|
if (!effect->init(effectName, pathToScript)) {
|
2012-01-29 16:32:56 +00:00
|
|
|
delete effect;
|
2014-02-24 15:33:40 +00:00
|
|
|
return nullptr;
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
2014-03-24 10:50:09 +00:00
|
|
|
effect->m_chainPosition = chainPosition;
|
2012-01-29 16:32:56 +00:00
|
|
|
return effect;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScriptedEffect::ScriptedEffect()
|
|
|
|
: AnimationEffect()
|
|
|
|
, m_engine(new QScriptEngine(this))
|
2012-02-01 13:26:54 +00:00
|
|
|
, m_scriptFile(QString())
|
2014-02-24 15:33:40 +00:00
|
|
|
, m_config(nullptr)
|
2014-03-24 10:50:09 +00:00
|
|
|
, m_chainPosition(0)
|
2012-01-29 16:32:56 +00:00
|
|
|
{
|
|
|
|
connect(m_engine, SIGNAL(signalHandlerException(QScriptValue)), SLOT(signalHandlerException(QScriptValue)));
|
2012-05-10 14:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ScriptedEffect::~ScriptedEffect()
|
|
|
|
{
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
|
2012-02-01 13:26:54 +00:00
|
|
|
bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript)
|
2012-01-29 16:32:56 +00:00
|
|
|
{
|
|
|
|
QFile scriptFile(pathToScript);
|
|
|
|
if (!scriptFile.open(QIODevice::ReadOnly)) {
|
2013-09-02 11:14:39 +00:00
|
|
|
qDebug() << "Could not open script file: " << pathToScript;
|
2012-01-29 16:32:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-02-01 13:26:54 +00:00
|
|
|
m_effectName = effectName;
|
2012-01-29 16:32:56 +00:00
|
|
|
m_scriptFile = pathToScript;
|
2012-02-01 13:26:54 +00:00
|
|
|
|
2013-02-15 15:45:05 +00:00
|
|
|
// does the effect contain an KConfigXT file?
|
2013-08-03 20:34:24 +00:00
|
|
|
const QString kconfigXTFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral(KWIN_NAME) + QStringLiteral("/effects/") + m_effectName + QStringLiteral("/contents/config/main.xml"));
|
2013-02-15 15:45:05 +00:00
|
|
|
if (!kconfigXTFile.isNull()) {
|
|
|
|
KConfigGroup cg = effects->effectConfig(m_effectName);
|
|
|
|
QFile xmlFile(kconfigXTFile);
|
2013-12-16 08:27:19 +00:00
|
|
|
m_config = new KConfigLoader(cg, &xmlFile, this);
|
2014-03-25 15:29:03 +00:00
|
|
|
m_config->load();
|
2013-02-15 15:45:05 +00:00
|
|
|
}
|
|
|
|
|
2012-01-29 16:32:56 +00:00
|
|
|
QScriptValue effectsObject = m_engine->newQObject(effects, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater);
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("effects"), effectsObject, QScriptValue::Undeletable);
|
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("Effect"), m_engine->newQMetaObject(&ScriptedEffect::staticMetaObject));
|
2014-03-23 08:23:30 +00:00
|
|
|
#ifndef KWIN_UNIT_TEST
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("KWin"), m_engine->newQMetaObject(&WorkspaceWrapper::staticMetaObject));
|
2014-03-23 08:23:30 +00:00
|
|
|
#endif
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("QEasingCurve"), m_engine->newQMetaObject(&QEasingCurve::staticMetaObject));
|
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("effect"), m_engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater), QScriptValue::Undeletable);
|
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("AnimationData"), m_engine->scriptValueFromQMetaObject<AnimationData>());
|
2012-01-29 16:32:56 +00:00
|
|
|
MetaScripting::registration(m_engine);
|
|
|
|
qScriptRegisterMetaType<KEffectWindowRef>(m_engine, effectWindowToScriptValue, effectWindowFromScriptValue);
|
2012-01-30 09:21:32 +00:00
|
|
|
qScriptRegisterMetaType<KWin::FPx2>(m_engine, fpx2ToScriptValue, fpx2FromScriptValue);
|
2012-02-02 17:00:07 +00:00
|
|
|
qScriptRegisterSequenceMetaType<QList< KWin::EffectWindow* > >(m_engine);
|
2012-01-29 16:32:56 +00:00
|
|
|
// add our print
|
|
|
|
QScriptValue printFunc = m_engine->newFunction(kwinEffectScriptPrint);
|
|
|
|
printFunc.setData(m_engine->newQObject(this));
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("print"), printFunc);
|
2012-02-01 13:47:20 +00:00
|
|
|
// add our animationTime
|
|
|
|
QScriptValue animationTimeFunc = m_engine->newFunction(kwinEffectScriptAnimationTime);
|
|
|
|
animationTimeFunc.setData(m_engine->newQObject(this));
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("animationTime"), animationTimeFunc);
|
2012-02-02 13:34:12 +00:00
|
|
|
// add displayWidth and displayHeight
|
|
|
|
QScriptValue displayWidthFunc = m_engine->newFunction(kwinEffectDisplayWidth);
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("displayWidth"), displayWidthFunc);
|
2012-02-02 13:34:12 +00:00
|
|
|
QScriptValue displayHeightFunc = m_engine->newFunction(kwinEffectDisplayHeight);
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("displayHeight"), displayHeightFunc);
|
2012-03-25 07:59:01 +00:00
|
|
|
// add global Shortcut
|
|
|
|
registerGlobalShortcutFunction(this, m_engine, kwinScriptGlobalShortcut);
|
2012-05-10 14:09:36 +00:00
|
|
|
registerScreenEdgeFunction(this, m_engine, kwinScriptScreenEdge);
|
Adding more declarative way to animate a window in JavaScript
The current API call to animate a window does not feel very JavaScripty.
Therefore a new method "animate" is added to the global scope, which
takes a JavaScript object of the following structure:
{
window: EffectWindow, /* the window to animate, required */
duration: int, /* duration in msec, required */
curve: QEasingCurve.Type, /* global easing curve, optional */
type: Effect.Attribute, /* for first animation, optional */
from: FPx2, /* for first animation, optional */
to: FPx2, /* for first animation, optional */
delay: int, /* for first animation, optional */
animations: [ /* additional animations, optional */
{
curve: QEasingCurve.Type, /* overrides global */
type: Effect.Attribute,
from: FPx2,
to: FPx2,
delay: int
}
]
}
At least one animation needs to be specified either on the root level
or in the array of animations. Curve is the only property on root level
which is used in the animations, if not provided.
REVIEW: 107079
2012-10-27 15:43:14 +00:00
|
|
|
// add the animate method
|
|
|
|
QScriptValue animateFunc = m_engine->newFunction(kwinEffectAnimate);
|
|
|
|
animateFunc.setData(m_engine->newQObject(this));
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("animate"), animateFunc);
|
2012-01-29 16:32:56 +00:00
|
|
|
|
2013-02-28 18:52:16 +00:00
|
|
|
// and the set variant
|
|
|
|
QScriptValue setFunc = m_engine->newFunction(kwinEffectSet);
|
|
|
|
setFunc.setData(m_engine->newQObject(this));
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("set"), setFunc);
|
2013-02-28 18:52:16 +00:00
|
|
|
|
|
|
|
// cancel...
|
|
|
|
QScriptValue cancelFunc = m_engine->newFunction(kwinEffectCancel);
|
|
|
|
cancelFunc.setData(m_engine->newQObject(this));
|
2013-07-23 05:02:52 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("cancel"), cancelFunc);
|
2013-02-28 18:52:16 +00:00
|
|
|
|
2013-07-23 05:02:52 +00:00
|
|
|
QScriptValue ret = m_engine->evaluate(QString::fromUtf8(scriptFile.readAll()));
|
2012-01-29 16:32:56 +00:00
|
|
|
|
|
|
|
if (ret.isError()) {
|
|
|
|
signalHandlerException(ret);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
scriptFile.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptedEffect::signalHandlerException(const QScriptValue &value)
|
|
|
|
{
|
|
|
|
if (value.isError()) {
|
2013-09-02 11:14:39 +00:00
|
|
|
qDebug() << "KWin Effect script encountered an error at [Line " << m_engine->uncaughtExceptionLineNumber() << "]";
|
|
|
|
qDebug() << "Message: " << value.toString();
|
2012-01-29 16:32:56 +00:00
|
|
|
|
|
|
|
QScriptValueIterator iter(value);
|
|
|
|
while (iter.hasNext()) {
|
|
|
|
iter.next();
|
2013-09-02 11:14:39 +00:00
|
|
|
qDebug() << " " << iter.name() << ": " << iter.value().toString();
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 18:52:16 +00:00
|
|
|
uint metaFromData(KWin::AnimationData* data)
|
2012-01-29 16:32:56 +00:00
|
|
|
{
|
2012-03-09 12:16:09 +00:00
|
|
|
uint meta = 0;
|
|
|
|
if (data) {
|
|
|
|
if (data->axis() != 0) {
|
|
|
|
AnimationEffect::setMetaData(AnimationEffect::Axis, data->axis() -1, meta);
|
|
|
|
}
|
|
|
|
if (data->sourceAnchor() != 0) {
|
|
|
|
AnimationEffect::setMetaData(AnimationEffect::SourceAnchor, data->sourceAnchor(), meta);
|
|
|
|
}
|
|
|
|
if (data->targetAnchor() != 0) {
|
|
|
|
AnimationEffect::setMetaData(AnimationEffect::TargetAnchor, data->targetAnchor(), meta);
|
|
|
|
}
|
|
|
|
if (data->relativeSourceX() != 0) {
|
|
|
|
AnimationEffect::setMetaData(AnimationEffect::RelativeSourceX, data->relativeSourceX(), meta);
|
|
|
|
}
|
|
|
|
if (data->relativeSourceY() != 0) {
|
|
|
|
AnimationEffect::setMetaData(AnimationEffect::RelativeSourceY, data->relativeSourceY(), meta);
|
|
|
|
}
|
|
|
|
if (data->relativeTargetX() != 0) {
|
|
|
|
AnimationEffect::setMetaData(AnimationEffect::RelativeTargetX, data->relativeTargetX(), meta);
|
|
|
|
}
|
|
|
|
if (data->relativeTargetY() != 0) {
|
|
|
|
AnimationEffect::setMetaData(AnimationEffect::RelativeTargetY, data->relativeTargetY(), meta);
|
|
|
|
}
|
|
|
|
}
|
2013-02-28 18:52:16 +00:00
|
|
|
return meta;
|
|
|
|
}
|
|
|
|
|
|
|
|
quint64 ScriptedEffect::animate(KWin::EffectWindow* w, KWin::AnimationEffect::Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from, KWin::AnimationData* data, QEasingCurve::Type curve, int delay)
|
|
|
|
{
|
|
|
|
return AnimationEffect::animate(w, a, metaFromData(data), ms, to, QEasingCurve(curve), delay, from);
|
|
|
|
}
|
|
|
|
|
|
|
|
quint64 ScriptedEffect::set(KWin::EffectWindow* w, KWin::AnimationEffect::Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from, KWin::AnimationData* data, QEasingCurve::Type curve, int delay)
|
|
|
|
{
|
|
|
|
return AnimationEffect::set(w, a, metaFromData(data), ms, to, QEasingCurve(curve), delay, from);
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
|
2012-01-31 13:37:28 +00:00
|
|
|
bool ScriptedEffect::isGrabbed(EffectWindow* w, ScriptedEffect::DataRole grabRole)
|
|
|
|
{
|
|
|
|
void *e = w->data(static_cast<KWin::DataRole>(grabRole)).value<void*>();
|
|
|
|
if (e) {
|
|
|
|
return e != this;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-01 13:26:54 +00:00
|
|
|
void ScriptedEffect::reconfigure(ReconfigureFlags flags)
|
|
|
|
{
|
|
|
|
AnimationEffect::reconfigure(flags);
|
2013-02-15 15:45:05 +00:00
|
|
|
if (m_config) {
|
2014-03-25 15:29:03 +00:00
|
|
|
m_config->read();
|
2013-02-15 15:45:05 +00:00
|
|
|
}
|
2012-02-01 13:26:54 +00:00
|
|
|
emit configChanged();
|
|
|
|
}
|
|
|
|
|
2012-03-25 07:59:01 +00:00
|
|
|
void ScriptedEffect::registerShortcut(QAction *a, QScriptValue callback)
|
|
|
|
{
|
|
|
|
m_shortcutCallbacks.insert(a, callback);
|
|
|
|
connect(a, SIGNAL(triggered(bool)), SLOT(globalShortcutTriggered()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptedEffect::globalShortcutTriggered()
|
|
|
|
{
|
|
|
|
callGlobalShortcutCallback<KWin::ScriptedEffect*>(this, sender());
|
|
|
|
}
|
|
|
|
|
2013-01-22 11:47:06 +00:00
|
|
|
bool ScriptedEffect::borderActivated(ElectricBorder edge)
|
2012-05-10 14:09:36 +00:00
|
|
|
{
|
|
|
|
screenEdgeActivated(this, edge);
|
2013-01-22 11:47:06 +00:00
|
|
|
return true;
|
2012-05-10 14:09:36 +00:00
|
|
|
}
|
|
|
|
|
2012-02-10 08:11:28 +00:00
|
|
|
QVariant ScriptedEffect::readConfig(const QString &key, const QVariant defaultValue)
|
2012-02-01 13:26:54 +00:00
|
|
|
{
|
2013-02-15 15:45:05 +00:00
|
|
|
if (!m_config) {
|
|
|
|
return defaultValue;
|
|
|
|
}
|
|
|
|
return m_config->property(key);
|
2012-02-01 13:26:54 +00:00
|
|
|
}
|
|
|
|
|
2012-03-09 12:16:09 +00:00
|
|
|
AnimationData::AnimationData (QObject* parent)
|
|
|
|
: QObject (parent)
|
|
|
|
, m_sourceAnchor((AnimationEffect::Anchor)0)
|
|
|
|
, m_targetAnchor((AnimationEffect::Anchor)0)
|
|
|
|
, m_relativeSourceX(0)
|
|
|
|
, m_relativeSourceY(0)
|
|
|
|
, m_relativeTargetX(0)
|
|
|
|
, m_relativeTargetY(0)
|
|
|
|
, m_axis((AnimationData::Axis)0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationData::Axis AnimationData::axis() const
|
|
|
|
{
|
|
|
|
return m_axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AnimationData::relativeSourceX() const
|
|
|
|
{
|
|
|
|
return m_relativeSourceX;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AnimationData::relativeSourceY() const
|
|
|
|
{
|
|
|
|
return m_relativeSourceY;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AnimationData::relativeTargetX() const
|
|
|
|
{
|
|
|
|
return m_relativeTargetX;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AnimationData::relativeTargetY() const
|
|
|
|
{
|
|
|
|
return m_relativeTargetY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationData::setRelativeSourceX(int relativeSourceX)
|
|
|
|
{
|
|
|
|
m_relativeSourceX = relativeSourceX;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationData::setRelativeSourceY(int relativeSourceY)
|
|
|
|
{
|
|
|
|
m_relativeSourceY = relativeSourceY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationData::setRelativeTargetX(int relativeTargetX)
|
|
|
|
{
|
|
|
|
m_relativeTargetX = relativeTargetX;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationData::setRelativeTargetY(int relativeTargetY)
|
|
|
|
{
|
|
|
|
m_relativeTargetY = relativeTargetY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationData::setAxis(AnimationData::Axis axis)
|
|
|
|
{
|
|
|
|
m_axis = axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationData::setSourceAnchor(AnimationEffect::Anchor sourceAnchor)
|
|
|
|
{
|
|
|
|
m_sourceAnchor = sourceAnchor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationData::setTargetAnchor(AnimationEffect::Anchor targetAnchor)
|
|
|
|
{
|
|
|
|
m_targetAnchor = targetAnchor;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationEffect::Anchor AnimationData::sourceAnchor() const
|
|
|
|
{
|
|
|
|
return m_sourceAnchor;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationEffect::Anchor AnimationData::targetAnchor() const
|
|
|
|
{
|
|
|
|
return m_targetAnchor;
|
|
|
|
}
|
|
|
|
|
2012-01-29 16:32:56 +00:00
|
|
|
} // namespace
|