2020-08-02 22:22:19 +00:00
|
|
|
/*
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
2012-01-29 16:32:56 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
|
2012-01-29 16:32:56 +00:00
|
|
|
|
2020-08-02 22:22:19 +00:00
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2012-01-29 16:32:56 +00:00
|
|
|
|
|
|
|
#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"
|
2016-06-08 10:46:02 +00:00
|
|
|
#include "../screens.h"
|
2013-01-21 08:04:06 +00:00
|
|
|
#include "../screenedge.h"
|
2015-07-31 11:24:56 +00:00
|
|
|
#include "scripting_logging.h"
|
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>
|
2015-07-06 14:50:33 +00:00
|
|
|
#include <KPluginMetaData>
|
2012-01-29 16:32:56 +00:00
|
|
|
// Qt
|
2013-02-26 08:00:51 +00:00
|
|
|
#include <QFile>
|
2012-01-29 16:32:56 +00:00
|
|
|
#include <QtScript/QScriptEngine>
|
|
|
|
#include <QtScript/QScriptValueIterator>
|
2018-06-05 10:52:57 +00:00
|
|
|
#include <QStandardPaths>
|
2012-01-29 16:32:56 +00:00
|
|
|
|
|
|
|
typedef KWin::EffectWindow* KEffectWindowRef;
|
2012-03-09 12:16:09 +00:00
|
|
|
|
2016-11-16 15:53:17 +00:00
|
|
|
Q_DECLARE_METATYPE(KSharedConfigPtr)
|
|
|
|
|
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) {
|
2015-11-05 14:14:06 +00:00
|
|
|
result.append(QLatin1Char(' '));
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
result.append(context->argument(i).toString());
|
|
|
|
}
|
2015-07-31 11:24:56 +00:00
|
|
|
qCDebug(KWIN_SCRIPTING) << 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)
|
2016-06-08 10:46:02 +00:00
|
|
|
return screens()->displaySize().width();
|
2012-02-02 13:34:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QScriptValue kwinEffectDisplayHeight(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
Q_UNUSED(context)
|
|
|
|
Q_UNUSED(engine)
|
2016-06-08 10:46:02 +00:00
|
|
|
return screens()->displaySize().height();
|
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);
|
|
|
|
}
|
|
|
|
|
2017-04-02 13:42:18 +00:00
|
|
|
QScriptValue kwinRegisterTouchScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
return registerTouchScreenEdge<KWin::ScriptedEffect*>(context, engine);
|
|
|
|
}
|
|
|
|
|
|
|
|
QScriptValue kwinUnregisterTouchScreenEdge(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
return unregisterTouchScreenEdge<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 {
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
enum {
|
|
|
|
Type = 1<<0,
|
|
|
|
Curve = 1<<1,
|
|
|
|
Delay = 1<<2,
|
|
|
|
Duration = 1<<3,
|
|
|
|
FullScreen = 1<<4,
|
|
|
|
KeepAlive = 1<<5
|
|
|
|
};
|
2013-02-28 18:52:16 +00:00
|
|
|
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;
|
2015-03-28 23:15:22 +00:00
|
|
|
uint metaData;
|
2018-10-03 00:11:59 +00:00
|
|
|
bool fullScreenEffect;
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
bool keepAlive;
|
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;
|
2015-03-28 23:15:22 +00:00
|
|
|
settings.metaData = 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
|
|
|
}
|
|
|
|
|
2018-10-03 00:11:59 +00:00
|
|
|
QScriptValue isFullScreen = object.property(QStringLiteral("fullScreen"));
|
|
|
|
if (isFullScreen.isValid() && isFullScreen.isBool()) {
|
|
|
|
settings.fullScreenEffect = isFullScreen.toBool();
|
|
|
|
settings.set |= AnimationSettings::FullScreen;
|
|
|
|
} else {
|
|
|
|
settings.fullScreenEffect = false;
|
|
|
|
}
|
|
|
|
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
QScriptValue keepAlive = object.property(QStringLiteral("keepAlive"));
|
|
|
|
if (keepAlive.isValid() && keepAlive.isBool()) {
|
|
|
|
settings.keepAlive = keepAlive.toBool();
|
|
|
|
settings.set |= AnimationSettings::KeepAlive;
|
|
|
|
} else {
|
|
|
|
settings.keepAlive = true;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2018-10-10 08:58:17 +00:00
|
|
|
if (!(s.set & AnimationSettings::FullScreen)) {
|
|
|
|
s.fullScreenEffect = settings.at(0).fullScreenEffect;
|
|
|
|
}
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
if (!(s.set & AnimationSettings::KeepAlive)) {
|
|
|
|
s.keepAlive = settings.at(0).keepAlive;
|
|
|
|
}
|
2015-03-28 23:15:22 +00:00
|
|
|
|
|
|
|
s.metaData = 0;
|
|
|
|
typedef QMap<AnimationEffect::MetaType, QString> MetaTypeMap;
|
|
|
|
static MetaTypeMap metaTypes({
|
|
|
|
{AnimationEffect::SourceAnchor, QStringLiteral("sourceAnchor")},
|
|
|
|
{AnimationEffect::TargetAnchor, QStringLiteral("targetAnchor")},
|
|
|
|
{AnimationEffect::RelativeSourceX, QStringLiteral("relativeSourceX")},
|
|
|
|
{AnimationEffect::RelativeSourceY, QStringLiteral("relativeSourceY")},
|
|
|
|
{AnimationEffect::RelativeTargetX, QStringLiteral("relativeTargetX")},
|
|
|
|
{AnimationEffect::RelativeTargetY, QStringLiteral("relativeTargetY")},
|
|
|
|
{AnimationEffect::Axis, QStringLiteral("axis")}
|
|
|
|
});
|
|
|
|
|
|
|
|
for (MetaTypeMap::const_iterator it = metaTypes.constBegin(),
|
|
|
|
end = metaTypes.constEnd(); it != end; ++it) {
|
|
|
|
QScriptValue metaVal = value.property(*it);
|
|
|
|
if (metaVal.isValid() && metaVal.isNumber()) {
|
|
|
|
AnimationEffect::setMetaData(it.key(), metaVal.toInt32(), s.metaData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-28 18:52:16 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2016-02-10 15:55:22 +00:00
|
|
|
QScriptValue array = engine->newArray(settings.length());
|
|
|
|
int i = 0;
|
2013-02-28 18:52:16 +00:00
|
|
|
foreach (const AnimationSettings &setting, settings) {
|
2016-02-10 15:55:22 +00:00
|
|
|
array.setProperty(i, (uint)effect->animate(window,
|
2013-02-28 18:52:16 +00:00
|
|
|
setting.type,
|
|
|
|
setting.duration,
|
|
|
|
setting.to,
|
|
|
|
setting.from,
|
2015-03-28 23:15:22 +00:00
|
|
|
setting.metaData,
|
2013-02-28 18:52:16 +00:00
|
|
|
setting.curve,
|
2018-10-03 00:11:59 +00:00
|
|
|
setting.delay,
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
setting.fullScreenEffect,
|
|
|
|
setting.keepAlive));
|
2016-02-10 15:55:22 +00:00
|
|
|
++i;
|
2013-02-28 18:52:16 +00:00
|
|
|
}
|
2016-02-10 15:55:22 +00:00
|
|
|
return array;
|
2013-02-28 18:52:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2015-03-28 23:15:22 +00:00
|
|
|
setting.metaData,
|
2013-02-28 18:52:16 +00:00
|
|
|
setting.curve,
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
setting.delay,
|
|
|
|
setting.fullScreenEffect,
|
|
|
|
setting.keepAlive));
|
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);
|
|
|
|
}
|
|
|
|
|
2016-02-03 18:10:00 +00:00
|
|
|
QList<quint64> animations(const QVariant &v, bool *ok)
|
2013-02-28 18:52:16 +00:00
|
|
|
{
|
|
|
|
QList<quint64> animIds;
|
2016-02-03 18:10:00 +00:00
|
|
|
*ok = false;
|
2013-02-28 18:52:16 +00:00
|
|
|
if (v.isValid()) {
|
2016-02-03 18:10:00 +00:00
|
|
|
quint64 animId = v.toULongLong(ok);
|
|
|
|
if (*ok)
|
2013-02-28 18:52:16 +00:00
|
|
|
animIds << animId;
|
|
|
|
}
|
2016-02-03 18:10:00 +00:00
|
|
|
if (!*ok) { // may still be a variantlist of variants being quint64
|
2013-02-28 18:52:16 +00:00
|
|
|
QList<QVariant> list = v.toList();
|
|
|
|
if (!list.isEmpty()) {
|
|
|
|
foreach (const QVariant &vv, list) {
|
2016-02-03 18:10:00 +00:00
|
|
|
quint64 animId = vv.toULongLong(ok);
|
|
|
|
if (*ok)
|
2013-02-28 18:52:16 +00:00
|
|
|
animIds << animId;
|
|
|
|
}
|
2016-02-03 18:10:00 +00:00
|
|
|
*ok = !animIds.isEmpty();
|
2013-02-28 18:52:16 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-03 18:10:00 +00:00
|
|
|
return animIds;
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
|
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()) {
|
2015-07-31 11:24:56 +00:00
|
|
|
qCDebug(KWIN_SCRIPTING) << "Cannot cast scripted FPx2 to C++";
|
2012-01-30 09:21:32 +00:00
|
|
|
fpx2 = FPx2();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fpx2 = FPx2(value1.toNumber(), value2.toNumber());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-03 18:10:00 +00:00
|
|
|
QScriptValue kwinEffectRetarget(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
|
|
|
|
if (context->argumentCount() < 2 || context->argumentCount() > 3) {
|
|
|
|
context->throwError(QScriptContext::SyntaxError, QStringLiteral("2 or 3 arguments expected"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
QVariant v = context->argument(0).toVariant();
|
|
|
|
bool ok = false;
|
|
|
|
QList<quint64> animIds = animations(v, &ok);
|
|
|
|
if (!ok) {
|
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Argument needs to be one or several quint64"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
FPx2 target;
|
|
|
|
fpx2FromScriptValue(context->argument(1), target);
|
|
|
|
|
2016-02-26 09:27:34 +00:00
|
|
|
ok = false;
|
2016-02-16 14:06:56 +00:00
|
|
|
const int remainingTime = context->argumentCount() == 3 ? context->argument(2).toVariant().toInt() : -1;
|
2016-02-03 18:10:00 +00:00
|
|
|
foreach (const quint64 &animId, animIds) {
|
2016-02-26 09:27:34 +00:00
|
|
|
ok = effect->retarget(animId, target, remainingTime);
|
|
|
|
if (!ok) {
|
|
|
|
break;
|
|
|
|
}
|
2016-02-03 18:10:00 +00:00
|
|
|
}
|
|
|
|
|
2016-02-26 09:27:34 +00:00
|
|
|
return QScriptValue(ok);
|
2016-02-03 18:10:00 +00:00
|
|
|
}
|
|
|
|
|
[scripting] Introduce redirect function
Summary:
Consider current implementation of the Squash effect: if a window was
minimized, an animation will be started; if the window is unminimized
and the animation is still active (that can happen when user clicks on
app's icon really fast), the animation will be stopped and a new one will
be created. Such behavior can lead to rapid jumps in the observed
"animation".
A better approach would be first try to **reverse** the already active
animation, and if that attempt wasn't successful, start a new animation.
This patch introduces a new function to the scripted effects API that
lets JavaScript effects to control direction of animations. The
prototype of the function looks as follows:
redirect(<animation id(s)>, <direction>, [<termination policy>])
the first argument is an animation id or a list of animation ids, the
second argument specifies the new direction of the animation or
animations if a list of ids was passed as the first argument. The
third argument specifies whether the animation(s) should be terminated
when it(they) reaches the source position, currently it's relevant only
for animations that are created with set() function. The termination
policy argument is optional, by default it's Effect.TerminateAtSource.
We can use this function to fix issues with rapid jumps in the Squash
effect. Also, redirect() lets us to write effects for simple animations
in slightly different style: first, we have to start the main animation
(e.g. for the Dialog Parent effect, it would be dimming of main windows)
and then change direction of the animation depending on external events,
e.g. when the Desktop Cube effect is activated.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16449
2018-10-24 19:58:29 +00:00
|
|
|
QScriptValue kwinEffectRedirect(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
if (context->argumentCount() != 2 && context->argumentCount() != 3) {
|
|
|
|
const QString errorMessage = QStringLiteral("redirect() takes either 2 or 3 arguments (%1 given)")
|
|
|
|
.arg(context->argumentCount());
|
|
|
|
context->throwError(QScriptContext::SyntaxError, errorMessage);
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok = false;
|
|
|
|
QList<quint64> animationIds = animations(context->argument(0).toVariant(), &ok);
|
|
|
|
if (!ok) {
|
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Argument needs to be one or several quint64"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
const QScriptValue wrappedDirection = context->argument(1);
|
|
|
|
if (!wrappedDirection.isNumber()) {
|
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Direction has invalid type"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto direction = static_cast<AnimationEffect::Direction>(wrappedDirection.toInt32());
|
|
|
|
switch (direction) {
|
|
|
|
case AnimationEffect::Forward:
|
|
|
|
case AnimationEffect::Backward:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
context->throwError(QScriptContext::SyntaxError, QStringLiteral("Unknown direction"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimationEffect::TerminationFlags terminationFlags = AnimationEffect::TerminateAtSource;
|
|
|
|
if (context->argumentCount() >= 3) {
|
|
|
|
const QScriptValue wrappedTerminationFlags = context->argument(2);
|
|
|
|
if (!wrappedTerminationFlags.isNumber()) {
|
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Termination flags argument has invalid type"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
terminationFlags = static_cast<AnimationEffect::TerminationFlags>(wrappedTerminationFlags.toInt32());
|
|
|
|
}
|
|
|
|
|
|
|
|
ScriptedEffect *effect = qobject_cast<ScriptedEffect *>(context->callee().data().toQObject());
|
|
|
|
for (const quint64 &animationId : qAsConst(animationIds)) {
|
|
|
|
if (!effect->redirect(animationId, direction, terminationFlags)) {
|
|
|
|
return QScriptValue(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QScriptValue(true);
|
|
|
|
}
|
|
|
|
|
2018-10-25 18:02:36 +00:00
|
|
|
QScriptValue kwinEffectComplete(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
if (context->argumentCount() != 1) {
|
|
|
|
const QString errorMessage = QStringLiteral("complete() takes exactly 1 arguments (%1 given)")
|
|
|
|
.arg(context->argumentCount());
|
|
|
|
context->throwError(QScriptContext::SyntaxError, errorMessage);
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok = false;
|
|
|
|
QList<quint64> animationIds = animations(context->argument(0).toVariant(), &ok);
|
|
|
|
if (!ok) {
|
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Argument needs to be one or several quint64"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
ScriptedEffect *effect = qobject_cast<ScriptedEffect *>(context->callee().data().toQObject());
|
|
|
|
for (const quint64 &animationId : qAsConst(animationIds)) {
|
|
|
|
if (!effect->complete(animationId)) {
|
|
|
|
return QScriptValue(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QScriptValue(true);
|
|
|
|
}
|
|
|
|
|
2016-02-03 18:10:00 +00:00
|
|
|
QScriptValue kwinEffectCancel(QScriptContext *context, QScriptEngine *engine)
|
|
|
|
{
|
|
|
|
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
|
|
|
|
if (context->argumentCount() != 1) {
|
|
|
|
context->throwError(QScriptContext::SyntaxError, QStringLiteral("Exactly one argument expected"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
QVariant v = context->argument(0).toVariant();
|
|
|
|
bool ok = false;
|
|
|
|
QList<quint64> animIds = animations(v, &ok);
|
|
|
|
if (!ok) {
|
|
|
|
context->throwError(QScriptContext::TypeError, QStringLiteral("Argument needs to be one or several quint64"));
|
|
|
|
return engine->undefinedValue();
|
|
|
|
}
|
|
|
|
foreach (const quint64 &animId, animIds) {
|
|
|
|
ok |= engine->newVariant(effect->cancel(animId)).toBool();
|
|
|
|
}
|
|
|
|
|
|
|
|
return engine->newVariant(ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2015-07-06 14:50:33 +00:00
|
|
|
ScriptedEffect *ScriptedEffect::create(const KPluginMetaData &effect)
|
2014-03-24 10:02:28 +00:00
|
|
|
{
|
2015-07-06 14:50:33 +00:00
|
|
|
const QString name = effect.pluginId();
|
|
|
|
const QString scriptName = effect.value(QStringLiteral("X-Plasma-MainScript"));
|
2014-03-24 10:02:28 +00:00
|
|
|
if (scriptName.isEmpty()) {
|
2015-07-31 11:24:56 +00:00
|
|
|
qCDebug(KWIN_SCRIPTING) << "X-Plasma-MainScript not set";
|
2014-03-24 10:02:28 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
const QString scriptFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
|
2015-11-05 14:14:06 +00:00
|
|
|
QLatin1String(KWIN_NAME "/effects/") + name + QLatin1String("/contents/") + scriptName);
|
2014-03-24 10:02:28 +00:00
|
|
|
if (scriptFile.isNull()) {
|
2015-07-31 11:24:56 +00:00
|
|
|
qCDebug(KWIN_SCRIPTING) << "Could not locate the effect script";
|
2014-03-24 10:02:28 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2015-07-06 14:50:33 +00:00
|
|
|
return ScriptedEffect::create(name, scriptFile, effect.value(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;
|
|
|
|
}
|
|
|
|
|
2016-08-10 07:24:53 +00:00
|
|
|
bool ScriptedEffect::supported()
|
|
|
|
{
|
|
|
|
return effects->animationsSupported();
|
|
|
|
}
|
|
|
|
|
2012-01-29 16:32:56 +00:00
|
|
|
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
|
|
|
{
|
2018-10-03 00:11:59 +00:00
|
|
|
Q_ASSERT(effects);
|
2020-09-23 18:39:59 +00:00
|
|
|
connect(m_engine, &QScriptEngine::signalHandlerException, this, &ScriptedEffect::signalHandlerException);
|
2018-10-03 00:11:59 +00:00
|
|
|
connect(effects, &EffectsHandler::activeFullScreenEffectChanged, this, [this]() {
|
|
|
|
Effect* fullScreenEffect = effects->activeFullScreenEffect();
|
|
|
|
if (fullScreenEffect == m_activeFullScreenEffect) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (m_activeFullScreenEffect == this || fullScreenEffect == this) {
|
|
|
|
emit isActiveFullScreenEffectChanged();
|
|
|
|
}
|
|
|
|
m_activeFullScreenEffect = fullScreenEffect;
|
|
|
|
});
|
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)) {
|
2015-07-31 11:24:56 +00:00
|
|
|
qCDebug(KWIN_SCRIPTING) << "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?
|
2015-11-05 14:14:06 +00:00
|
|
|
const QString kconfigXTFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String(KWIN_NAME "/effects/") + m_effectName + QLatin1String("/contents/config/main.xml"));
|
2013-02-15 15:45:05 +00:00
|
|
|
if (!kconfigXTFile.isNull()) {
|
2016-11-16 15:53:17 +00:00
|
|
|
KConfigGroup cg = QCoreApplication::instance()->property("config").value<KSharedConfigPtr>()->group(QStringLiteral("Effect-%1").arg(m_effectName));
|
2013-02-15 15:45:05 +00:00
|
|
|
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
|
2016-11-02 21:56:56 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("KWin"), m_engine->newQMetaObject(&QtScriptWorkspaceWrapper::staticMetaObject));
|
2014-03-23 08:23:30 +00:00
|
|
|
#endif
|
2019-11-01 17:14:55 +00:00
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("Globals"), m_engine->newQMetaObject(&KWin::staticMetaObject));
|
|
|
|
|
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);
|
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);
|
2017-04-02 13:42:18 +00:00
|
|
|
registerTouchScreenEdgeFunction(this, m_engine, kwinRegisterTouchScreenEdge);
|
|
|
|
unregisterTouchScreenEdgeFunction(this, m_engine, kwinUnregisterTouchScreenEdge);
|
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
|
|
|
|
2016-02-03 18:10:00 +00:00
|
|
|
// retarget
|
|
|
|
QScriptValue retargetFunc = m_engine->newFunction(kwinEffectRetarget);
|
|
|
|
retargetFunc.setData(m_engine->newQObject(this));
|
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("retarget"), retargetFunc);
|
|
|
|
|
[scripting] Introduce redirect function
Summary:
Consider current implementation of the Squash effect: if a window was
minimized, an animation will be started; if the window is unminimized
and the animation is still active (that can happen when user clicks on
app's icon really fast), the animation will be stopped and a new one will
be created. Such behavior can lead to rapid jumps in the observed
"animation".
A better approach would be first try to **reverse** the already active
animation, and if that attempt wasn't successful, start a new animation.
This patch introduces a new function to the scripted effects API that
lets JavaScript effects to control direction of animations. The
prototype of the function looks as follows:
redirect(<animation id(s)>, <direction>, [<termination policy>])
the first argument is an animation id or a list of animation ids, the
second argument specifies the new direction of the animation or
animations if a list of ids was passed as the first argument. The
third argument specifies whether the animation(s) should be terminated
when it(they) reaches the source position, currently it's relevant only
for animations that are created with set() function. The termination
policy argument is optional, by default it's Effect.TerminateAtSource.
We can use this function to fix issues with rapid jumps in the Squash
effect. Also, redirect() lets us to write effects for simple animations
in slightly different style: first, we have to start the main animation
(e.g. for the Dialog Parent effect, it would be dimming of main windows)
and then change direction of the animation depending on external events,
e.g. when the Desktop Cube effect is activated.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16449
2018-10-24 19:58:29 +00:00
|
|
|
// redirect
|
|
|
|
QScriptValue redirectFunc = m_engine->newFunction(kwinEffectRedirect);
|
|
|
|
redirectFunc.setData(m_engine->newQObject(this));
|
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("redirect"), redirectFunc);
|
|
|
|
|
2018-10-25 18:02:36 +00:00
|
|
|
// complete
|
|
|
|
QScriptValue completeFunc = m_engine->newFunction(kwinEffectComplete);
|
|
|
|
completeFunc.setData(m_engine->newQObject(this));
|
|
|
|
m_engine->globalObject().setProperty(QStringLiteral("complete"), completeFunc);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-03-30 09:38:38 +00:00
|
|
|
void ScriptedEffect::animationEnded(KWin::EffectWindow *w, Attribute a, uint meta)
|
|
|
|
{
|
|
|
|
AnimationEffect::animationEnded(w, a, meta);
|
|
|
|
emit animationEnded(w, 0);
|
|
|
|
}
|
|
|
|
|
2020-08-11 16:49:17 +00:00
|
|
|
QString ScriptedEffect::pluginId() const
|
|
|
|
{
|
|
|
|
return m_effectName;
|
|
|
|
}
|
|
|
|
|
2018-10-03 00:11:59 +00:00
|
|
|
bool ScriptedEffect::isActiveFullScreenEffect() const
|
|
|
|
{
|
|
|
|
return effects->activeFullScreenEffect() == this;
|
|
|
|
}
|
|
|
|
|
2012-01-29 16:32:56 +00:00
|
|
|
void ScriptedEffect::signalHandlerException(const QScriptValue &value)
|
|
|
|
{
|
|
|
|
if (value.isError()) {
|
2015-07-31 11:24:56 +00:00
|
|
|
qCDebug(KWIN_SCRIPTING) << "KWin Effect script encountered an error at [Line " << m_engine->uncaughtExceptionLineNumber() << "]";
|
|
|
|
qCDebug(KWIN_SCRIPTING) << "Message: " << value.toString();
|
2012-01-29 16:32:56 +00:00
|
|
|
|
|
|
|
QScriptValueIterator iter(value);
|
|
|
|
while (iter.hasNext()) {
|
|
|
|
iter.next();
|
2015-07-31 11:24:56 +00:00
|
|
|
qCDebug(KWIN_SCRIPTING) << " " << iter.name() << ": " << iter.value().toString();
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
quint64 ScriptedEffect::animate(KWin::EffectWindow* w, KWin::AnimationEffect::Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from, uint metaData, int curve, int delay, bool fullScreen, bool keepAlive)
|
2013-02-28 18:52:16 +00:00
|
|
|
{
|
2015-03-30 09:38:38 +00:00
|
|
|
QEasingCurve qec;
|
|
|
|
if (curve < QEasingCurve::Custom)
|
2018-08-07 20:32:53 +00:00
|
|
|
qec.setType(static_cast<QEasingCurve::Type>(curve));
|
|
|
|
else if (curve == GaussianCurve)
|
2015-03-30 09:38:38 +00:00
|
|
|
qec.setCustomType(qecGaussian);
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
return AnimationEffect::animate(w, a, metaData, ms, to, qec, delay, from, fullScreen, keepAlive);
|
2013-02-28 18:52:16 +00:00
|
|
|
}
|
|
|
|
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
quint64 ScriptedEffect::set(KWin::EffectWindow* w, KWin::AnimationEffect::Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from, uint metaData, int curve, int delay, bool fullScreen, bool keepAlive)
|
2013-02-28 18:52:16 +00:00
|
|
|
{
|
2015-03-30 09:38:38 +00:00
|
|
|
QEasingCurve qec;
|
|
|
|
if (curve < QEasingCurve::Custom)
|
2018-08-07 20:32:53 +00:00
|
|
|
qec.setType(static_cast<QEasingCurve::Type>(curve));
|
|
|
|
else if (curve == GaussianCurve)
|
2015-03-30 09:38:38 +00:00
|
|
|
qec.setCustomType(qecGaussian);
|
[effects/dialogparent] Fix flickering of parent windows
Summary:
If a modal window is closed and some alternative effect that animates
the disappearing of windows is enabled(e.g. the Glide effect, or the
Scale effect), the Dialog Parent effect can cause flickering of the
parent window because its animation duration doesn't match duration of
those alternative effects.
Also, if the Fade effect, the Glide effect, and the Scale effect are
disabled, the Dialog Parent will keep the parent window alive for no
good reason.
This change addresses that problem by adding keepAlive property to
`animate` function so scripted effects have more control over lifetime
of animated windows.
If both a modal window and its parent window are closed at the same time
(and there is no effect that animates the disappearing of windows), the
Dialog Parent will stop immediately(because windowDeleted will be
emitted right after windowClosed signal).
If both a modal window and its parent window are closed at the same time
(and there is effect that animates the disappearing of windows), the
Dialog Parent won't reference the latter window. Thus, it won't cause
flickering. I.e. it will "passively" animate parent windows.
BUG: 355036
FIXED-IN: 5.15.0
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D14919
2018-10-10 07:36:45 +00:00
|
|
|
return AnimationEffect::set(w, a, metaData, ms, to, qec, delay, from, fullScreen, keepAlive);
|
2012-01-29 16:32:56 +00:00
|
|
|
}
|
|
|
|
|
2016-02-03 18:10:00 +00:00
|
|
|
bool ScriptedEffect::retarget(quint64 animationId, KWin::FPx2 newTarget, int newRemainingTime)
|
|
|
|
{
|
|
|
|
return AnimationEffect::retarget(animationId, newTarget, newRemainingTime);
|
|
|
|
}
|
|
|
|
|
[scripting] Introduce redirect function
Summary:
Consider current implementation of the Squash effect: if a window was
minimized, an animation will be started; if the window is unminimized
and the animation is still active (that can happen when user clicks on
app's icon really fast), the animation will be stopped and a new one will
be created. Such behavior can lead to rapid jumps in the observed
"animation".
A better approach would be first try to **reverse** the already active
animation, and if that attempt wasn't successful, start a new animation.
This patch introduces a new function to the scripted effects API that
lets JavaScript effects to control direction of animations. The
prototype of the function looks as follows:
redirect(<animation id(s)>, <direction>, [<termination policy>])
the first argument is an animation id or a list of animation ids, the
second argument specifies the new direction of the animation or
animations if a list of ids was passed as the first argument. The
third argument specifies whether the animation(s) should be terminated
when it(they) reaches the source position, currently it's relevant only
for animations that are created with set() function. The termination
policy argument is optional, by default it's Effect.TerminateAtSource.
We can use this function to fix issues with rapid jumps in the Squash
effect. Also, redirect() lets us to write effects for simple animations
in slightly different style: first, we have to start the main animation
(e.g. for the Dialog Parent effect, it would be dimming of main windows)
and then change direction of the animation depending on external events,
e.g. when the Desktop Cube effect is activated.
Reviewers: #kwin, davidedmundson
Reviewed By: #kwin, davidedmundson
Subscribers: davidedmundson, abetts, kwin
Tags: #kwin
Differential Revision: https://phabricator.kde.org/D16449
2018-10-24 19:58:29 +00:00
|
|
|
bool ScriptedEffect::redirect(quint64 animationId, Direction direction, TerminationFlags terminationFlags)
|
|
|
|
{
|
|
|
|
return AnimationEffect::redirect(animationId, direction, terminationFlags);
|
|
|
|
}
|
|
|
|
|
2018-10-25 18:02:36 +00:00
|
|
|
bool ScriptedEffect::complete(quint64 animationId)
|
|
|
|
{
|
|
|
|
return AnimationEffect::complete(animationId);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-27 20:13:53 +00:00
|
|
|
bool ScriptedEffect::grab(EffectWindow *w, DataRole grabRole, bool force)
|
|
|
|
{
|
|
|
|
void *grabber = w->data(grabRole).value<void *>();
|
|
|
|
|
|
|
|
if (grabber == this) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grabber != nullptr && grabber != this && !force) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->setData(grabRole, QVariant::fromValue(static_cast<void *>(this)));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScriptedEffect::ungrab(EffectWindow *w, DataRole grabRole)
|
|
|
|
{
|
|
|
|
void *grabber = w->data(grabRole).value<void *>();
|
|
|
|
|
|
|
|
if (grabber == nullptr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grabber != this) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
w->setData(grabRole, QVariant());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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);
|
2020-09-23 18:39:59 +00:00
|
|
|
connect(a, &QAction::triggered, this, &ScriptedEffect::globalShortcutTriggered);
|
2012-03-25 07:59:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-04-02 13:42:18 +00:00
|
|
|
bool ScriptedEffect::registerTouchScreenCallback(int edge, QScriptValue callback)
|
|
|
|
{
|
|
|
|
if (m_touchScreenEdgeCallbacks.constFind(edge) != m_touchScreenEdgeCallbacks.constEnd()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QAction *action = new QAction(this);
|
|
|
|
connect(action, &QAction::triggered, this,
|
|
|
|
[callback] {
|
|
|
|
QScriptValue invoke(callback);
|
|
|
|
invoke.call();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
ScreenEdges::self()->reserveTouch(KWin::ElectricBorder(edge), action);
|
|
|
|
m_touchScreenEdgeCallbacks.insert(edge, action);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ScriptedEffect::unregisterTouchScreenCallback(int edge)
|
|
|
|
{
|
|
|
|
auto it = m_touchScreenEdgeCallbacks.find(edge);
|
2017-04-07 18:36:36 +00:00
|
|
|
if (it == m_touchScreenEdgeCallbacks.end()) {
|
2017-04-02 13:42:18 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
delete it.value();
|
|
|
|
m_touchScreenEdgeCallbacks.erase(it);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-23 21:52:58 +00:00
|
|
|
QScriptEngine *ScriptedEffect::engine() const
|
|
|
|
{
|
|
|
|
return m_engine;
|
|
|
|
}
|
|
|
|
|
2012-01-29 16:32:56 +00:00
|
|
|
} // namespace
|