File indexing completed on 2024-12-01 13:36:47

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #pragma once
0012 
0013 #include <kwinanimationeffect.h>
0014 
0015 #include <QJSEngine>
0016 #include <QJSValue>
0017 
0018 class KConfigLoader;
0019 class KPluginMetaData;
0020 
0021 namespace KWin
0022 {
0023 
0024 class KWIN_EXPORT ScriptedEffect : public KWin::AnimationEffect
0025 {
0026     Q_OBJECT
0027     Q_ENUMS(DataRole)
0028     Q_ENUMS(Qt::Axis)
0029     Q_ENUMS(Anchor)
0030     Q_ENUMS(MetaType)
0031     Q_ENUMS(EasingCurve)
0032     Q_ENUMS(SessionState)
0033     Q_ENUMS(ElectricBorder)
0034     Q_ENUMS(ShaderTrait)
0035     /**
0036      * The plugin ID of the effect
0037      */
0038     Q_PROPERTY(QString pluginId READ pluginId CONSTANT)
0039     /**
0040      * True if we are the active fullscreen effect
0041      */
0042     Q_PROPERTY(bool isActiveFullScreenEffect READ isActiveFullScreenEffect NOTIFY isActiveFullScreenEffectChanged)
0043 
0044 public:
0045     // copied from kwineffects.h
0046     enum DataRole {
0047         // Grab roles are used to force all other animations to ignore the window.
0048         // The value of the data is set to the Effect's `this` value.
0049         WindowAddedGrabRole = 1,
0050         WindowClosedGrabRole,
0051         WindowMinimizedGrabRole,
0052         WindowUnminimizedGrabRole,
0053         WindowForceBlurRole, ///< For fullscreen effects to enforce blurring of windows,
0054         WindowBlurBehindRole, ///< For single windows to blur behind
0055         WindowForceBackgroundContrastRole, ///< For fullscreen effects to enforce the background contrast,
0056         WindowBackgroundContrastRole, ///< For single windows to enable Background contrast
0057     };
0058     enum EasingCurve {
0059         GaussianCurve = 128
0060     };
0061     // copied from kwinglutils.h
0062     enum class ShaderTrait {
0063         MapTexture = (1 << 0),
0064         UniformColor = (1 << 1),
0065         Modulate = (1 << 2),
0066         AdjustSaturation = (1 << 3),
0067     };
0068 
0069     const QString &scriptFile() const
0070     {
0071         return m_scriptFile;
0072     }
0073     void reconfigure(ReconfigureFlags flags) override;
0074     int requestedEffectChainPosition() const override
0075     {
0076         return m_chainPosition;
0077     }
0078     QString activeConfig() const;
0079     void setActiveConfig(const QString &name);
0080     static ScriptedEffect *create(const QString &effectName, const QString &pathToScript, int chainPosition, const QString &exclusiveCategory);
0081     static ScriptedEffect *create(const KPluginMetaData &effect);
0082     static bool supported();
0083     ~ScriptedEffect() override;
0084     /**
0085      * Whether another effect has grabbed the @p w with the given @p grabRole.
0086      * @param w The window to check
0087      * @param grabRole The grab role to check
0088      * @returns @c true if another window has grabbed the effect, @c false otherwise
0089      */
0090     Q_SCRIPTABLE bool isGrabbed(KWin::EffectWindow *w, DataRole grabRole);
0091 
0092     /**
0093      * Grabs the window with the specified role.
0094      *
0095      * @param w The window.
0096      * @param grabRole The grab role.
0097      * @param force By default, if the window is already grabbed by another effect,
0098      *   then that window won't be grabbed by effect that called this method. If you
0099      *   would like to grab a window even if it's grabbed by another effect, then
0100      *   pass @c true.
0101      * @returns @c true if the window was grabbed successfully, otherwise @c false.
0102      */
0103     Q_SCRIPTABLE bool grab(KWin::EffectWindow *w, DataRole grabRole, bool force = false);
0104 
0105     /**
0106      * Ungrabs the window with the specified role.
0107      *
0108      * @param w The window.
0109      * @param grabRole The grab role.
0110      * @returns @c true if the window was ungrabbed successfully, otherwise @c false.
0111      */
0112     Q_SCRIPTABLE bool ungrab(KWin::EffectWindow *w, DataRole grabRole);
0113 
0114     /**
0115      * Reads the value from the configuration data for the given key.
0116      * @param key The key to search for
0117      * @param defaultValue The value to return if the key is not found
0118      * @returns The config value if present
0119      */
0120     Q_SCRIPTABLE QJSValue readConfig(const QString &key, const QJSValue &defaultValue = QJSValue());
0121 
0122     Q_SCRIPTABLE int displayWidth() const;
0123     Q_SCRIPTABLE int displayHeight() const;
0124     Q_SCRIPTABLE int animationTime(int defaultTime) const;
0125 
0126     Q_SCRIPTABLE void registerShortcut(const QString &objectName, const QString &text,
0127                                        const QString &keySequence, const QJSValue &callback);
0128     Q_SCRIPTABLE bool registerScreenEdge(int edge, const QJSValue &callback);
0129     Q_SCRIPTABLE bool registerRealtimeScreenEdge(int edge, const QJSValue &callback);
0130     Q_SCRIPTABLE bool unregisterScreenEdge(int edge);
0131     Q_SCRIPTABLE bool registerTouchScreenEdge(int edge, const QJSValue &callback);
0132     Q_SCRIPTABLE bool unregisterTouchScreenEdge(int edge);
0133 
0134     Q_SCRIPTABLE quint64 animate(KWin::EffectWindow *window, Attribute attribute, int ms,
0135                                  const QJSValue &to, const QJSValue &from = QJSValue(),
0136                                  uint metaData = 0, int curve = QEasingCurve::Linear, int delay = 0,
0137                                  bool fullScreen = false, bool keepAlive = true, uint shaderId = 0);
0138     Q_SCRIPTABLE QJSValue animate(const QJSValue &object);
0139 
0140     Q_SCRIPTABLE quint64 set(KWin::EffectWindow *window, Attribute attribute, int ms,
0141                              const QJSValue &to, const QJSValue &from = QJSValue(),
0142                              uint metaData = 0, int curve = QEasingCurve::Linear, int delay = 0,
0143                              bool fullScreen = false, bool keepAlive = true, uint shaderId = 0);
0144     Q_SCRIPTABLE QJSValue set(const QJSValue &object);
0145 
0146     Q_SCRIPTABLE bool retarget(quint64 animationId, const QJSValue &newTarget,
0147                                int newRemainingTime = -1);
0148     Q_SCRIPTABLE bool retarget(const QList<quint64> &animationIds, const QJSValue &newTarget,
0149                                int newRemainingTime = -1);
0150     Q_SCRIPTABLE bool freezeInTime(quint64 animationId, qint64 frozenTime);
0151     Q_SCRIPTABLE bool freezeInTime(const QList<quint64> &animationIds, qint64 frozenTime);
0152 
0153     Q_SCRIPTABLE bool redirect(quint64 animationId, Direction direction,
0154                                TerminationFlags terminationFlags = TerminateAtSource);
0155     Q_SCRIPTABLE bool redirect(const QList<quint64> &animationIds, Direction direction,
0156                                TerminationFlags terminationFlags = TerminateAtSource);
0157 
0158     Q_SCRIPTABLE bool complete(quint64 animationId);
0159     Q_SCRIPTABLE bool complete(const QList<quint64> &animationIds);
0160 
0161     Q_SCRIPTABLE bool cancel(quint64 animationId);
0162     Q_SCRIPTABLE bool cancel(const QList<quint64> &animationIds);
0163 
0164     Q_SCRIPTABLE QList<int> touchEdgesForAction(const QString &action) const;
0165 
0166     Q_SCRIPTABLE uint addFragmentShader(ShaderTrait traits, const QString &fragmentShaderFile = {});
0167 
0168     Q_SCRIPTABLE void setUniform(uint shaderId, const QString &name, const QJSValue &value);
0169 
0170     QHash<int, QJSValueList> &screenEdgeCallbacks()
0171     {
0172         return m_screenEdgeCallbacks;
0173     }
0174 
0175     QHash<int, QJSValueList> &realtimeScreenEdgeCallbacks()
0176     {
0177         return m_realtimeScreenEdgeCallbacks;
0178     }
0179 
0180     QString pluginId() const;
0181     bool isActiveFullScreenEffect() const;
0182 
0183 public Q_SLOTS:
0184     bool borderActivated(ElectricBorder border) override;
0185 
0186 Q_SIGNALS:
0187     /**
0188      * Signal emitted whenever the effect's config changed.
0189      */
0190     void configChanged();
0191     void animationEnded(KWin::EffectWindow *w, quint64 animationId);
0192     void isActiveFullScreenEffectChanged();
0193 
0194 protected:
0195     ScriptedEffect();
0196     QJSEngine *engine() const;
0197     bool init(const QString &effectName, const QString &pathToScript);
0198     void animationEnded(KWin::EffectWindow *w, Attribute a, uint meta) override;
0199 
0200 private:
0201     enum class AnimationType {
0202         Animate,
0203         Set
0204     };
0205 
0206     QJSValue animate_helper(const QJSValue &object, AnimationType animationType);
0207 
0208     GLShader *findShader(uint shaderId) const;
0209 
0210     QJSEngine *m_engine;
0211     QString m_effectName;
0212     QString m_scriptFile;
0213     QString m_exclusiveCategory;
0214     QHash<int, QJSValueList> m_screenEdgeCallbacks;
0215     QHash<int, QJSValueList> m_realtimeScreenEdgeCallbacks;
0216     KConfigLoader *m_config;
0217     int m_chainPosition;
0218     QHash<int, QAction *> m_touchScreenEdgeCallbacks;
0219     Effect *m_activeFullScreenEffect = nullptr;
0220     std::map<uint, std::unique_ptr<GLShader>> m_shaders;
0221     uint m_nextShaderId{1u};
0222 };
0223 }