23#include <KConfigGroup> 
   24#include <KGlobalAccel> 
   25#include <KPluginMetaData> 
   26#include <kconfigloader.h> 
   32#include <QStandardPaths> 
   72    settings.
to = 
object.property(QStringLiteral(
"to"));
 
   73    settings.
from = 
object.property(QStringLiteral(
"from"));
 
   75    const QJSValue duration = 
object.property(QStringLiteral(
"duration"));
 
   76    if (duration.isNumber()) {
 
   77        settings.
duration = duration.toUInt();
 
   83    const QJSValue delay = 
object.property(QStringLiteral(
"delay"));
 
   84    if (delay.isNumber()) {
 
   85        settings.
delay = delay.toInt();
 
   91    const QJSValue curve = 
object.property(QStringLiteral(
"curve"));
 
   92    if (curve.isNumber()) {
 
   93        settings.
curve = 
static_cast<QEasingCurve::Type
>(curve.toInt());
 
   96        settings.
curve = QEasingCurve::Linear;
 
   99    const QJSValue 
type = 
object.property(QStringLiteral(
"type"));
 
  100    if (
type.isNumber()) {
 
  107    const QJSValue isFullScreen = 
object.property(QStringLiteral(
"fullScreen"));
 
  108    if (isFullScreen.isBool()) {
 
  115    const QJSValue keepAlive = 
object.property(QStringLiteral(
"keepAlive"));
 
  116    if (keepAlive.isBool()) {
 
  123    const QJSValue frozenTime = 
object.property(QStringLiteral(
"frozenTime"));
 
  124    if (frozenTime.isNumber()) {
 
  131    if (
const auto shader = 
object.property(QStringLiteral(
"fragmentShader")); shader.isNumber()) {
 
  132        settings.
shader = shader.toUInt();
 
 
  138static KWin::FPx2 fpx2FromScriptValue(
const QJSValue &value)
 
  140    if (value.isNull()) {
 
  143    if (value.isNumber()) {
 
  144        return FPx2(value.toNumber());
 
  146    if (value.isObject()) {
 
  147        const QJSValue value1 = value.property(QStringLiteral(
"value1"));
 
  148        const QJSValue value2 = value.property(QStringLiteral(
"value2"));
 
  149        if (!value1.isNumber() || !value2.isNumber()) {
 
  150            qCDebug(KWIN_SCRIPTING) << 
"Cannot cast scripted FPx2 to C++";
 
  153        return FPx2(value1.toNumber(), value2.toNumber());
 
  160    const QString name = effect.
pluginId();
 
  161    const QString 
scriptFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
 
  162                                                      QLatin1String(
"kwin/effects/") + name + QLatin1String(
"/contents/code/main.js"));
 
  164        qCDebug(KWIN_SCRIPTING) << 
"Could not locate effect script" << name;
 
  168    return ScriptedEffect::create(name, 
scriptFile, effect.value(QStringLiteral(
"X-KDE-Ordering"), 0), effect.value(QStringLiteral(
"X-KWin-Exclusive-Category")));
 
 
  174    effect->m_exclusiveCategory = exclusiveCategory;
 
  175    if (!effect->
init(effectName, pathToScript)) {
 
  179    effect->m_chainPosition = chainPosition;
 
 
  191    , m_engine(new QJSEngine(this))
 
  192    , m_scriptFile(QString())
 
  199        if (fullScreenEffect == m_activeFullScreenEffect) {
 
  202        if (m_activeFullScreenEffect == 
this || fullScreenEffect == 
this) {
 
  205        m_activeFullScreenEffect = fullScreenEffect;
 
 
  211bool ScriptedEffect::init(
const QString &effectName, 
const QString &pathToScript)
 
  213    qRegisterMetaType<QJSValueList>();
 
  214    qRegisterMetaType<QList<KWin::EffectWindow *>>();
 
  218        qCDebug(KWIN_SCRIPTING) << 
"Could not open script file: " << pathToScript;
 
  221    m_effectName = effectName;
 
  222    m_scriptFile = pathToScript;
 
  225    const QString kconfigXTFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String(
"kwin/effects/") + m_effectName + QLatin1String(
"/contents/config/main.xml"));
 
  226    if (!kconfigXTFile.isNull()) {
 
  227        KConfigGroup cg = QCoreApplication::instance()->property(
"config").value<KSharedConfigPtr>()->group(QStringLiteral(
"Effect-%1").arg(m_effectName));
 
  228        QFile xmlFile(kconfigXTFile);
 
  229        m_config = 
new KConfigLoader(cg, &xmlFile, 
this);
 
  233    m_engine->installExtensions(QJSEngine::ConsoleExtension);
 
  235    QJSValue globalObject = m_engine->globalObject();
 
  237    QJSValue effectsObject = m_engine->newQObject(
effects);
 
  238    QQmlEngine::setObjectOwnership(
effects, QQmlEngine::CppOwnership);
 
  239    globalObject.setProperty(QStringLiteral(
"effects"), effectsObject);
 
  241    QJSValue selfObject = m_engine->newQObject(
this);
 
  242    QQmlEngine::setObjectOwnership(
this, QQmlEngine::CppOwnership);
 
  243    globalObject.setProperty(QStringLiteral(
"effect"), selfObject);
 
  245    globalObject.setProperty(QStringLiteral(
"Effect"),
 
  246                             m_engine->newQMetaObject(&ScriptedEffect::staticMetaObject));
 
  247    globalObject.setProperty(QStringLiteral(
"KWin"),
 
  248                             m_engine->newQMetaObject(&QtScriptWorkspaceWrapper::staticMetaObject));
 
  249    globalObject.setProperty(QStringLiteral(
"Globals"),
 
  250                             m_engine->newQMetaObject(&KWin::staticMetaObject));
 
  251    globalObject.setProperty(QStringLiteral(
"QEasingCurve"),
 
  252                             m_engine->newQMetaObject(&QEasingCurve::staticMetaObject));
 
  254    static const QStringList globalProperties{
 
  255        QStringLiteral(
"animationTime"),
 
  256        QStringLiteral(
"displayWidth"),
 
  257        QStringLiteral(
"displayHeight"),
 
  259        QStringLiteral(
"registerShortcut"),
 
  260        QStringLiteral(
"registerScreenEdge"),
 
  261        QStringLiteral(
"registerRealtimeScreenEdge"),
 
  262        QStringLiteral(
"registerTouchScreenEdge"),
 
  263        QStringLiteral(
"unregisterScreenEdge"),
 
  264        QStringLiteral(
"unregisterTouchScreenEdge"),
 
  266        QStringLiteral(
"animate"),
 
  267        QStringLiteral(
"set"),
 
  268        QStringLiteral(
"retarget"),
 
  269        QStringLiteral(
"freezeInTime"),
 
  270        QStringLiteral(
"redirect"),
 
  271        QStringLiteral(
"complete"),
 
  272        QStringLiteral(
"cancel"),
 
  273        QStringLiteral(
"addShader"),
 
  274        QStringLiteral(
"setUniform"),
 
  277    for (
const QString &propertyName : globalProperties) {
 
  278        globalObject.setProperty(propertyName, selfObject.property(propertyName));
 
  281    const QJSValue result = m_engine->evaluate(QString::fromUtf8(
scriptFile.readAll()));
 
  283    if (result.isError()) {
 
  284        qCWarning(KWIN_SCRIPTING, 
"%s:%d: error: %s", qPrintable(
scriptFile.fileName()),
 
  285                  result.property(QStringLiteral(
"lineNumber")).toInt(),
 
  286                  qPrintable(result.property(QStringLiteral(
"message")).toString()));
 
 
  312    if (m_exclusiveCategory == QStringLiteral(
"show-desktop") && action == QStringLiteral(
"show-desktop")) {
 
  323        return m_config->property(QStringLiteral(
"TouchBorderActivate") + action).value<QList<int>>();
 
 
  327QJSValue ScriptedEffect::animate_helper(
const QJSValue &
object, AnimationType animationType)
 
  329    QJSValue windowProperty = 
object.property(QStringLiteral(
"window"));
 
  330    if (!windowProperty.isObject()) {
 
  331        m_engine->throwError(QStringLiteral(
"Window property missing in animation options"));
 
  335    EffectWindow *window = qobject_cast<EffectWindow *>(windowProperty.toQObject());
 
  337        m_engine->throwError(QStringLiteral(
"Window property references invalid window"));
 
  343    QJSValue animations = 
object.property(QStringLiteral(
"animations")); 
 
  344    if (!animations.isUndefined()) {
 
  345        if (!animations.isArray()) {
 
  346            m_engine->throwError(QStringLiteral(
"Animations provided but not an array"));
 
  350        const int length = 
static_cast<int>(animations.property(QStringLiteral(
"length")).toInt());
 
  351        for (
int i = 0; i < length; ++i) {
 
  352            QJSValue value = animations.property(QString::number(i));
 
  353            if (value.isObject()) {
 
  355                const uint 
set = s.set | settings.at(0).set;
 
  358                    m_engine->throwError(QStringLiteral(
"Type property missing in animation options"));
 
  362                    m_engine->throwError(QStringLiteral(
"Duration property missing in animation options"));
 
  367                    s.duration = settings.at(0).duration;
 
  370                    s.curve = settings.at(0).curve;
 
  373                    s.delay = settings.at(0).delay;
 
  376                    s.fullScreenEffect = settings.at(0).fullScreenEffect;
 
  379                    s.keepAlive = settings.at(0).keepAlive;
 
  381                if (!s.shader.has_value()) {
 
  382                    s.shader = settings.at(0).shader;
 
  386                typedef QMap<AnimationEffect::MetaType, QString> MetaTypeMap;
 
  395                for (
auto it = metaTypes.constBegin(),
 
  396                          end = metaTypes.constEnd();
 
  398                    QJSValue metaVal = value.property(*it);
 
  399                    if (metaVal.isNumber()) {
 
  404                    auto uniformProperty = value.property(QStringLiteral(
"uniform")).toString();
 
  405                    auto shader = findShader(s.shader.value());
 
  407                        m_engine->throwError(QStringLiteral(
"Shader for given shaderId not found"));
 
  411                        m_engine->throwError(QStringLiteral(
"Failed to make OpenGL context current"));
 
  414                    ShaderBinder binder{shader};
 
  415                    s.metaData = shader->uniformLocation(uniformProperty.toUtf8().constData());
 
  423    if (settings.count() == 1) {
 
  424        const uint 
set = settings.at(0).set;
 
  426            m_engine->throwError(QStringLiteral(
"Type property missing in animation options"));
 
  430            m_engine->throwError(QStringLiteral(
"Duration property missing in animation options"));
 
  434        settings.removeAt(0); 
 
  437    if (settings.isEmpty()) {
 
  438        m_engine->throwError(QStringLiteral(
"No animations provided"));
 
  442    QJSValue array = m_engine->newArray(settings.length());
 
  443    for (
int i = 0; i < settings.count(); i++) {
 
  444        const AnimationSettings &setting = settings[i];
 
  446        if (animationType == AnimationType::Set) {
 
  447            animationId = 
set(window,
 
  455                              setting.fullScreenEffect,
 
  457                              setting.shader ? setting.shader.value() : 0u);
 
  458            if (setting.frozenTime >= 0) {
 
  470                                  setting.fullScreenEffect,
 
  472                                  setting.shader ? setting.shader.value() : 0u);
 
  473            if (setting.frozenTime >= 0) {
 
  477        array.setProperty(i, animationId);
 
  484                                int ms, 
const QJSValue &to, 
const QJSValue &from, uint metaData, 
int curve,
 
  485                                int delay, 
bool fullScreen, 
bool keepAlive, uint shaderId)
 
  488    if (curve < QEasingCurve::Custom) {
 
  489        qec.setType(
static_cast<QEasingCurve::Type
>(curve));
 
  494                                    delay, fpx2FromScriptValue(from), fullScreen, keepAlive, findShader(shaderId));
 
 
  499    return animate_helper(
object, AnimationType::Animate);
 
 
  503                            int ms, 
const QJSValue &to, 
const QJSValue &from, uint metaData, 
int curve,
 
  504                            int delay, 
bool fullScreen, 
bool keepAlive, uint shaderId)
 
  507    if (curve < QEasingCurve::Custom) {
 
  508        qec.setType(
static_cast<QEasingCurve::Type
>(curve));
 
  513                                delay, fpx2FromScriptValue(from), fullScreen, keepAlive, findShader(shaderId));
 
 
  518    return animate_helper(
object, AnimationType::Set);
 
 
  528    return std::all_of(animationIds.begin(), animationIds.end(), [&](quint64 animationId) {
 
  529        return retarget(animationId, newTarget, newRemainingTime);
 
 
  540    return std::all_of(animationIds.begin(), animationIds.end(), [&](quint64 animationId) {
 
  541        return AnimationEffect::freezeInTime(animationId, frozenTime);
 
 
  552    return std::all_of(animationIds.begin(), animationIds.end(), [&](quint64 animationId) {
 
  553        return redirect(animationId, direction, terminationFlags);
 
 
  564    return std::all_of(animationIds.begin(), animationIds.end(), [&](quint64 animationId) {
 
  565        return complete(animationId);
 
 
  577    for (
const quint64 &animationId : animationIds) {
 
  578        ret |= 
cancel(animationId);
 
 
  595    void *grabber = w->
data(grabRole).value<
void *>();
 
  597    if (grabber == 
this) {
 
  601    if (grabber != 
nullptr && grabber != 
this && !force) {
 
  605    w->
setData(grabRole, QVariant::fromValue(
static_cast<void *
>(
this)));
 
 
  612    void *grabber = w->
data(grabRole).value<
void *>();
 
  614    if (grabber == 
nullptr) {
 
  618    if (grabber != 
this) {
 
  622    w->
setData(grabRole, QVariant());
 
 
  637                                      const QString &keySequence, 
const QJSValue &callback)
 
  639    if (!callback.isCallable()) {
 
  640        m_engine->throwError(QStringLiteral(
"Shortcut handler must be callable"));
 
  643    QAction *action = 
new QAction(
this);
 
  644    action->setObjectName(objectName);
 
  645    action->setText(text);
 
  646    const QKeySequence shortcut = QKeySequence(keySequence);
 
  647    KGlobalAccel::self()->setShortcut(action, QList<QKeySequence>() << shortcut);
 
  648    connect(action, &QAction::triggered, 
this, [
this, action, callback]() {
 
  649        QJSValue actionObject = m_engine->newQObject(action);
 
  650        QQmlEngine::setObjectOwnership(action, QQmlEngine::CppOwnership);
 
  651        QJSValue(callback).call(QJSValueList{actionObject});
 
 
  659        for (
const QJSValue &callback : it.value()) {
 
  660            QJSValue(callback).call();
 
 
  671    return m_engine->toScriptValue(m_config->property(key));
 
 
  691    if (!callback.isCallable()) {
 
  692        m_engine->throwError(QStringLiteral(
"Screen edge handler must be callable"));
 
  701        it->append(callback);
 
 
  708    if (!callback.isCallable()) {
 
  709        m_engine->throwError(QStringLiteral(
"Screen edge handler must be callable"));
 
  716        auto *triggerAction = 
new QAction(
this);
 
  717        connect(triggerAction, &QAction::triggered, 
this, [
this, edge]() {
 
  720                for (
const QJSValue &callback : it.value()) {
 
  721                    QJSValue(callback).call({edge});
 
  728                for (
const QJSValue &callback : it.value()) {
 
  729                    QJSValue delta = m_engine->newObject();
 
  730                    delta.setProperty(
"width", deltaProgress.x());
 
  731                    delta.setProperty(
"height", deltaProgress.y());
 
  733                    QJSValue(callback).call({border, QJSValue(delta), m_engine->newQObject(screen)});
 
  738        it->append(callback);
 
 
  757    if (m_touchScreenEdgeCallbacks.constFind(edge) != m_touchScreenEdgeCallbacks.constEnd()) {
 
  760    if (!callback.isCallable()) {
 
  761        m_engine->throwError(QStringLiteral(
"Touch screen edge handler must be callable"));
 
  764    QAction *action = 
new QAction(
this);
 
  765    connect(action, &QAction::triggered, 
this, [callback]() {
 
  766        QJSValue(callback).call();
 
  769    m_touchScreenEdgeCallbacks.insert(edge, action);
 
 
  775    auto it = m_touchScreenEdgeCallbacks.find(edge);
 
  776    if (it == m_touchScreenEdgeCallbacks.end()) {
 
  780    m_touchScreenEdgeCallbacks.erase(it);
 
 
  792        m_engine->throwError(QStringLiteral(
"Failed to make OpenGL context current"));
 
  795    const QString shaderDir{QLatin1String(
"kwin/effects/") + m_effectName + QLatin1String(
"/contents/shaders/")};
 
  796    const QString fragment = fragmentShaderFile.isEmpty() ? QString{} : QStandardPaths::locate(QStandardPaths::GenericDataLocation, shaderDir + fragmentShaderFile);
 
  799    if (!shader->isValid()) {
 
  800        m_engine->throwError(QStringLiteral(
"Shader failed to load"));
 
  805    const uint shaderId{m_nextShaderId};
 
  807    m_shaders[shaderId] = std::move(shader);
 
 
  811GLShader *ScriptedEffect::findShader(uint shaderId)
 const 
  813    if (
auto it = m_shaders.find(shaderId); it != m_shaders.end()) {
 
  814        return it->second.get();
 
  821    auto shader = findShader(shaderId);
 
  823        m_engine->throwError(QStringLiteral(
"Shader for given shaderId not found"));
 
  827        m_engine->throwError(QStringLiteral(
"Failed to make OpenGL context current"));
 
  830    auto setColorUniform = [
this, shader, name](
const QColor &color) {
 
  831        if (!color.isValid()) {
 
  834        if (!shader->setUniform(name.toUtf8().constData(), color)) {
 
  835            m_engine->throwError(QStringLiteral(
"Failed to set uniform ") + name);
 
  839    if (value.isString()) {
 
  840        setColorUniform(value.toString());
 
  841    } 
else if (value.isNumber()) {
 
  842        if (!shader->setUniform(name.toUtf8().constData(), 
float(value.toNumber()))) {
 
  843            m_engine->throwError(QStringLiteral(
"Failed to set uniform ") + name);
 
  845    } 
else if (value.isArray()) {
 
  846        const auto length = value.property(QStringLiteral(
"length")).toInt();
 
  848            if (!shader->setUniform(name.toUtf8().constData(), QVector2D{float(value.property(0).toNumber()), float(value.property(1).toNumber())})) {
 
  849                m_engine->throwError(QStringLiteral(
"Failed to set uniform ") + name);
 
  851        } 
else if (length == 3) {
 
  852            if (!shader->setUniform(name.toUtf8().constData(), QVector3D{float(value.property(0).toNumber()), float(value.property(1).toNumber()), float(value.property(2).toNumber())})) {
 
  853                m_engine->throwError(QStringLiteral(
"Failed to set uniform ") + name);
 
  855        } 
else if (length == 4) {
 
  856            if (!shader->setUniform(name.toUtf8().constData(), QVector4D{float(value.property(0).toNumber()), float(value.property(1).toNumber()), float(value.property(2).toNumber()), float(value.property(3).toNumber())})) {
 
  857                m_engine->throwError(QStringLiteral(
"Failed to set uniform ") + name);
 
  860            m_engine->throwError(QStringLiteral(
"Invalid number of elements in array"));
 
  862    } 
else if (value.isVariant()) {
 
  863        const auto variant = value.toVariant();
 
  864        setColorUniform(variant.value<QColor>());
 
  866        m_engine->throwError(QStringLiteral(
"Invalid value provided for uniform"));
 
 
  872#include "moc_scriptedeffect.cpp" 
quint64 set(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve=QEasingCurve(), int delay=0, const FPx2 &from=FPx2(), bool fullScreen=false, bool keepAlive=true, GLShader *shader=nullptr)
bool redirect(quint64 animationId, Direction direction, TerminationFlags terminationFlags=TerminateAtSource)
bool complete(quint64 animationId)
virtual void animationEnded(EffectWindow *w, Attribute a, uint meta)
static void setMetaData(MetaType type, uint value, uint &meta)
bool retarget(quint64 animationId, FPx2 newTarget, int newRemainingTime=-1)
bool cancel(quint64 animationId)
static int metaData(MetaType type, uint meta)
bool freezeInTime(quint64 animationId, qint64 frozenTime)
quint64 animate(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve=QEasingCurve(), int delay=0, const FPx2 &from=FPx2(), bool fullScreen=false, bool keepAlive=true, GLShader *shader=nullptr)
static qreal qecGaussian(qreal progress)
Base class for all KWin effects.
Representation of a window used by/for Effect classes.
Q_SCRIPTABLE void setData(int role, const QVariant &data)
Q_SCRIPTABLE QVariant data(int role) const
bool animationsSupported() const
bool makeOpenGLContextCurrent()
Makes the OpenGL compositing context current.
void registerRealtimeTouchBorder(ElectricBorder border, QAction *action, TouchBorderCallback progressCallback)
Effect * activeFullScreenEffect() const
void activeFullScreenEffectChanged()
void reserve(ElectricBorder border, QObject *object, const char *callback)
void unreserve(ElectricBorder border, QObject *object)
ElectricBorderAction actionForTouchBorder(ElectricBorder border) const
void reserveTouch(ElectricBorder border, QAction *action, TouchCallback::CallbackFunction callback=nullptr)
Q_SCRIPTABLE int displayHeight() const
Q_SCRIPTABLE bool registerRealtimeScreenEdge(int edge, const QJSValue &callback)
Q_SCRIPTABLE QList< int > touchEdgesForAction(const QString &action) const
~ScriptedEffect() override
QHash< int, QJSValueList > & realtimeScreenEdgeCallbacks()
Q_SCRIPTABLE bool unregisterScreenEdge(int edge)
Q_SCRIPTABLE bool registerScreenEdge(int edge, const QJSValue &callback)
bool init(const QString &effectName, const QString &pathToScript)
bool isActiveFullScreenEffect
Q_SCRIPTABLE uint addFragmentShader(ShaderTrait traits, const QString &fragmentShaderFile={})
Q_SCRIPTABLE bool retarget(quint64 animationId, const QJSValue &newTarget, int newRemainingTime=-1)
Q_SCRIPTABLE bool complete(quint64 animationId)
void animationEnded(KWin::EffectWindow *w, quint64 animationId)
Q_SCRIPTABLE int animationTime(int defaultTime) const
Q_SCRIPTABLE int displayWidth() const
Q_SCRIPTABLE void setUniform(uint shaderId, const QString &name, const QJSValue &value)
void isActiveFullScreenEffectChanged()
QJSEngine * engine() const
Q_SCRIPTABLE bool ungrab(KWin::EffectWindow *w, DataRole grabRole)
Q_SCRIPTABLE bool registerTouchScreenEdge(int edge, const QJSValue &callback)
Q_SCRIPTABLE quint64 animate(KWin::EffectWindow *window, Attribute attribute, int ms, const QJSValue &to, const QJSValue &from=QJSValue(), uint metaData=0, int curve=QEasingCurve::Linear, int delay=0, bool fullScreen=false, bool keepAlive=true, uint shaderId=0)
Q_SCRIPTABLE bool grab(KWin::EffectWindow *w, DataRole grabRole, bool force=false)
void reconfigure(ReconfigureFlags flags) override
Q_SCRIPTABLE bool redirect(quint64 animationId, Direction direction, TerminationFlags terminationFlags=TerminateAtSource)
static ScriptedEffect * create(const QString &effectName, const QString &pathToScript, int chainPosition, const QString &exclusiveCategory)
Q_SCRIPTABLE bool cancel(quint64 animationId)
const QString & scriptFile() const
Q_SCRIPTABLE bool unregisterTouchScreenEdge(int edge)
bool borderActivated(ElectricBorder border) override
Q_SCRIPTABLE bool isGrabbed(KWin::EffectWindow *w, DataRole grabRole)
Q_SCRIPTABLE QJSValue readConfig(const QString &key, const QJSValue &defaultValue=QJSValue())
Q_SCRIPTABLE void registerShortcut(const QString &objectName, const QString &text, const QString &keySequence, const QJSValue &callback)
Q_SCRIPTABLE quint64 set(KWin::EffectWindow *window, Attribute attribute, int ms, const QJSValue &to, const QJSValue &from=QJSValue(), uint metaData=0, int curve=QEasingCurve::Linear, int delay=0, bool fullScreen=false, bool keepAlive=true, uint shaderId=0)
QHash< int, QJSValueList > & screenEdgeCallbacks()
Q_SCRIPTABLE bool freezeInTime(quint64 animationId, qint64 frozenTime)
std::unique_ptr< GLShader > generateShaderFromFile(ShaderTraits traits, const QString &vertexFile=QString(), const QString &fragmentFile=QString())
static ShaderManager * instance()
ScreenEdges * screenEdges() const
virtual void reconfigure(ReconfigureFlags flags)
static double animationTime(const KConfigGroup &cfg, const QString &key, int defaultTime)
@ ElectricActionShowDesktop
AnimationSettings animationSettingsFromObject(const QJSValue &object)
std::optional< uint > shader
AnimationEffect::Attribute type