File indexing completed on 2024-05-12 05:32:10

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