File indexing completed on 2024-11-10 04:57:04

0001 /*
0002     SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "overvieweffect.h"
0008 #include "effect/effecthandler.h"
0009 #include "overviewconfig.h"
0010 
0011 #include <KGlobalAccel>
0012 #include <KLocalizedString>
0013 
0014 #include <QAction>
0015 #include <QDebug>
0016 #include <QQuickItem>
0017 #include <QTimer>
0018 
0019 namespace KWin
0020 {
0021 
0022 OverviewEffect::OverviewEffect()
0023     // manages the transition between inactive -> overview
0024     : m_overviewState(new EffectTogglableState(this))
0025     // manages the transition between overview -> grid
0026     , m_transitionState(new EffectTogglableState(this))
0027     // manages the transition betwee inactive -> overview
0028     , m_gridState(new EffectTogglableState(this))
0029     , m_border(new EffectTogglableTouchBorder(m_overviewState))
0030     , m_shutdownTimer(new QTimer(this))
0031 {
0032     auto gesture = new EffectTogglableGesture(m_overviewState);
0033     gesture->addTouchpadSwipeGesture(SwipeDirection::Up, 4);
0034     gesture->addTouchscreenSwipeGesture(SwipeDirection::Up, 3);
0035 
0036     auto transitionGesture = new EffectTogglableGesture(m_transitionState);
0037     transitionGesture->addTouchpadSwipeGesture(SwipeDirection::Up, 4);
0038     transitionGesture->addTouchscreenSwipeGesture(SwipeDirection::Up, 3);
0039     m_transitionState->stop();
0040 
0041     auto gridGesture = new EffectTogglableGesture(m_gridState);
0042     gridGesture->addTouchpadSwipeGesture(SwipeDirection::Down, 4);
0043     gridGesture->addTouchscreenSwipeGesture(SwipeDirection::Down, 3);
0044 
0045     connect(m_overviewState, &EffectTogglableState::inProgressChanged, this, &OverviewEffect::overviewGestureInProgressChanged);
0046     connect(m_overviewState, &EffectTogglableState::partialActivationFactorChanged, this, &OverviewEffect::overviewPartialActivationFactorChanged);
0047 
0048     connect(m_overviewState, &EffectTogglableState::statusChanged, this, [this](EffectTogglableState::Status status) {
0049         if (status == EffectTogglableState::Status::Activating || status == EffectTogglableState::Status::Active) {
0050             m_searchText = QString();
0051             setRunning(true);
0052             m_gridState->stop();
0053         }
0054         if (status == EffectTogglableState::Status::Active) {
0055             m_transitionState->deactivate();
0056         }
0057         if (status == EffectTogglableState::Status::Inactive || status == EffectTogglableState::Status::Deactivating) {
0058             m_transitionState->stop();
0059         }
0060         if (status == EffectTogglableState::Status::Inactive) {
0061             m_gridState->deactivate();
0062             deactivate();
0063         }
0064     });
0065 
0066     connect(m_transitionState, &EffectTogglableState::statusChanged, this, [this](EffectTogglableState::Status status) {
0067         if (status == EffectTogglableState::Status::Activating || status == EffectTogglableState::Status::Active) {
0068             m_overviewState->stop();
0069         }
0070         if (status == EffectTogglableState::Status::Inactive) {
0071             m_overviewState->activate();
0072         }
0073         if (status == EffectTogglableState::Status::Active) {
0074             m_gridState->activate();
0075         }
0076         if (status == EffectTogglableState::Status::Inactive || status == EffectTogglableState::Status::Deactivating) {
0077             m_gridState->stop();
0078         }
0079     });
0080 
0081     connect(m_gridState, &EffectTogglableState::statusChanged, this, [this](EffectTogglableState::Status status) {
0082         if (status == EffectTogglableState::Status::Activating || status == EffectTogglableState::Status::Active) {
0083             m_searchText = QString();
0084             setRunning(true);
0085             m_overviewState->stop();
0086         }
0087         if (status == EffectTogglableState::Status::Inactive) {
0088             m_overviewState->deactivate();
0089             deactivate();
0090         }
0091         if (status == EffectTogglableState::Status::Active) {
0092             m_transitionState->activate();
0093         }
0094         if (status == EffectTogglableState::Status::Inactive || status == EffectTogglableState::Status::Deactivating) {
0095             m_transitionState->stop();
0096         }
0097     });
0098 
0099     connect(m_transitionState, &EffectTogglableState::inProgressChanged, this, &OverviewEffect::transitionGestureInProgressChanged);
0100     connect(m_transitionState, &EffectTogglableState::partialActivationFactorChanged, this, &OverviewEffect::transitionPartialActivationFactorChanged);
0101 
0102     connect(m_gridState, &EffectTogglableState::inProgressChanged, this, &OverviewEffect::gridGestureInProgressChanged);
0103     connect(m_gridState, &EffectTogglableState::partialActivationFactorChanged, this, &OverviewEffect::gridPartialActivationFactorChanged);
0104 
0105     connect(effects, &EffectsHandler::desktopChanging, this, [this](VirtualDesktop *old, QPointF desktopOffset, EffectWindow *with) {
0106         m_desktopOffset = desktopOffset;
0107         Q_EMIT desktopOffsetChanged();
0108     });
0109     connect(effects, &EffectsHandler::desktopChanged, this, [this](VirtualDesktop *old, VirtualDesktop *current, EffectWindow *with) {
0110         m_desktopOffset = QPointF(0, 0);
0111         Q_EMIT desktopOffsetChanged();
0112     });
0113     connect(effects, &EffectsHandler::desktopChangingCancelled, this, [this]() {
0114         m_desktopOffset = QPointF(0, 0);
0115         Q_EMIT desktopOffsetChanged();
0116     });
0117 
0118     m_shutdownTimer->setSingleShot(true);
0119     connect(m_shutdownTimer, &QTimer::timeout, this, &OverviewEffect::realDeactivate);
0120 
0121     auto cycleAction = new QAction(this);
0122     connect(cycleAction, &QAction::triggered, this, &OverviewEffect::cycle);
0123     cycleAction->setObjectName(QStringLiteral("Cycle Overview"));
0124     cycleAction->setText(i18nc("@action Grid View and Overview are the name of KWin effects", "Cycle through Overview and Grid View"));
0125     KGlobalAccel::self()->setDefaultShortcut(cycleAction, {});
0126     KGlobalAccel::self()->setShortcut(cycleAction, {});
0127     m_cycleShortcut = KGlobalAccel::self()->shortcut(cycleAction);
0128 
0129     auto reverseCycleAction = new QAction(this);
0130     connect(reverseCycleAction, &QAction::triggered, this, &OverviewEffect::reverseCycle);
0131     reverseCycleAction->setObjectName(QStringLiteral("Cycle Overview Opposite"));
0132     reverseCycleAction->setText(i18nc("@action Grid View and Overview are the name of KWin effects", "Cycle through Grid View and Overview"));
0133     KGlobalAccel::self()->setDefaultShortcut(reverseCycleAction, {});
0134     KGlobalAccel::self()->setShortcut(reverseCycleAction, {});
0135     m_reverseCycleShortcut = KGlobalAccel::self()->shortcut(reverseCycleAction);
0136 
0137     const QKeySequence defaultOverviewShortcut = Qt::META | Qt::Key_W;
0138     auto overviewAction = m_overviewState->toggleAction();
0139     overviewAction->setObjectName(QStringLiteral("Overview"));
0140     overviewAction->setText(i18nc("@action Overview is the name of a Kwin effect", "Toggle Overview"));
0141     KGlobalAccel::self()->setDefaultShortcut(overviewAction, {defaultOverviewShortcut});
0142     KGlobalAccel::self()->setShortcut(overviewAction, {defaultOverviewShortcut});
0143     m_overviewShortcut = KGlobalAccel::self()->shortcut(overviewAction);
0144 
0145     const QKeySequence defaultGridShortcut = Qt::META | Qt::Key_G;
0146     auto gridAction = m_gridState->toggleAction();
0147     gridAction->setObjectName(QStringLiteral("Grid View"));
0148     gridAction->setText(i18nc("@action Grid view is the name of a Kwin effect", "Toggle Grid View"));
0149     KGlobalAccel::self()->setDefaultShortcut(gridAction, {defaultGridShortcut});
0150     KGlobalAccel::self()->setShortcut(gridAction, {defaultGridShortcut});
0151     m_overviewShortcut = KGlobalAccel::self()->shortcut(gridAction);
0152 
0153     connect(effects, &EffectsHandler::screenAboutToLock, this, &OverviewEffect::realDeactivate);
0154 
0155     OverviewConfig::instance(effects->config());
0156     reconfigure(ReconfigureAll);
0157 
0158     auto delegate = new QQmlComponent(effects->qmlEngine());
0159     connect(delegate, &QQmlComponent::statusChanged, this, [delegate]() {
0160         if (delegate->isError()) {
0161             qWarning() << "Failed to load overview:" << delegate->errorString();
0162         }
0163     });
0164     delegate->loadUrl(QUrl(QStringLiteral("qrc:/overview/qml/main.qml")), QQmlComponent::Asynchronous);
0165     setDelegate(delegate);
0166 }
0167 
0168 OverviewEffect::~OverviewEffect()
0169 {
0170 }
0171 
0172 void OverviewEffect::reconfigure(ReconfigureFlags)
0173 {
0174     OverviewConfig::self()->read();
0175     setLayout(OverviewConfig::layoutMode());
0176     setAnimationDuration(animationTime(300));
0177     setFilterWindows(OverviewConfig::filterWindows());
0178 
0179     for (const ElectricBorder &border : std::as_const(m_borderActivate)) {
0180         effects->unreserveElectricBorder(border, this);
0181     }
0182 
0183     m_borderActivate.clear();
0184 
0185     const QList<int> activateBorders = OverviewConfig::borderActivate();
0186     for (const int &border : activateBorders) {
0187         m_borderActivate.append(ElectricBorder(border));
0188         effects->reserveElectricBorder(ElectricBorder(border), this);
0189     }
0190 
0191     m_border->setBorders(OverviewConfig::touchBorderActivate());
0192 }
0193 
0194 int OverviewEffect::animationDuration() const
0195 {
0196     return m_animationDuration;
0197 }
0198 
0199 void OverviewEffect::setAnimationDuration(int duration)
0200 {
0201     if (m_animationDuration != duration) {
0202         m_animationDuration = duration;
0203         Q_EMIT animationDurationChanged();
0204     }
0205 }
0206 
0207 bool OverviewEffect::filterWindows() const
0208 {
0209     return m_filterWindows;
0210 }
0211 
0212 void OverviewEffect::setFilterWindows(bool filterWindows)
0213 {
0214     if (m_filterWindows != filterWindows) {
0215         m_filterWindows = filterWindows;
0216         Q_EMIT filterWindowsChanged();
0217     }
0218 }
0219 
0220 qreal OverviewEffect::overviewPartialActivationFactor() const
0221 {
0222     return m_overviewState->partialActivationFactor();
0223 }
0224 
0225 bool OverviewEffect::overviewGestureInProgress() const
0226 {
0227     return m_overviewState->inProgress();
0228 }
0229 
0230 qreal OverviewEffect::transitionPartialActivationFactor() const
0231 {
0232     return m_transitionState->partialActivationFactor();
0233 }
0234 
0235 bool OverviewEffect::transitionGestureInProgress() const
0236 {
0237     return m_transitionState->inProgress();
0238 }
0239 
0240 qreal OverviewEffect::gridPartialActivationFactor() const
0241 {
0242     return m_gridState->partialActivationFactor();
0243 }
0244 
0245 bool OverviewEffect::gridGestureInProgress() const
0246 {
0247     return m_gridState->inProgress();
0248 }
0249 
0250 QPointF OverviewEffect::desktopOffset() const
0251 {
0252     return m_desktopOffset;
0253 }
0254 
0255 int OverviewEffect::layout() const
0256 {
0257     return m_layout;
0258 }
0259 
0260 bool OverviewEffect::ignoreMinimized() const
0261 {
0262     return OverviewConfig::ignoreMinimized();
0263 }
0264 
0265 bool OverviewEffect::organizedGrid() const
0266 {
0267     return OverviewConfig::organizedGrid();
0268 }
0269 
0270 void OverviewEffect::setLayout(int layout)
0271 {
0272     if (m_layout != layout) {
0273         m_layout = layout;
0274         Q_EMIT layoutChanged();
0275     }
0276 }
0277 
0278 int OverviewEffect::requestedEffectChainPosition() const
0279 {
0280     return 70;
0281 }
0282 
0283 bool OverviewEffect::borderActivated(ElectricBorder border)
0284 {
0285     if (m_borderActivate.contains(border)) {
0286         cycle();
0287         return true;
0288     }
0289     return false;
0290 }
0291 
0292 void OverviewEffect::activate()
0293 {
0294     if (effects->isScreenLocked()) {
0295         return;
0296     }
0297 
0298     m_overviewState->activate();
0299 }
0300 
0301 void OverviewEffect::deactivate()
0302 {
0303     const auto screens = effects->screens();
0304     m_shutdownTimer->start(animationDuration());
0305     m_overviewState->deactivate();
0306 }
0307 
0308 void OverviewEffect::realDeactivate()
0309 {
0310     if (m_overviewState->status() == EffectTogglableState::Status::Inactive) {
0311         setRunning(false);
0312     }
0313 }
0314 
0315 void OverviewEffect::cycle()
0316 {
0317     if (m_overviewState->status() == EffectTogglableState::Status::Inactive) {
0318         m_overviewState->activate();
0319     } else if (m_transitionState->status() == EffectTogglableState::Status::Inactive) {
0320         m_transitionState->activate();
0321     } else if (m_gridState->status() == EffectTogglableState::Status::Active) {
0322         m_overviewState->deactivate();
0323     }
0324 }
0325 
0326 void OverviewEffect::reverseCycle()
0327 {
0328     if (m_overviewState->status() == EffectTogglableState::Status::Active) {
0329         m_overviewState->deactivate();
0330     } else if (m_transitionState->status() == EffectTogglableState::Status::Active) {
0331         m_transitionState->deactivate();
0332     } else if (m_gridState->status() == EffectTogglableState::Status::Inactive) {
0333         m_gridState->activate();
0334     }
0335 }
0336 
0337 void OverviewEffect::grabbedKeyboardEvent(QKeyEvent *keyEvent)
0338 {
0339     if (m_cycleShortcut.contains(keyEvent->key() | keyEvent->modifiers())) {
0340         if (keyEvent->type() == QEvent::KeyPress) {
0341             cycle();
0342         }
0343         return;
0344     }
0345     if (m_reverseCycleShortcut.contains(keyEvent->key() | keyEvent->modifiers())) {
0346         if (keyEvent->type() == QEvent::KeyPress) {
0347             reverseCycle();
0348         }
0349         return;
0350     }
0351     if (m_overviewShortcut.contains(keyEvent->key() | keyEvent->modifiers())) {
0352         if (keyEvent->type() == QEvent::KeyPress) {
0353             m_overviewState->toggleAction();
0354         }
0355         return;
0356     }
0357     if (m_gridShortcut.contains(keyEvent->key() | keyEvent->modifiers())) {
0358         if (keyEvent->type() == QEvent::KeyPress) {
0359             m_gridState->toggleAction();
0360         }
0361         return;
0362     }
0363     QuickSceneEffect::grabbedKeyboardEvent(keyEvent);
0364 }
0365 
0366 void OverviewEffect::swapDesktops(VirtualDesktop *from, VirtualDesktop *to)
0367 {
0368     QList<EffectWindow *> fromList;
0369     QList<EffectWindow *> toList;
0370     for (auto *w : effects->stackingOrder()) {
0371         if (!w->isNormalWindow() || !w->isOnCurrentActivity()) {
0372             continue;
0373         }
0374         if (w->isOnDesktop(from)) {
0375             fromList << w;
0376         } else if (w->isOnDesktop(to)) {
0377             toList << w;
0378         }
0379     }
0380     for (auto *w : fromList) {
0381         effects->windowToDesktops(w, {to});
0382     }
0383     for (auto *w : toList) {
0384         effects->windowToDesktops(w, {from});
0385     }
0386 }
0387 
0388 } // namespace KWin
0389 
0390 #include "moc_overvieweffect.cpp"