File indexing completed on 2024-11-10 04:56:44
0001 /* 0002 SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "effect/effecttogglablestate.h" 0008 #include "effect/effecthandler.h" 0009 0010 namespace KWin 0011 { 0012 0013 EffectTogglableState::EffectTogglableState(Effect *effect) 0014 : QObject(effect) 0015 , m_deactivateAction(std::make_unique<QAction>()) 0016 , m_activateAction(std::make_unique<QAction>()) 0017 , m_toggleAction(std::make_unique<QAction>()) 0018 { 0019 connect(m_activateAction.get(), &QAction::triggered, this, [this]() { 0020 if (m_status == Status::Activating) { 0021 if (m_partialActivationFactor > 0.5) { 0022 activate(); 0023 Q_EMIT activated(); 0024 } else { 0025 deactivate(); 0026 Q_EMIT deactivated(); 0027 } 0028 } 0029 }); 0030 connect(m_deactivateAction.get(), &QAction::triggered, this, [this]() { 0031 if (m_status == Status::Deactivating) { 0032 if (m_partialActivationFactor < 0.5) { 0033 deactivate(); 0034 Q_EMIT deactivated(); 0035 } else { 0036 activate(); 0037 Q_EMIT activated(); 0038 } 0039 } 0040 }); 0041 connect(m_toggleAction.get(), &QAction::triggered, this, &EffectTogglableState::toggle); 0042 } 0043 0044 void EffectTogglableState::activate() 0045 { 0046 setInProgress(false); 0047 setPartialActivationFactor(1.0); 0048 setStatus(Status::Active); 0049 } 0050 0051 void EffectTogglableState::setPartialActivationFactor(qreal factor) 0052 { 0053 if (m_partialActivationFactor != factor) { 0054 m_partialActivationFactor = factor; 0055 Q_EMIT partialActivationFactorChanged(); 0056 } 0057 } 0058 0059 void EffectTogglableState::deactivate() 0060 { 0061 setInProgress(false); 0062 setPartialActivationFactor(0.0); 0063 setStatus(Status::Inactive); 0064 } 0065 0066 void EffectTogglableState::stop() 0067 { 0068 setInProgress(false); 0069 setPartialActivationFactor(0.0); 0070 setStatus(Status::Stopped); 0071 } 0072 0073 bool EffectTogglableState::inProgress() const 0074 { 0075 return m_inProgress; 0076 } 0077 0078 void EffectTogglableState::setInProgress(bool gesture) 0079 { 0080 if (m_inProgress != gesture) { 0081 m_inProgress = gesture; 0082 Q_EMIT inProgressChanged(); 0083 } 0084 } 0085 0086 void EffectTogglableState::setStatus(Status status) 0087 { 0088 if (m_status != status) { 0089 m_status = status; 0090 Q_EMIT statusChanged(status); 0091 } 0092 } 0093 0094 void EffectTogglableState::partialActivate(qreal factor) 0095 { 0096 if (effects->isScreenLocked()) { 0097 return; 0098 } 0099 0100 setStatus(Status::Activating); 0101 setInProgress(true); 0102 setPartialActivationFactor(factor); 0103 } 0104 0105 void EffectTogglableState::partialDeactivate(qreal factor) 0106 { 0107 setStatus(Status::Deactivating); 0108 setInProgress(true); 0109 setPartialActivationFactor(1.0 - factor); 0110 } 0111 0112 void EffectTogglableState::toggle() 0113 { 0114 if (m_status == Status::Inactive) { 0115 activate(); 0116 Q_EMIT activated(); 0117 } else { 0118 deactivate(); 0119 Q_EMIT deactivated(); 0120 } 0121 } 0122 0123 void EffectTogglableState::setProgress(qreal progress) 0124 { 0125 if (m_status == Status::Stopped) { 0126 return; 0127 } 0128 if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == parent()) { 0129 switch (m_status) { 0130 case Status::Inactive: 0131 case Status::Activating: 0132 partialActivate(progress); 0133 break; 0134 default: 0135 break; 0136 } 0137 } 0138 } 0139 0140 void EffectTogglableState::setRegress(qreal regress) 0141 { 0142 if (m_status == Status::Stopped) { 0143 return; 0144 } 0145 if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == parent()) { 0146 switch (m_status) { 0147 case Status::Active: 0148 case Status::Deactivating: 0149 partialDeactivate(regress); 0150 break; 0151 default: 0152 break; 0153 } 0154 } 0155 } 0156 0157 EffectTogglableGesture::EffectTogglableGesture(EffectTogglableState *state) 0158 : QObject(state) 0159 , m_state(state) 0160 { 0161 } 0162 0163 static PinchDirection opposite(PinchDirection direction) 0164 { 0165 switch (direction) { 0166 case PinchDirection::Contracting: 0167 return PinchDirection::Expanding; 0168 case PinchDirection::Expanding: 0169 return PinchDirection::Contracting; 0170 } 0171 return PinchDirection::Expanding; 0172 } 0173 0174 static SwipeDirection opposite(SwipeDirection direction) 0175 { 0176 switch (direction) { 0177 case SwipeDirection::Invalid: 0178 return SwipeDirection::Invalid; 0179 case SwipeDirection::Down: 0180 return SwipeDirection::Up; 0181 case SwipeDirection::Up: 0182 return SwipeDirection::Down; 0183 case SwipeDirection::Left: 0184 return SwipeDirection::Right; 0185 case SwipeDirection::Right: 0186 return SwipeDirection::Left; 0187 } 0188 return SwipeDirection::Invalid; 0189 } 0190 0191 std::function<void(qreal progress)> EffectTogglableState::progressCallback() 0192 { 0193 return [this](qreal progress) { 0194 setProgress(progress); 0195 }; 0196 } 0197 0198 std::function<void(qreal progress)> EffectTogglableState::regressCallback() 0199 { 0200 return [this](qreal progress) { 0201 setRegress(progress); 0202 }; 0203 } 0204 0205 void EffectTogglableGesture::addTouchpadPinchGesture(PinchDirection direction, uint fingerCount) 0206 { 0207 effects->registerTouchpadPinchShortcut(direction, fingerCount, m_state->activateAction(), m_state->progressCallback()); 0208 effects->registerTouchpadPinchShortcut(opposite(direction), fingerCount, m_state->deactivateAction(), m_state->regressCallback()); 0209 } 0210 0211 void EffectTogglableGesture::addTouchpadSwipeGesture(SwipeDirection direction, uint fingerCount) 0212 { 0213 effects->registerTouchpadSwipeShortcut(direction, fingerCount, m_state->activateAction(), m_state->progressCallback()); 0214 effects->registerTouchpadSwipeShortcut(opposite(direction), fingerCount, m_state->deactivateAction(), m_state->regressCallback()); 0215 } 0216 0217 void EffectTogglableGesture::addTouchscreenSwipeGesture(SwipeDirection direction, uint fingerCount) 0218 { 0219 effects->registerTouchscreenSwipeShortcut(direction, fingerCount, m_state->activateAction(), m_state->progressCallback()); 0220 effects->registerTouchscreenSwipeShortcut(opposite(direction), fingerCount, m_state->deactivateAction(), m_state->regressCallback()); 0221 } 0222 0223 EffectTogglableTouchBorder::EffectTogglableTouchBorder(EffectTogglableState *state) 0224 : QObject(state) 0225 , m_state(state) 0226 { 0227 } 0228 0229 EffectTogglableTouchBorder::~EffectTogglableTouchBorder() 0230 { 0231 for (const ElectricBorder &border : std::as_const(m_touchBorderActivate)) { 0232 effects->unregisterTouchBorder(border, m_state->activateAction()); 0233 } 0234 } 0235 0236 void EffectTogglableTouchBorder::setBorders(const QList<int> &touchActivateBorders) 0237 { 0238 for (const ElectricBorder &border : std::as_const(m_touchBorderActivate)) { 0239 effects->unregisterTouchBorder(border, m_state->activateAction()); 0240 } 0241 m_touchBorderActivate.clear(); 0242 0243 for (const int &border : touchActivateBorders) { 0244 m_touchBorderActivate.append(ElectricBorder(border)); 0245 effects->registerRealtimeTouchBorder(ElectricBorder(border), m_state->activateAction(), [this](ElectricBorder border, const QPointF &deltaProgress, const Output *screen) { 0246 if (m_state->status() == EffectTogglableState::Status::Active) { 0247 return; 0248 } 0249 const int maxDelta = 500; // Arbitrary logical pixels value seems to behave better than scaledScreenSize 0250 qreal progress = 0; 0251 if (border == ElectricTop || border == ElectricBottom) { 0252 progress = std::min(1.0, std::abs(deltaProgress.y()) / maxDelta); 0253 } else { 0254 progress = std::min(1.0, std::abs(deltaProgress.x()) / maxDelta); 0255 } 0256 m_state->setProgress(progress); 0257 }); 0258 } 0259 } 0260 0261 } 0262 0263 #include "moc_effecttogglablestate.cpp"