diff --git a/autotests/test_virtual_desktops.cpp b/autotests/test_virtual_desktops.cpp index 3d217a26a7..9d296c5165 100644 --- a/autotests/test_virtual_desktops.cpp +++ b/autotests/test_virtual_desktops.cpp @@ -36,6 +36,13 @@ void InputRedirection::registerAxisShortcut(Qt::KeyboardModifiers modifiers, Poi void InputRedirection::registerTouchpadSwipeShortcut(SwipeDirection, uint fingerCount, QAction *) { + Q_UNUSED(fingerCount) +} + +void InputRedirection::registerRealtimeTouchpadSwipeShortcut(SwipeDirection, uint fingerCount, QAction *, std::function progressCallback) +{ + Q_UNUSED(progressCallback) + Q_UNUSED(fingerCount) } void InputRedirection::registerTouchscreenSwipeShortcut(SwipeDirection, uint fingerCount, QAction *) diff --git a/src/effects.cpp b/src/effects.cpp index 228e6887be..503d033826 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -145,13 +145,22 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene) } }); connect(ws, &Workspace::currentDesktopChanged, this, [this](int old, AbstractClient *c) { - const int newDesktop = VirtualDesktopManager::self()->current(); - if (old != 0 && newDesktop != old) { - Q_EMIT desktopChanged(old, newDesktop, c ? c->effectWindow() : nullptr); - // TODO: remove in 4.10 - Q_EMIT desktopChanged(old, newDesktop); + const int newDesktop = VirtualDesktopManager::self()->current(); + if (old != 0 && newDesktop != old) { + Q_EMIT desktopChanged(old, newDesktop, c ? c->effectWindow() : nullptr); + // TODO: remove in 4.10 + Q_EMIT desktopChanged(old, newDesktop); + } } - }); + ); + connect(ws, &Workspace::currentDesktopChanging, this, [this](uint currentDesktop, QPointF offset, KWin::AbstractClient* c){ + Q_EMIT desktopChanging(currentDesktop, offset, c ? c->effectWindow() : nullptr); + } + ); + connect(ws, &Workspace::currentDesktopChangingCancelled, this, [this](){ + Q_EMIT desktopChangingCancelled(); + } + ); connect(ws, &Workspace::desktopPresenceChanged, this, [this](AbstractClient *c, int old) { if (!c->effectWindow()) { return; diff --git a/src/libkwineffects/kwineffects.h b/src/libkwineffects/kwineffects.h index 51b2702ec2..198e100fe5 100644 --- a/src/libkwineffects/kwineffects.h +++ b/src/libkwineffects/kwineffects.h @@ -1501,6 +1501,17 @@ Q_SIGNALS: * @since 4.9 */ void desktopChanged(int oldDesktop, int newDesktop, KWin::EffectWindow *with); + + /** + * Signal emmitted while desktop is changing for animation. + * @param currentDesktop The current desktop untiotherwise. + * @param offset The current desktop offset. + * offset.x() = .6 means 60% of the way to the desktop to the right. + * Positive Values means Up and Right. + */ + void desktopChanging(uint currentDesktop, QPointF offset, KWin::EffectWindow *with); + void desktopChangingCancelled(); + /** * @since 4.7 * @deprecated diff --git a/src/virtualdesktops.cpp b/src/virtualdesktops.cpp index fcde5588ea..dc0faf9eac 100644 --- a/src/virtualdesktops.cpp +++ b/src/virtualdesktops.cpp @@ -19,13 +19,15 @@ // Qt #include #include - #include + #include + namespace KWin { static bool s_loadingDesktopSettings = false; +static const double GESTURE_SWITCH_THRESHOLD = .25; static QString generateDesktopId() { @@ -209,6 +211,8 @@ VirtualDesktopManager::VirtualDesktopManager(QObject *parent) : QObject(parent) , m_navigationWrapsAround(false) , m_rootInfo(nullptr) + , m_swipeGestureReleasedY(new QAction(this)) + , m_swipeGestureReleasedX(new QAction(this)) { } @@ -519,7 +523,7 @@ VirtualDesktop *VirtualDesktopManager::currentDesktop() const bool VirtualDesktopManager::setCurrent(uint newDesktop) { - if (newDesktop < 1 || newDesktop > count() || newDesktop == current()) { + if (newDesktop < 1 || newDesktop > count()) { return false; } auto d = desktopForX11Id(newDesktop); @@ -780,10 +784,10 @@ void VirtualDesktopManager::initShortcuts() { initSwitchToShortcuts(); - QAction *nextAction = addAction(QStringLiteral("Switch to Next Desktop"), i18n("Switch to Next Desktop"), &VirtualDesktopManager::slotNext); - input()->registerTouchpadSwipeShortcut(SwipeDirection::Right, 4, nextAction); - QAction *previousAction = addAction(QStringLiteral("Switch to Previous Desktop"), i18n("Switch to Previous Desktop"), &VirtualDesktopManager::slotPrevious); - input()->registerTouchpadSwipeShortcut(SwipeDirection::Left, 4, previousAction); + Q_UNUSED(addAction(QStringLiteral("Switch to Next Desktop"), i18n("Switch to Next Desktop"), &VirtualDesktopManager::slotNext)) + Q_UNUSED(addAction(QStringLiteral("Switch to Previous Desktop"), i18n("Switch to Previous Desktop"), &VirtualDesktopManager::slotPrevious)) + + //shortcuts QAction *slotRightAction = addAction(QStringLiteral("Switch One Desktop to the Right"), i18n("Switch One Desktop to the Right"), &VirtualDesktopManager::slotRight); KGlobalAccel::setGlobalShortcut(slotRightAction, QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Right)); QAction *slotLeftAction = addAction(QStringLiteral("Switch One Desktop to the Left"), i18n("Switch One Desktop to the Left"), &VirtualDesktopManager::slotLeft); @@ -793,14 +797,81 @@ void VirtualDesktopManager::initShortcuts() QAction *slotDownAction = addAction(QStringLiteral("Switch One Desktop Down"), i18n("Switch One Desktop Down"), &VirtualDesktopManager::slotDown); KGlobalAccel::setGlobalShortcut(slotDownAction, QKeySequence(Qt::CTRL | Qt::META | Qt::Key_Down)); + // Gestures + // These connections decide which desktop to end on after gesture ends + connect(m_swipeGestureReleasedX.get(), &QAction::triggered, this, &VirtualDesktopManager::gestureReleasedX); + connect(m_swipeGestureReleasedY, &QAction::triggered, this, &VirtualDesktopManager::gestureReleasedY); + + //These take the live feedback from a gesture + input()->registerRealtimeTouchpadSwipeShortcut(SwipeDirection::Left, 3, m_swipeGestureReleasedX.get(), [this](qreal cb) { + if (grid().width() > 1) { + m_currentDesktopOffset.setX(cb); + Q_EMIT currentChanging(current(), m_currentDesktopOffset); + } + }); + input()->registerRealtimeTouchpadSwipeShortcut(SwipeDirection::Right, 3, m_swipeGestureReleasedX.get(), [this](qreal cb) { + if (grid().width() > 1) { + m_currentDesktopOffset.setX(-cb); + Q_EMIT currentChanging(current(), m_currentDesktopOffset); + } + }); + input()->registerRealtimeTouchpadSwipeShortcut(SwipeDirection::Left, 4, m_swipeGestureReleasedX.get(), [this](qreal cb) { + if (grid().width() > 1) { + m_currentDesktopOffset.setX(cb); + Q_EMIT currentChanging(current(), m_currentDesktopOffset); + } + }); + input()->registerRealtimeTouchpadSwipeShortcut(SwipeDirection::Right, 4, m_swipeGestureReleasedX.get(), [this](qreal cb) { + if (grid().width() > 1) { + m_currentDesktopOffset.setX(-cb); + Q_EMIT currentChanging(current(), m_currentDesktopOffset); + } + }); + input()->registerRealtimeTouchpadSwipeShortcut(SwipeDirection::Down, 3, m_swipeGestureReleasedY.get(), [this](qreal cb) { + if (grid().height() > 1) { + m_currentDesktopOffset.setY(-cb); + Q_EMIT currentChanging(current(), m_currentDesktopOffset); + } + }); + input()->registerRealtimeTouchpadSwipeShortcut(SwipeDirection::Up, 3, m_swipeGestureReleasedY.get(), [this](qreal cb) { + if (grid().height() > 1) { + m_currentDesktopOffset.setY(cb); + Q_EMIT currentChanging(current(), m_currentDesktopOffset); + } + }); + + input()->registerTouchscreenSwipeShortcut(SwipeDirection::Left, 3, slotRightAction); + input()->registerTouchscreenSwipeShortcut(SwipeDirection::Right, 3, slotLeftAction); + // axis events input()->registerAxisShortcut(Qt::ControlModifier | Qt::AltModifier, PointerAxisDown, findChild(QStringLiteral("Switch to Next Desktop"))); input()->registerAxisShortcut(Qt::ControlModifier | Qt::AltModifier, PointerAxisUp, findChild(QStringLiteral("Switch to Previous Desktop"))); +} - input()->registerTouchscreenSwipeShortcut(SwipeDirection::Left, 3, nextAction); - input()->registerTouchscreenSwipeShortcut(SwipeDirection::Right, 3, previousAction); +void VirtualDesktopManager::gestureReleasedY() +{ + if (m_currentDesktopOffset.y() <= -GESTURE_SWITCH_THRESHOLD) { + slotUp(); + } else if (m_currentDesktopOffset.y() >= GESTURE_SWITCH_THRESHOLD) { + slotDown(); + } else { + Q_EMIT currentChangingCancelled(); + } + m_currentDesktopOffset = QPointF(0, 0); +} + +void VirtualDesktopManager::gestureReleasedX() +{ + if (m_currentDesktopOffset.x() <= -GESTURE_SWITCH_THRESHOLD) { + slotLeft(); + } else if (m_currentDesktopOffset.x() >= GESTURE_SWITCH_THRESHOLD) { + slotRight(); + } else { + Q_EMIT currentChangingCancelled(); + } + m_currentDesktopOffset = QPointF(0, 0); } void VirtualDesktopManager::initSwitchToShortcuts() diff --git a/src/virtualdesktops.h b/src/virtualdesktops.h index e8ed8a0537..760f26325d 100644 --- a/src/virtualdesktops.h +++ b/src/virtualdesktops.h @@ -16,6 +16,7 @@ #include #include #include +#include // KDE includes #include @@ -24,6 +25,7 @@ class KLocalizedString; class NETRootInfo; class QAction; +class Options; namespace KWaylandServer { @@ -395,6 +397,17 @@ Q_SIGNALS: * @param newDesktop The virtual desktop changed to */ void currentChanged(uint previousDesktop, uint newDesktop); + + /** + * Signal emmitted for realtime desktop switching animations. + * @param currentDesktop The current virtual desktop + * @param offset The current total change in desktop coordinate + * Offset x and y are negative if switching Left and Down. + * Example: x = 0.6 means 60% of the way to the desktop to the right. + */ + void currentChanging(uint currentDesktop, QPointF offset); + void currentChangingCancelled(); + /** * Signal emitted whenever the desktop layout changes. * @param columns The new number of columns in the layout @@ -438,6 +451,12 @@ private Q_SLOTS: */ void slotDown(); + /* For gestured desktopSwitching + * Called when gesture ended, the thing that actually switches the desktop. + */ + void gestureReleasedY(); + void gestureReleasedX(); + private: /** * Generate a desktop layout from EWMH _NET_DESKTOP_LAYOUT property parameters. @@ -482,6 +501,10 @@ private: KWaylandServer::PlasmaVirtualDesktopManagementInterface *m_virtualDesktopManagement = nullptr; KSharedConfig::Ptr m_config; + QScopedPointer m_swipeGestureReleasedY; + QScopedPointer m_swipeGestureReleasedX; + QPointF m_currentDesktopOffset = QPointF(0, 0); + KWIN_SINGLETON_VARIABLE(VirtualDesktopManager, s_manager) }; diff --git a/src/workspace.cpp b/src/workspace.cpp index b726d648d3..a5c2c07280 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -227,6 +227,8 @@ void Workspace::init() connect(vds, &VirtualDesktopManager::desktopCreated, this, &Workspace::slotDesktopAdded); connect(vds, &VirtualDesktopManager::desktopRemoved, this, &Workspace::slotDesktopRemoved); connect(vds, &VirtualDesktopManager::currentChanged, this, &Workspace::slotCurrentDesktopChanged); + connect(vds, &VirtualDesktopManager::currentChanging, this, &Workspace::slotCurrentDesktopChanging); + connect(vds, &VirtualDesktopManager::currentChangingCancelled, this, &Workspace::slotCurrentDesktopChangingCancelled); vds->setNavigationWrappingAround(options->isRollOverDesktops()); connect(options, &Options::rollOverDesktopsChanged, vds, &VirtualDesktopManager::setNavigationWrappingAround); vds->setConfig(config); @@ -1024,6 +1026,17 @@ void Workspace::slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop) Q_EMIT currentDesktopChanged(oldDesktop, movingClient); } +void Workspace::slotCurrentDesktopChanging(uint currentDesktop, QPointF offset) +{ + closeActivePopup(); + Q_EMIT currentDesktopChanging(currentDesktop, offset, movingClient); +} + +void Workspace::slotCurrentDesktopChangingCancelled() +{ + Q_EMIT currentDesktopChangingCancelled(); +} + void Workspace::updateClientVisibilityOnDesktopChange(VirtualDesktop *newDesktop) { for (auto it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) { diff --git a/src/workspace.h b/src/workspace.h index 1cd5dc031e..3a6d987a39 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -510,6 +510,8 @@ private Q_SLOTS: void updateCurrentActivity(const QString &new_activity); // virtual desktop handling void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop); + void slotCurrentDesktopChanging(uint currentDesktop, QPointF delta); + void slotCurrentDesktopChangingCancelled(); void slotDesktopAdded(VirtualDesktop *desktop); void slotDesktopRemoved(VirtualDesktop *desktop); void slotOutputEnabled(AbstractOutput *output); @@ -527,6 +529,8 @@ Q_SIGNALS: void desktopPresenceChanged(KWin::AbstractClient *, int); void currentActivityChanged(); void currentDesktopChanged(int, KWin::AbstractClient *); + void currentDesktopChanging(uint currentDesktop, QPointF delta, KWin::AbstractClient*);//for realtime animations + void currentDesktopChangingCancelled(); void clientAdded(KWin::AbstractClient *); void clientRemoved(KWin::AbstractClient *); void clientActivated(KWin::AbstractClient *);