// SPDX-FileCopyrightText: 2021 Vlad Zahorodnii // SPDX-FileCopyrightText: 2023 Devin Lin // SPDX-FileCopyrightText: 2024 Luis Büchi // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include #include #include #include #include #include #include "effecttouchborder.h" #include "taskfiltermodel.h" #include "taskmodel.h" namespace KWin { class MobileTaskSwitcherState : public QObject { Q_OBJECT Q_PROPERTY(bool gestureEnabled READ gestureEnabled WRITE setGestureEnabled NOTIFY gestureEnabledChanged) Q_PROPERTY(bool wasInActiveTask READ wasInActiveTask WRITE setWasInActiveTask NOTIFY wasInActiveTaskChanged) Q_PROPERTY(int currentTaskIndex READ currentTaskIndex WRITE setCurrentTaskIndex NOTIFY currentTaskIndexChanged) Q_PROPERTY(int initialTaskIndex READ initialTaskIndex WRITE setInitialTaskIndex NOTIFY initialTaskIndexChanged) Q_PROPERTY(qreal touchXPosition READ touchXPosition NOTIFY touchPositionChanged) Q_PROPERTY(qreal touchYPosition READ touchYPosition NOTIFY touchPositionChanged) Q_PROPERTY(qreal xVelocity READ xVelocity NOTIFY velocityChanged) Q_PROPERTY(qreal yVelocity READ yVelocity NOTIFY velocityChanged) Q_PROPERTY(qreal totalSquaredVelocity READ totalSquaredVelocity NOTIFY velocityChanged) Q_PROPERTY(qreal flickVelocityThreshold READ flickVelocityThreshold NOTIFY flickVelocityThresholdChanged) Q_PROPERTY(qreal xPosition READ xPosition WRITE setXPosition NOTIFY xPositionChanged) Q_PROPERTY(qreal yPosition READ yPosition WRITE setYPosition NOTIFY yPositionChanged) Q_PROPERTY(bool gestureInProgress READ gestureInProgress NOTIFY gestureInProgressChanged) Q_PROPERTY(KWin::MobileTaskSwitcherState::Status status READ status WRITE setStatus NOTIFY statusChanged) Q_PROPERTY(qint64 elapsedTimeSinceStart READ getElapsedTimeSinceStart) Q_PROPERTY(qint64 doubleClickInterval READ getDoubleClickInterval) // is there a better way than to forward this? Q_PROPERTY(KWin::TaskModel *taskModel READ taskModel CONSTANT) QML_ELEMENT public: enum class Status { // TODO! I could (should?) re-add the activating and deactivating states again to match EffectTogglableState. could help with/tie into // currentlyBeingOpened and currentlyBeingClosed Inactive, // Task switcher is not fully showing Active, // Task switcher is active and gesture not in progress anymore Stopped // When is this the case? }; Q_ENUM(Status) MobileTaskSwitcherState(QObject *parent = nullptr); Q_INVOKABLE void init(KWin::QuickSceneEffect *parent); bool gestureEnabled() const; void setGestureEnabled(bool gestureEnabled); bool gestureInProgress() const; void setGestureInProgress(bool gestureInProgress); bool wasInActiveTask() const; void setWasInActiveTask(bool wasInActiveTask); Q_INVOKABLE void updateWasInActiveTask(KWin::Window *window); qreal touchXPosition() const; qreal touchYPosition() const; qreal xVelocity() const; qreal yVelocity() const; qreal totalSquaredVelocity() const; qreal flickVelocityThreshold() const; void setFlickVelocityThreshold(qreal flickVelocityThreshold); qreal xPosition() const; void setXPosition(qreal positionX); qreal yPosition() const; void setYPosition(qreal positionY); Status status() const; void setStatus(Status status); int currentTaskIndex() const; void setCurrentTaskIndex(int newTaskIndex); int initialTaskIndex() const; void setInitialTaskIndex(int newTaskIndex); void restartDoubleClickTimer(); int animationDuration() const; void setDBusState(bool active); TaskModel *taskModel() const; public Q_SLOTS: void processTouchPositionChanged(qreal primaryPosition, qreal orthogonalPosition); void activate(); void realDeactivate(); void deactivate(bool deactivateInstantly); void quickDeactivate(); void toggle(); Q_SIGNALS: void gestureEnabledChanged(); void activated(); void deactivated(); void gestureInProgressChanged(); void statusChanged(); void wasInActiveTaskChanged(); void currentTaskIndexChanged(); void initialTaskIndexChanged(); void touchPositionChanged(); void velocityChanged(); void flickVelocityThresholdChanged(); void xPositionChanged(); void yPositionChanged(); private Q_SLOTS: void refreshBorders(); private: void invokeEffect(); bool m_gestureEnabled{false}; EffectTouchBorderState *m_effectState{nullptr}; EffectTouchBorder *m_border{nullptr}; TaskModel *m_taskModel{nullptr}; KWin::QuickSceneEffect *m_effect{nullptr}; Status m_status = Status::Inactive; bool m_gestureInProgress = false; int m_currentTaskIndex; int m_initialTaskIndex; void clearVelocityFilter(); void calculateFilteredVelocity(qreal primaryPosition, qreal orthogonalPosition); qint64 getElapsedTimeSinceStart(); // velocities in (logical) pixels/msec QElapsedTimer m_frameTimer; qreal m_flickVelocityThreshold = 0.5 * 0.5; // squared because total velocity is kept as a square qreal m_filterTimeConstant = 0.03; // time constant of velocity filter qreal m_touchXPosition; qreal m_touchYPosition; qreal m_xVelocity = 0; qreal m_yVelocity = 0; // Using the square of velocity for the total (2-axis) because we just need it // for one threshold comparison and we skip having to calculate the square root qreal m_totalSquaredVelocity; // Positions of the task switcher effect itself qreal m_xPosition = 0; qreal m_yPosition = 0; bool m_wasInActiveTask; QElapsedTimer *m_doubleClickTimer; qint64 getDoubleClickInterval() const { return qApp->doubleClickInterval(); } QTimer *m_shutdownTimer; }; } // namespace KWin