diff --git a/effects/maximize/package/contents/code/maximize.js b/effects/maximize/package/contents/code/maximize.js
index 75413b7d3f..744021b8cd 100644
--- a/effects/maximize/package/contents/code/maximize.js
+++ b/effects/maximize/package/contents/code/maximize.js
@@ -16,7 +16,7 @@ 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 .
*********************************************************************/
-/*global effect, effects, animationTime, Effect*/
+/*global effect, effects, animate, animationTime, Effect*/
var maximizeEffect = {
duration: animationTime(250),
loadConfig: function () {
@@ -31,19 +31,30 @@ var maximizeEffect = {
var oldGeometry, newGeometry;
oldGeometry = window.oldGeometry;
newGeometry = window.geometry;
- effect.animate(window, Effect.Scale, maximizeEffect.duration, {
- value1: 1.0,
- value2: 1.0
- }, {
- value1: oldGeometry.width / newGeometry.width,
- value2: oldGeometry.height / newGeometry.height
- });
- effect.animate(window, Effect.Translation, maximizeEffect.duration, {
- value1: 0,
- value2: 0
- }, {
- value1: oldGeometry.x - newGeometry.x - (newGeometry.width / 2 - oldGeometry.width / 2),
- value2: oldGeometry.y - newGeometry.y - (newGeometry.height / 2 - oldGeometry.height / 2)
+ animate({
+ window: window,
+ duration: maximizeEffect.duration,
+ animations: [{
+ type: Effect.Scale,
+ to: {
+ value1: 1.0,
+ value2: 1.0
+ },
+ from: {
+ value1: oldGeometry.width / newGeometry.width,
+ value2: oldGeometry.height / newGeometry.height
+ }
+ }, {
+ type: Effect.Translation,
+ to: {
+ value1: 0,
+ value2: 0
+ },
+ from: {
+ value1: oldGeometry.x - newGeometry.x - (newGeometry.width / 2 - oldGeometry.width / 2),
+ value2: oldGeometry.y - newGeometry.y - (newGeometry.height / 2 - oldGeometry.height / 2)
+ }
+ }]
});
},
geometryChange: function (window, oldGeometry) {
diff --git a/scripting/documentation-effect-global.xml b/scripting/documentation-effect-global.xml
index 983827fa5f..e5440e0ba5 100644
--- a/scripting/documentation-effect-global.xml
+++ b/scripting/documentation-effect-global.xml
@@ -41,6 +41,39 @@
+
+ Q_SCRIPTABLE void
+ void KWin::ScriptedEffect::animate
+ (settings)
+ animate
+
+
+Schedules one or many animations for one window. The animations are defined through the settings object providing
+a more declarative way to specify the animations than the animate call on the effect object. The settings object
+supports the following attributes:
+<syntaxhighlight lang="javascript">
+{
+ 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
+ }
+ ]
+}
+</syntaxhighlight>
+At least one animation needs to be specified either with the top-level properties or in the animations list.
+
+
Q_SCRIPTABLE void
void KWin::ScriptedEffect::print
diff --git a/scripting/scriptedeffect.cpp b/scripting/scriptedeffect.cpp
index 610f02a81d..4a7e8e1607 100644
--- a/scripting/scriptedeffect.cpp
+++ b/scripting/scriptedeffect.cpp
@@ -89,6 +89,128 @@ QScriptValue kwinScriptScreenEdge(QScriptContext *context, QScriptEngine *engine
return registerScreenEdge(context, engine);
}
+struct AnimationSettings {
+ AnimationEffect::Attribute a;
+ QEasingCurve curve;
+ bool curveSet;
+ FPx2 from;
+ FPx2 to;
+ int delay;
+ bool valid;
+};
+
+AnimationSettings animationSettingsFromObject(QScriptValue &object)
+{
+ AnimationSettings settings;
+ settings.valid = true;
+ settings.curveSet = false;
+
+ settings.to = qscriptvalue_cast(object.property("to"));
+ settings.from = qscriptvalue_cast(object.property("from"));
+
+ QScriptValue delay = object.property("delay");
+ if (delay.isValid() && delay.isNumber()) {
+ settings.delay = delay.toInt32();
+ } else {
+ settings.delay = 0;
+ }
+
+ QScriptValue curve = object.property("curve");
+ if (curve.isValid() && curve.isNumber()) {
+ settings.curve = QEasingCurve(static_cast(curve.toInt32()));
+ settings.curveSet = true;
+ }
+
+ QScriptValue type = object.property("type");
+ if (!type.isValid() || !type.isNumber()) {
+ settings.valid = false;
+ }
+ settings.a = static_cast(type.toInt32());
+
+ return settings;
+}
+
+QScriptValue kwinEffectAnimate(QScriptContext *context, QScriptEngine *engine)
+{
+ ScriptedEffect *effect = qobject_cast(context->callee().data().toQObject());
+ if (!effect) {
+ context->throwError(QScriptContext::ReferenceError, "Internal Scripted KWin Effect error");
+ return engine->undefinedValue();
+ }
+ if (context->argumentCount() != 1) {
+ context->throwError(QScriptContext::SyntaxError, "Exactly one argument expected");
+ return engine->undefinedValue();
+ }
+ if (!context->argument(0).isObject()) {
+ context->throwError(QScriptContext::TypeError, "Argument needs to be an object");
+ return engine->undefinedValue();
+ }
+ QScriptValue object = context->argument(0);
+ QScriptValue windowProperty = object.property("window");
+ if (!windowProperty.isValid() || !windowProperty.isObject()) {
+ context->throwError(QScriptContext::TypeError, "Window property missing in animation options");
+ return engine->undefinedValue();
+ }
+ EffectWindow *window = qobject_cast(windowProperty.toQObject());
+ if (!window) {
+ context->throwError(QScriptContext::TypeError, "Window property does not contain an EffectWindow");
+ return engine->undefinedValue();
+ }
+ QScriptValue durationProperty = object.property("duration");
+ if (!durationProperty.isValid() || !durationProperty.isNumber()) {
+ context->throwError(QScriptContext::TypeError, "Duration property missing in animation options");
+ return engine->undefinedValue();
+ }
+ const int duration = durationProperty.toInt32();
+
+ QEasingCurve curve;
+ QList settings;
+ AnimationSettings globalSettings = animationSettingsFromObject(object);
+ if (globalSettings.valid) {
+ settings << globalSettings;
+ if (globalSettings.curveSet) {
+ curve = globalSettings.curve;
+ }
+ }
+ QScriptValue animations = object.property("animations");
+ if (animations.isValid()) {
+ if (!animations.isArray()) {
+ context->throwError(QScriptContext::TypeError, "Animations provided but not an array");
+ return engine->undefinedValue();
+ }
+ const int length = static_cast(animations.property("length").toInteger());
+ for (int i=0; ithrowError(QScriptContext::TypeError, "No animations provided");
+ return engine->undefinedValue();
+ }
+ foreach (const AnimationSettings &setting, settings) {
+ effect->animate(window,
+ setting.a,
+ duration,
+ setting.to,
+ setting.from,
+ NULL,
+ setting.curveSet ? setting.curve : curve,
+ setting.delay);
+ }
+
+ return engine->newVariant(true);
+}
+
QScriptValue effectWindowToScriptValue(QScriptEngine *eng, const KEffectWindowRef &window)
{
return eng->newQObject(window, QScriptEngine::QtOwnership,
@@ -198,6 +320,10 @@ bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript
// add global Shortcut
registerGlobalShortcutFunction(this, m_engine, kwinScriptGlobalShortcut);
registerScreenEdgeFunction(this, m_engine, kwinScriptScreenEdge);
+ // add the animate method
+ QScriptValue animateFunc = m_engine->newFunction(kwinEffectAnimate);
+ animateFunc.setData(m_engine->newQObject(this));
+ m_engine->globalObject().setProperty("animate", animateFunc);
QScriptValue ret = m_engine->evaluate(scriptFile.readAll());