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"