2023-03-06 06:38:43 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
|
|
|
|
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
|
|
#include "mobiletaskswitchereffect.h"
|
|
|
|
|
|
2023-03-25 06:29:40 +00:00
|
|
|
#include <QDBusConnection>
|
|
|
|
|
#include <QDBusMessage>
|
|
|
|
|
#include <QDBusReply>
|
2023-03-06 06:38:43 +00:00
|
|
|
#include <QKeyEvent>
|
|
|
|
|
#include <QMetaObject>
|
|
|
|
|
#include <QQuickItem>
|
|
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
MobileTaskSwitcherEffect::MobileTaskSwitcherEffect()
|
2023-11-16 06:45:23 +00:00
|
|
|
: m_taskSwitcherState{new EffectTogglableState(this)}
|
|
|
|
|
, m_border{new EffectTogglableTouchBorder{m_taskSwitcherState}}
|
|
|
|
|
, m_shutdownTimer{new QTimer{this}}
|
|
|
|
|
{
|
|
|
|
|
auto gesture = new EffectTogglableGesture{m_taskSwitcherState};
|
|
|
|
|
gesture->addTouchpadSwipeGesture(SwipeDirection::Up, 3);
|
|
|
|
|
gesture->addTouchscreenSwipeGesture(SwipeDirection::Up, 1);
|
|
|
|
|
|
|
|
|
|
connect(m_taskSwitcherState, &EffectTogglableState::inProgressChanged, this, &MobileTaskSwitcherEffect::gestureInProgressChanged);
|
|
|
|
|
connect(m_taskSwitcherState, &EffectTogglableState::partialActivationFactorChanged, this, &MobileTaskSwitcherEffect::partialActivationFactorChanged);
|
|
|
|
|
connect(m_taskSwitcherState, &EffectTogglableState::statusChanged, this, [this](EffectTogglableState::Status status) {
|
|
|
|
|
if (status == EffectTogglableState::Status::Activating || status == EffectTogglableState::Status::Active) {
|
|
|
|
|
setRunning(true);
|
|
|
|
|
setDBusState(true);
|
|
|
|
|
}
|
|
|
|
|
if (status == EffectTogglableState::Status::Inactive) {
|
|
|
|
|
deactivate(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// configure close timer
|
2023-03-06 06:38:43 +00:00
|
|
|
m_shutdownTimer->setSingleShot(true);
|
|
|
|
|
connect(m_shutdownTimer, &QTimer::timeout, this, &MobileTaskSwitcherEffect::realDeactivate);
|
|
|
|
|
|
2023-11-16 06:45:23 +00:00
|
|
|
// toggle action
|
2023-03-06 06:38:43 +00:00
|
|
|
const QKeySequence defaultToggleShortcut = Qt::META | Qt::Key_C;
|
|
|
|
|
|
2023-11-16 06:45:23 +00:00
|
|
|
auto toggleAction = m_taskSwitcherState->toggleAction();
|
|
|
|
|
toggleAction->setObjectName(QStringLiteral("Mobile Task Switcher"));
|
|
|
|
|
toggleAction->setText(i18n("Toggle Mobile Task Switcher"));
|
|
|
|
|
KGlobalAccel::self()->setDefaultShortcut(toggleAction, {defaultToggleShortcut});
|
|
|
|
|
KGlobalAccel::self()->setShortcut(toggleAction, {defaultToggleShortcut});
|
2023-03-06 06:38:43 +00:00
|
|
|
|
|
|
|
|
connect(effects, &EffectsHandler::screenAboutToLock, this, &MobileTaskSwitcherEffect::realDeactivate);
|
|
|
|
|
|
|
|
|
|
setSource(QUrl::fromLocalFile(
|
|
|
|
|
QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/mobiletaskswitcher/qml/TaskSwitcher.qml"))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MobileTaskSwitcherEffect::~MobileTaskSwitcherEffect()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::reconfigure(ReconfigureFlags)
|
|
|
|
|
{
|
|
|
|
|
setAnimationDuration(animationTime(300));
|
|
|
|
|
|
|
|
|
|
for (const ElectricBorder &border : std::as_const(m_borderActivate)) {
|
|
|
|
|
effects->unreserveElectricBorder(border, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_borderActivate.clear();
|
|
|
|
|
|
|
|
|
|
const QList<int> activateBorders = {ElectricBorder::ElectricBottom};
|
|
|
|
|
for (const int &border : activateBorders) {
|
|
|
|
|
m_borderActivate.append(ElectricBorder(border));
|
|
|
|
|
effects->reserveElectricBorder(ElectricBorder(border), this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int MobileTaskSwitcherEffect::requestedEffectChainPosition() const
|
|
|
|
|
{
|
|
|
|
|
return 70;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MobileTaskSwitcherEffect::borderActivated(ElectricBorder border)
|
|
|
|
|
{
|
2023-11-16 06:45:23 +00:00
|
|
|
if (m_borderActivate.contains(border)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-03-06 06:38:43 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::grabbedKeyboardEvent(QKeyEvent *keyEvent)
|
|
|
|
|
{
|
|
|
|
|
if (m_toggleShortcut.contains(keyEvent->key() | keyEvent->modifiers())) {
|
|
|
|
|
if (keyEvent->type() == QEvent::KeyPress) {
|
|
|
|
|
toggle();
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
QuickSceneEffect::grabbedKeyboardEvent(keyEvent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::toggle()
|
|
|
|
|
{
|
|
|
|
|
if (!isRunning()) {
|
|
|
|
|
activate();
|
|
|
|
|
} else {
|
|
|
|
|
deactivate(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::activate()
|
|
|
|
|
{
|
|
|
|
|
if (effects->isScreenLocked()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-16 06:45:23 +00:00
|
|
|
m_taskSwitcherState->activate();
|
2023-03-06 06:38:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::deactivate(bool deactivateInstantly)
|
|
|
|
|
{
|
|
|
|
|
const auto screens = effects->screens();
|
|
|
|
|
for (const auto screen : screens) {
|
|
|
|
|
if (QuickSceneView *view = viewForScreen(screen)) {
|
|
|
|
|
QMetaObject::invokeMethod(view->rootItem(), "hideAnimation");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_shutdownTimer->start(animationTime(deactivateInstantly ? 0 : 200));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::realDeactivate()
|
|
|
|
|
{
|
2023-11-16 06:45:23 +00:00
|
|
|
m_taskSwitcherState->deactivate();
|
|
|
|
|
if (m_taskSwitcherState->status() == EffectTogglableState::Status::Inactive) {
|
|
|
|
|
setRunning(false);
|
|
|
|
|
setDBusState(false);
|
|
|
|
|
}
|
2023-03-06 06:38:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::quickDeactivate()
|
|
|
|
|
{
|
|
|
|
|
m_shutdownTimer->start(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int MobileTaskSwitcherEffect::animationDuration() const
|
|
|
|
|
{
|
|
|
|
|
return m_animationDuration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::setAnimationDuration(int duration)
|
|
|
|
|
{
|
|
|
|
|
if (m_animationDuration != duration) {
|
|
|
|
|
m_animationDuration = duration;
|
|
|
|
|
Q_EMIT animationDurationChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MobileTaskSwitcherEffect::gestureInProgress() const
|
|
|
|
|
{
|
2023-11-16 06:45:23 +00:00
|
|
|
return m_taskSwitcherState->inProgress();
|
2023-03-06 06:38:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qreal MobileTaskSwitcherEffect::partialActivationFactor() const
|
|
|
|
|
{
|
2023-11-16 06:45:23 +00:00
|
|
|
return m_taskSwitcherState->partialActivationFactor();
|
2023-03-06 06:38:43 +00:00
|
|
|
}
|
2023-03-25 06:29:40 +00:00
|
|
|
|
|
|
|
|
void MobileTaskSwitcherEffect::setDBusState(bool active)
|
|
|
|
|
{
|
|
|
|
|
QDBusMessage request = QDBusMessage::createMethodCall(QStringLiteral("org.kde.plasmashell"),
|
|
|
|
|
QStringLiteral("/Mobile"),
|
|
|
|
|
QStringLiteral("org.kde.plasmashell"),
|
|
|
|
|
QStringLiteral("setIsTaskSwitcherVisible"));
|
|
|
|
|
request.setArguments({active});
|
2023-03-26 17:18:06 +00:00
|
|
|
|
|
|
|
|
// this does not block, so it won't necessarily be called before the method returns
|
|
|
|
|
QDBusConnection::sessionBus().send(request);
|
2023-03-25 06:29:40 +00:00
|
|
|
}
|
2023-03-06 06:38:43 +00:00
|
|
|
}
|