From 0042d2d8c141e914c4a2bd7086e669b11771a78a Mon Sep 17 00:00:00 2001 From: Janet Blackquill Date: Mon, 31 May 2021 15:12:59 -0400 Subject: [PATCH] effects/desktopgrid: port to realtime gestures This ports the Desktop Grid effect to realtime gestures, both to have the end-user result, and to demonstrate how effects can have realtime gestures. --- src/effects/desktopgrid/desktopgrid.cpp | 201 +++++++++++++++--------- src/effects/desktopgrid/desktopgrid.h | 13 +- 2 files changed, 136 insertions(+), 78 deletions(-) diff --git a/src/effects/desktopgrid/desktopgrid.cpp b/src/effects/desktopgrid/desktopgrid.cpp index d66abbc1bb..2456951e15 100644 --- a/src/effects/desktopgrid/desktopgrid.cpp +++ b/src/effects/desktopgrid/desktopgrid.cpp @@ -5,6 +5,7 @@ SPDX-FileCopyrightText: 2007 Lubos Lunak SPDX-FileCopyrightText: 2008 Lucas Murray SPDX-FileCopyrightText: 2009 Martin Gräßlin + SPDX-FileCopyrightText: 2021 Carson Black SPDX-License-Identifier: GPL-2.0-or-later */ @@ -58,19 +59,60 @@ DesktopGridEffect::DesktopGridEffect() , scaledSize() , scaledOffset() , m_proxy(nullptr) - , m_activateAction(new QAction(this)) + , m_gestureAction(new QAction(this)) + , m_shortcutAction(new QAction(this)) { initConfig(); - // Load shortcuts - QAction* a = m_activateAction; - a->setObjectName(QStringLiteral("ShowDesktopGrid")); - a->setText(i18n("Show Desktop Grid")); - KGlobalAccel::self()->setDefaultShortcut(a, QList() << Qt::CTRL + Qt::Key_F8); - KGlobalAccel::self()->setShortcut(a, QList() << Qt::CTRL + Qt::Key_F8); - shortcut = KGlobalAccel::self()->shortcut(a); - effects->registerGlobalShortcut(Qt::CTRL + Qt::Key_F8, a); - effects->registerTouchpadSwipeShortcut(SwipeDirection::Up, a); - connect(a, &QAction::triggered, this, &DesktopGridEffect::toggle); + + // First we set up the gestures... + QAction* a = m_gestureAction; + + connect(a, &QAction::triggered, this, [this]() { + if ((qreal(timeline.currentTime()) / qreal(timeline.duration())) > 0.5) { + activated = true; + timeline.setDirection(QTimeLine::Forward); + timelineRunning = true; + } else { + activated = false; + timeline.setDirection(QTimeLine::Backward); + timelineRunning = true; + } + }); + effects->registerRealtimeTouchpadSwipeShortcut(SwipeDirection::Up, a, [this](qreal cb) { + if (activated) return; + + if (timeline.currentValue() == 0) { + activated = true; + setup(); + activated = false; + } + + timeline.setDirection(QTimeLine::Forward); + timeline.setCurrentTime(timeline.duration() * cb); + effects->addRepaintFull(); + }); + connect(&timeline, &QTimeLine::frameChanged, this, []() { + effects->addRepaintFull(); + }); + connect(&timeline, &QTimeLine::finished, this, [this]() { + timelineRunning = false; + if (timeline.currentTime() == 0) { + finish(); + } + }); + + // Now we set up the shortcut + QAction* s = m_shortcutAction; + s->setObjectName(QStringLiteral("ShowDesktopGrid")); + s->setText(i18n("Show Desktop Grid")); + + KGlobalAccel::self()->setDefaultShortcut(s, QList() << Qt::CTRL + Qt::Key_F8); + KGlobalAccel::self()->setShortcut(s, QList() << Qt::CTRL + Qt::Key_F8); + shortcut = KGlobalAccel::self()->shortcut(s); + effects->registerGlobalShortcut(Qt::CTRL + Qt::Key_F8, s); + + connect(s, &QAction::triggered, this, &DesktopGridEffect::toggle); + connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, &DesktopGridEffect::globalShortcutChanged); connect(effects, &EffectsHandler::windowAdded, this, &DesktopGridEffect::slotWindowAdded); connect(effects, &EffectsHandler::windowClosed, this, &DesktopGridEffect::slotWindowClosed); @@ -80,7 +122,7 @@ DesktopGridEffect::DesktopGridEffect() connect(effects, &EffectsHandler::numberScreensChanged, this, &DesktopGridEffect::setup); connect(effects, &EffectsHandler::screenAboutToLock, this, [this]() { - setActive(false); + deactivate(); windowMoveElevateTimer->stop(); if (keyboardGrab) { effects->ungrabKeyboard(); @@ -130,14 +172,14 @@ void DesktopGridEffect::reconfigure(ReconfigureFlags) // deactivate and activate all touch border const QVector relevantBorders{ElectricLeft, ElectricTop, ElectricRight, ElectricBottom}; for (auto e : relevantBorders) { - effects->unregisterTouchBorder(e, m_activateAction); + effects->unregisterTouchBorder(e, m_shortcutAction); } const auto touchBorders = DesktopGridConfig::touchBorderActivate(); for (int i : touchBorders) { if (!relevantBorders.contains(ElectricBorder(i))) { continue; } - effects->registerTouchBorder(ElectricBorder(i), m_activateAction); + effects->registerTouchBorder(ElectricBorder(i), m_shortcutAction); } } @@ -154,29 +196,37 @@ void DesktopGridEffect::prePaintScreen(ScreenPrePaintData& data, std::chrono::mi time = 1; } lastPresentTime = presentTime; + if (timelineRunning) { + timeline.setCurrentTime(timeline.currentTime() + (timeline.direction() == QTimeLine::Forward ? time : -time)); + + if ((timeline.currentTime() <= 0 && timeline.direction() == QTimeLine::Backward)) { + timelineRunning = false; + // defer until the event loop to finish + QTimer::singleShot(0, [this]() { + finish(); + }); + } + } + for (int i = 0; i < effects->numberOfDesktops(); i++) { + auto item = hoverTimeline[i]; + + if (i == highlightedDesktop-1) { // if this is the highlighted desktop, we want to progress the animation from "not highlighted" to "highlight" + item->setCurrentTime(item->currentTime() + time); + } else { // otherwise we progress from "highlighted" to "not highlighted" + item->setCurrentTime(item->currentTime() - time); + } + } if (timeline.currentValue() != 0 || activated || (isUsingPresentWindows() && isMotionManagerMovingWindows())) { - if (activated) - timeline.setCurrentTime(timeline.currentTime() + time); - else - timeline.setCurrentTime(timeline.currentTime() - time); - for (int i = 0; i < effects->numberOfDesktops(); i++) { - if (i == highlightedDesktop - 1) - hoverTimeline[i]->setCurrentTime(hoverTimeline[i]->currentTime() + time); - else - hoverTimeline[i]->setCurrentTime(hoverTimeline[i]->currentTime() - time); - } if (isUsingPresentWindows()) { QList::iterator i; for (i = m_managers.begin(); i != m_managers.end(); ++i) - (*i).calculate(time); + (*i).calculate(timeline.currentTime()); } // PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once, // so with normal screen painting second screen paint would erase parts of the first paint if (timeline.currentValue() != 0 || (isUsingPresentWindows() && isMotionManagerMovingWindows())) data.mask |= PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST; - if (!activated && timeline.currentValue() == 0 && !(isUsingPresentWindows() && isMotionManagerMovingWindows())) - finish(); } const EffectWindowList windows = effects->stackingOrder(); @@ -617,7 +667,7 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e) if (desk > effects->numberOfDesktops()) return; // don't quit when missing desktop setCurrentDesktop(desk); - setActive(false); + deactivate(); } if (windowMove) { if (wasWindowMove && isUsingPresentWindows()) { @@ -644,6 +694,28 @@ void DesktopGridEffect::windowInputMouseEvent(QEvent* e) } } +void DesktopGridEffect::activate() +{ + activated = true; + setup(); + timeline.setDirection(QTimeLine::Forward); + timelineRunning = true; + // timeline.resume(); +} + +void DesktopGridEffect::deactivate() +{ + activated = false; + timeline.setDirection(QTimeLine::Backward); + timelineRunning = true; + // timeline.resume(); +} + +void DesktopGridEffect::toggle() +{ + if (activated) deactivate(); else activate(); +} + void DesktopGridEffect::grabbedKeyboardEvent(QKeyEvent* e) { if (timeline.currentValue() != 1) // Block user input during animations @@ -654,7 +726,7 @@ void DesktopGridEffect::grabbedKeyboardEvent(QKeyEvent* e) // check for global shortcuts // HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155) if (shortcut.contains(e->key() + e->modifiers())) { - toggle(); + deactivate(); return; } @@ -668,7 +740,7 @@ void DesktopGridEffect::grabbedKeyboardEvent(QKeyEvent* e) if (desktop <= effects->numberOfDesktops()) { setHighlightedDesktop(desktop); setCurrentDesktop(desktop); - setActive(false); + deactivate(); } return; } @@ -687,13 +759,13 @@ void DesktopGridEffect::grabbedKeyboardEvent(QKeyEvent* e) setHighlightedDesktop(desktopDown(highlightedDesktop, !e->isAutoRepeat())); break; case Qt::Key_Escape: - setActive(false); + deactivate(); return; case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_Space: setCurrentDesktop(highlightedDesktop); - setActive(false); + deactivate(); return; case Qt::Key_Plus: slotAddDesktop(); @@ -713,7 +785,7 @@ bool DesktopGridEffect::borderActivated(ElectricBorder border) return false; if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) return true; - toggle(); + // toggle(); return true; } @@ -989,48 +1061,6 @@ int DesktopGridEffect::desktopDown(int desktop, bool wrap) const //----------------------------------------------------------------------------- // Activation -void DesktopGridEffect::toggle() -{ - setActive(!activated); -} - -void DesktopGridEffect::setActive(bool active) -{ - if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) - return; // Only one fullscreen effect at a time thanks - if (active && isMotionManagerMovingWindows()) - return; // Still moving windows from last usage - don't activate - if (activated == active) - return; // Already in that state - - activated = active; - if (activated) { - effects->setShowingDesktop(false); - if (timeline.currentValue() == 0) - setup(); - } else { - if (isUsingPresentWindows()) { - QList::iterator it; - for (it = m_managers.begin(); it != m_managers.end(); ++it) { - Q_FOREACH (EffectWindow * w, (*it).managedWindows()) { - (*it).moveWindow(w, w->frameGeometry()); - } - } - } - QTimer::singleShot(zoomDuration + 1, this, - [this] { - if (activated) - return; - for (EffectQuickScene *view : qAsConst(m_desktopButtons)) { - view->hide(); - } - } - ); - setHighlightedDesktop(effects->currentDesktop()); // Ensure selected desktop is highlighted - } - effects->addRepaintFull(); -} - void DesktopGridEffect::setup() { if (!isActive()) @@ -1193,6 +1223,25 @@ void DesktopGridEffect::finish() desktopNames.clear(); } + if (isUsingPresentWindows()) { + QList::iterator it; + for (it = m_managers.begin(); it != m_managers.end(); ++it) { + Q_FOREACH (EffectWindow * w, (*it).managedWindows()) { + (*it).moveWindow(w, w->frameGeometry()); + } + } + } + QTimer::singleShot(zoomDuration + 1, this, + [this] { + if (activated) + return; + for (EffectQuickScene *view : qAsConst(m_desktopButtons)) { + view->hide(); + } + } + ); + setHighlightedDesktop(effects->currentDesktop()); // Ensure selected desktop is highlighted + windowMoveElevateTimer->stop(); if (keyboardGrab) @@ -1208,6 +1257,8 @@ void DesktopGridEffect::finish() } m_proxy = nullptr; } + + effects->addRepaintFull(); } void DesktopGridEffect::globalShortcutChanged(QAction *action, const QKeySequence& seq) diff --git a/src/effects/desktopgrid/desktopgrid.h b/src/effects/desktopgrid/desktopgrid.h index 94301ec79f..dba1fb6e57 100644 --- a/src/effects/desktopgrid/desktopgrid.h +++ b/src/effects/desktopgrid/desktopgrid.h @@ -83,7 +83,6 @@ public: return clickBehavior == SwitchDesktopAndActivateWindow; } private Q_SLOTS: - void toggle(); // slots for global shortcut changed // needed to toggle the effect void globalShortcutChanged(QAction *action, const QKeySequence& seq); @@ -106,7 +105,9 @@ private: int desktopToLeft(int desktop, bool wrap = true) const; int desktopUp(int desktop, bool wrap = true) const; int desktopDown(int desktop, bool wrap = true) const; - void setActive(bool active); + void deactivate(); + void activate(); + void toggle(); void setup(); void setupGrid(); void finish(); @@ -127,7 +128,12 @@ private: int clickBehavior; bool activated; + QTimeLine timeline; + // used to indicate whether or not the prepaint thingy should drive the + // animation. + bool timelineRunning = false; + int paintingDesktop; int highlightedDesktop; int sourceDesktop; @@ -164,7 +170,8 @@ private: QVector m_desktopButtons; - QAction *m_activateAction; + QAction *m_gestureAction; + QAction *m_shortcutAction; };