mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
taskswitcher: Switch to declarative effect
This switches the kwin effect to be a declarative effect. However, for now I have retained much of the logic that exists in cpp as a QML plugin. Fixes https://invent.kde.org/plasma/plasma-mobile/-/issues/448 Also implements https://invent.kde.org/plasma/plasma-mobile/-/issues/408 now that we can access the QML api
This commit is contained in:
parent
7e07038a69
commit
bbac7e98b4
19 changed files with 235 additions and 220 deletions
|
|
@ -4,7 +4,7 @@
|
|||
# SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
project(plasma-mobile)
|
||||
set(PROJECT_VERSION "6.3.80")
|
||||
|
|
|
|||
|
|
@ -1,28 +1,10 @@
|
|||
# SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
kcoreaddons_add_plugin(mobiletaskswitcher INSTALL_NAMESPACE "kwin/effects/plugins")
|
||||
target_sources(mobiletaskswitcher PRIVATE
|
||||
main.cpp
|
||||
mobiletaskswitchereffect.cpp
|
||||
effecttouchborder.cpp
|
||||
taskfiltermodel.cpp
|
||||
taskmodel.cpp
|
||||
)
|
||||
kpackage_install_package(package mobiletaskswitcher effects kwin)
|
||||
|
||||
target_link_libraries(mobiletaskswitcher
|
||||
KF6::ConfigGui
|
||||
KF6::GlobalAccel
|
||||
KF6::I18n
|
||||
KF6::CoreAddons
|
||||
KF6::WindowSystem
|
||||
# Copy the script to the build directory so one can run tests without prior
|
||||
# make install.
|
||||
file(COPY package/contents package/metadata.json DESTINATION ${CMAKE_BINARY_DIR}/bin/kwin/effects/mobiletaskswitcher)
|
||||
|
||||
Qt::Quick
|
||||
Qt::Core
|
||||
|
||||
KWin::kwin
|
||||
Plasma::Activities
|
||||
)
|
||||
|
||||
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/mobiletaskswitcher)
|
||||
install(FILES mobiletaskswitcher.json DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/mobiletaskswitcher)
|
||||
add_subdirectory(plugin)
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "mobiletaskswitchereffect.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
KWIN_EFFECT_FACTORY_SUPPORTED(MobileTaskSwitcherEffect, "mobiletaskswitcher.json", return MobileTaskSwitcherEffect::supported();)
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
#include "main.moc"
|
||||
|
|
@ -12,7 +12,7 @@ import org.kde.plasma.components 3.0 as PlasmaComponents
|
|||
import org.kde.plasma.private.mobileshell as MobileShell
|
||||
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
||||
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
||||
import org.kde.private.mobileshell.taskswitcher 1.0 as TaskSwitcherData
|
||||
import org.kde.plasma.private.mobileshell.taskswitcherplugin as TaskSwitcherPlugin
|
||||
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
import org.kde.kwin.private.effects 1.0
|
||||
|
|
@ -26,8 +26,8 @@ FocusScope {
|
|||
id: root
|
||||
focus: true
|
||||
|
||||
property TaskSwitcherPlugin.MobileTaskSwitcherState state
|
||||
readonly property QtObject effect: KWinComponents.SceneView.effect
|
||||
readonly property TaskSwitcherData.TaskSwitcherState state: TaskSwitcherData.TaskSwitcherState
|
||||
readonly property QtObject targetScreen: KWinComponents.SceneView.screen
|
||||
|
||||
readonly property real topMargin: MobileShell.Constants.topPanelHeight
|
||||
|
|
@ -37,7 +37,6 @@ FocusScope {
|
|||
|
||||
property var taskSwitcherHelpers: TaskSwitcherHelpers {
|
||||
taskSwitcher: root
|
||||
stateClass: TaskSwitcherData.TaskSwitcherState
|
||||
taskList: taskList
|
||||
}
|
||||
|
||||
|
|
@ -45,9 +44,9 @@ FocusScope {
|
|||
id: haptics
|
||||
}
|
||||
|
||||
property var tasksModel: TaskSwitcherData.TaskFilterModel {
|
||||
property var tasksModel: TaskSwitcherPlugin.TaskFilterModel {
|
||||
screenName: root.targetScreen.name
|
||||
windowModel: TaskSwitcherData.TaskModel
|
||||
windowModel: root.state.taskModel
|
||||
}
|
||||
|
||||
readonly property int tasksCount: taskList.count
|
||||
|
|
@ -147,11 +146,11 @@ FocusScope {
|
|||
}
|
||||
|
||||
function instantHide() {
|
||||
root.effect.deactivate(true);
|
||||
root.state.deactivate(true);
|
||||
}
|
||||
|
||||
function hide() {
|
||||
root.effect.deactivate(false);
|
||||
root.state.deactivate(false);
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
|
@ -196,7 +195,7 @@ FocusScope {
|
|||
// setup some values and return to the initial setup so that the user can always navigate with no down time
|
||||
state.wasInActiveTask = taskSwitcherHelpers.openAppAnim.running ? true : false
|
||||
taskList.setTaskOffsetValue(state.wasInActiveTask ? taskSwitcherHelpers.taskOffsetValue : taskSwitcherHelpers.homeOffsetValue, true);
|
||||
state.status = !state.wasInActiveTask ? (taskSwitcherHelpers.openAppAnim.closeAnim && !taskSwitcherHelpers.taskDrawerWillOpen ? TaskSwitcherData.TaskSwitcherState.Active : TaskSwitcherData.TaskSwitcherState.Inactive) : TaskSwitcherData.TaskSwitcherState.Inactive
|
||||
state.status = !state.wasInActiveTask ? (taskSwitcherHelpers.openAppAnim.closeAnim && !taskSwitcherHelpers.taskDrawerWillOpen ? TaskSwitcherPlugin.TaskSwitcherState.Active : TaskSwitcherPlugin.TaskSwitcherState.Inactive) : TaskSwitcherPlugin.TaskSwitcherState.Inactive
|
||||
initialSetup();
|
||||
} else if (taskSwitcherHelpers.openAnim.running) {
|
||||
taskSwitcherHelpers.cancelAnimations();
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
import QtQuick 2.15
|
||||
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.private.mobileshell.taskswitcher 1.0 as TaskSwitcherData
|
||||
import org.kde.plasma.private.mobileshell.taskswitcherplugin as TaskSwitcherPlugin
|
||||
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
|
||||
|
|
@ -19,7 +19,6 @@ QtObject {
|
|||
// We assume that the taskSwitcher is the size of the entire screen.
|
||||
required property var taskSwitcher
|
||||
property var state: taskSwitcher.state
|
||||
required property var stateClass
|
||||
required property var taskList
|
||||
|
||||
// task switcher peek and pop setting for when it is toggled from the home screen
|
||||
|
|
@ -56,7 +55,7 @@ QtObject {
|
|||
readonly property real heightThreshold: windowHeight * 0.55
|
||||
|
||||
// whether the switcher is opened or not
|
||||
readonly property bool taskDrawerOpened: state.status == TaskSwitcherData.TaskSwitcherState.Active
|
||||
readonly property bool taskDrawerOpened: state.status == TaskSwitcherPlugin.MobileTaskSwitcherState.Active
|
||||
|
||||
// This is true when the task drawer is already opened or if within an app
|
||||
readonly property bool notHomeScreenState: state.wasInActiveTask || taskDrawerOpened
|
||||
|
|
@ -312,7 +311,7 @@ QtObject {
|
|||
|
||||
onFinished: {
|
||||
if (!isInTaskScrubMode) {
|
||||
root.state.status = stateClass.Active;
|
||||
root.state.status = TaskSwitcherPlugin.MobileTaskSwitcherState.Active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -328,7 +327,7 @@ QtObject {
|
|||
easing.type: Easing.InBack
|
||||
|
||||
onFinished: {
|
||||
root.state.status = stateClass.Inactive;
|
||||
root.state.status = TaskSwitcherPlugin.MobileTaskSwitcherState.Inactive;
|
||||
taskSwitcher.instantHide();
|
||||
}
|
||||
}
|
||||
|
|
@ -360,7 +359,7 @@ QtObject {
|
|||
duration: 300
|
||||
easing.type: Easing.OutQuint
|
||||
onFinished: {
|
||||
root.state.status = stateClass.Inactive;
|
||||
root.state.status = TaskSwitcherPlugin.MobileTaskSwitcherState.Inactive;
|
||||
taskSwitcher.instantHide();
|
||||
}
|
||||
}
|
||||
38
kwin/mobiletaskswitcher/package/contents/ui/main.qml
Normal file
38
kwin/mobiletaskswitcher/package/contents/ui/main.qml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// SPDX-FileCopyrightText: 2025 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick
|
||||
|
||||
import org.kde.kwin
|
||||
|
||||
import org.kde.plasma.private.mobileshell.taskswitcherplugin as TaskSwitcherPlugin
|
||||
import org.kde.plasma.private.mobileshell.shellsettingsplugin as ShellSettings
|
||||
|
||||
SceneEffect {
|
||||
id: root
|
||||
|
||||
// Created per screen
|
||||
delegate: TaskSwitcher {
|
||||
id: taskSwitcher
|
||||
state: taskSwitcherState
|
||||
}
|
||||
|
||||
ShortcutHandler {
|
||||
name: 'Mobile Task Switcher'
|
||||
text: i18n('Toggle Mobile Task Switcher')
|
||||
sequence: 'Meta+C'
|
||||
|
||||
onActivated: taskSwitcherState.toggle()
|
||||
}
|
||||
|
||||
TaskSwitcherPlugin.MobileTaskSwitcherState {
|
||||
id: taskSwitcherState
|
||||
|
||||
gestureEnabled: !ShellSettings.Settings.navigationPanelEnabled
|
||||
|
||||
Component.onCompleted: {
|
||||
// Initialize with effect
|
||||
taskSwitcherState.init(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,12 @@
|
|||
{
|
||||
"KPackageStructure": "KWin/Effect",
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "devin@kde.org",
|
||||
"Name": "Devin Lin"
|
||||
}
|
||||
],
|
||||
"Category": "Window Management",
|
||||
"Description": "Allows you to switch between running tasks with a mobile interface.",
|
||||
"Description[ca@valencia]": "Us permet canviar entre les tasques diferents en execució amb una interfície mòbil.",
|
||||
|
|
@ -34,8 +41,10 @@
|
|||
"Description[x-test]": "xxAllows you to switch between running tasks with a mobile interface.xx",
|
||||
"Description[zh_CN]": "允许您使用移动界面在正在运行的任务之间切换。",
|
||||
"Description[zh_TW]": "讓您用手機介面在執行中的工作項目之間切換。",
|
||||
"Icon": "preferences-system-windows",
|
||||
"Id": "mobiletaskswitcher",
|
||||
"EnabledByDefault": false,
|
||||
"License": "GPL",
|
||||
"License": "GPL-2.0-or-later",
|
||||
"Name": "Mobile Task Switcher",
|
||||
"Name[ca@valencia]": "Commutador de tasques del mòbil",
|
||||
"Name[ca]": "Commutador de tasques del mòbil",
|
||||
|
|
@ -71,5 +80,7 @@
|
|||
"Name[zh_CN]": "移动任务切换",
|
||||
"Name[zh_TW]": "行動工作切換器"
|
||||
},
|
||||
"X-KWin-Border-Activate": true
|
||||
"X-KWin-Border-Activate": true,
|
||||
"X-KDE-Ordering": 60,
|
||||
"X-Plasma-API": "declarativescript"
|
||||
}
|
||||
26
kwin/mobiletaskswitcher/plugin/CMakeLists.txt
Normal file
26
kwin/mobiletaskswitcher/plugin/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# SPDX-FileCopyrightText: 2025 Devin Lin <devin@kde.org>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
ecm_add_qml_module(mobiletaskswitcherplugin URI org.kde.plasma.private.mobileshell.taskswitcherplugin GENERATE_PLUGIN_SOURCE)
|
||||
|
||||
target_sources(mobiletaskswitcherplugin PRIVATE
|
||||
mobiletaskswitchereffect.cpp
|
||||
effecttouchborder.cpp
|
||||
taskfiltermodel.cpp
|
||||
taskmodel.cpp)
|
||||
|
||||
target_link_libraries(mobiletaskswitcherplugin PRIVATE
|
||||
KF6::ConfigGui
|
||||
KF6::GlobalAccel
|
||||
KF6::I18n
|
||||
KF6::CoreAddons
|
||||
KF6::WindowSystem
|
||||
|
||||
Qt::Quick
|
||||
Qt::Core
|
||||
|
||||
KWin::kwin
|
||||
Plasma::Activities
|
||||
)
|
||||
|
||||
ecm_finalize_qml_module(mobiletaskswitcherplugin)
|
||||
|
|
@ -57,7 +57,7 @@ void EffectTouchBorder::setBorders(const QList<int> &touchActivateBorders)
|
|||
effects->registerRealtimeTouchBorder(ElectricBorder(border),
|
||||
m_state->activateAction(),
|
||||
[this](ElectricBorder border, const QPointF &deltaProgress, const Output *screen) {
|
||||
Q_UNUSED(screen)
|
||||
Q_UNUSED(screen)
|
||||
m_state->setInProgress(true);
|
||||
|
||||
if (border == ElectricTop || border == ElectricBottom) {
|
||||
|
|
@ -18,11 +18,56 @@ using namespace std::chrono_literals;
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
MobileTaskSwitcherState::MobileTaskSwitcherState(EffectTouchBorderState *effectState)
|
||||
: m_effectState{effectState}
|
||||
MobileTaskSwitcherState::MobileTaskSwitcherState(QObject *parent)
|
||||
: QObject{parent}
|
||||
, m_doubleClickTimer{new QElapsedTimer{}}
|
||||
, m_shutdownTimer{new QTimer{this}}
|
||||
{
|
||||
// Configure close timer
|
||||
m_shutdownTimer->setSingleShot(true);
|
||||
m_shutdownTimer->setInterval(300ms);
|
||||
connect(m_shutdownTimer, &QTimer::timeout, this, &MobileTaskSwitcherState::realDeactivate);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherState::init(KWin::QuickSceneEffect *parent)
|
||||
{
|
||||
m_effectState = new EffectTouchBorderState(parent);
|
||||
m_border = new EffectTouchBorder{m_effectState};
|
||||
m_taskModel = new TaskModel{parent};
|
||||
m_effect = parent;
|
||||
|
||||
// Connect signals
|
||||
connect(this, &MobileTaskSwitcherState::gestureEnabledChanged, this, &MobileTaskSwitcherState::refreshBorders);
|
||||
connect(m_border, &EffectTouchBorder::touchPositionChanged, this, &MobileTaskSwitcherState::processTouchPositionChanged);
|
||||
connect(this, &MobileTaskSwitcherState::gestureInProgressChanged, this, [this]() {
|
||||
if (gestureInProgress()) {
|
||||
invokeEffect();
|
||||
}
|
||||
});
|
||||
connect(m_effectState, &EffectTouchBorderState::inProgressChanged, this, &MobileTaskSwitcherState::gestureInProgressChanged);
|
||||
connect(effects, &EffectsHandler::screenAboutToLock, this, &MobileTaskSwitcherState::realDeactivate);
|
||||
|
||||
refreshBorders();
|
||||
}
|
||||
|
||||
bool MobileTaskSwitcherState::gestureEnabled() const
|
||||
{
|
||||
return m_gestureEnabled;
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherState::setGestureEnabled(bool gestureEnabled)
|
||||
{
|
||||
m_gestureEnabled = gestureEnabled;
|
||||
Q_EMIT gestureEnabledChanged();
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherState::refreshBorders()
|
||||
{
|
||||
if (m_gestureEnabled) {
|
||||
m_border->setBorders({ElectricBorder::ElectricBottom});
|
||||
} else {
|
||||
m_border->setBorders({});
|
||||
}
|
||||
}
|
||||
|
||||
bool MobileTaskSwitcherState::gestureInProgress() const
|
||||
|
|
@ -124,6 +169,11 @@ void MobileTaskSwitcherState::setYPosition(qreal yPosition)
|
|||
}
|
||||
}
|
||||
|
||||
MobileTaskSwitcherState::Status MobileTaskSwitcherState::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherState::setStatus(Status status)
|
||||
{
|
||||
if (m_status != status) {
|
||||
|
|
@ -135,6 +185,11 @@ void MobileTaskSwitcherState::setStatus(Status status)
|
|||
}
|
||||
}
|
||||
|
||||
int MobileTaskSwitcherState::currentTaskIndex() const
|
||||
{
|
||||
return m_currentTaskIndex;
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherState::setCurrentTaskIndex(int newTaskIndex)
|
||||
{
|
||||
if (m_currentTaskIndex != newTaskIndex) {
|
||||
|
|
@ -143,6 +198,11 @@ void MobileTaskSwitcherState::setCurrentTaskIndex(int newTaskIndex)
|
|||
}
|
||||
}
|
||||
|
||||
int MobileTaskSwitcherState::initialTaskIndex() const
|
||||
{
|
||||
return m_initialTaskIndex;
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherState::setInitialTaskIndex(int newTaskIndex)
|
||||
{
|
||||
if (m_initialTaskIndex != newTaskIndex) {
|
||||
|
|
@ -151,6 +211,11 @@ void MobileTaskSwitcherState::setInitialTaskIndex(int newTaskIndex)
|
|||
}
|
||||
}
|
||||
|
||||
TaskModel *MobileTaskSwitcherState::taskModel() const
|
||||
{
|
||||
return m_taskModel;
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherState::restartDoubleClickTimer()
|
||||
{
|
||||
m_doubleClickTimer->restart();
|
||||
|
|
@ -198,100 +263,27 @@ void MobileTaskSwitcherState::processTouchPositionChanged(qreal primaryDelta, qr
|
|||
|
||||
qint64 MobileTaskSwitcherState::getElapsedTimeSinceStart()
|
||||
{
|
||||
if (m_doubleClickTimer->isValid())
|
||||
{
|
||||
if (m_doubleClickTimer->isValid()) {
|
||||
return m_doubleClickTimer->elapsed();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MobileTaskSwitcherEffect::MobileTaskSwitcherEffect()
|
||||
: m_effectState{new EffectTouchBorderState(this)}
|
||||
, m_taskSwitcherState{new MobileTaskSwitcherState(m_effectState)}
|
||||
, m_taskModel{new TaskModel{this}}
|
||||
, m_border{new EffectTouchBorder{m_effectState}}
|
||||
, m_toggleAction{std::make_unique<QAction>()}
|
||||
, m_shutdownTimer{new QTimer{this}}
|
||||
void MobileTaskSwitcherState::toggle()
|
||||
{
|
||||
const char *uri = "org.kde.private.mobileshell.taskswitcher";
|
||||
qmlRegisterType<TaskFilterModel>(uri, 1, 0, "TaskFilterModel");
|
||||
qmlRegisterSingletonType<TaskModel>(uri, 1, 0, "TaskModel", [this](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
return m_taskModel;
|
||||
});
|
||||
qmlRegisterSingletonType<MobileTaskSwitcherState>(uri, 1, 0, "TaskSwitcherState", [this](QQmlEngine *, QJSEngine *) -> QObject * {
|
||||
return m_taskSwitcherState;
|
||||
});
|
||||
|
||||
connect(m_border, &EffectTouchBorder::touchPositionChanged, m_taskSwitcherState, &MobileTaskSwitcherState::processTouchPositionChanged);
|
||||
|
||||
connect(m_taskSwitcherState, &MobileTaskSwitcherState::gestureInProgressChanged, this, [this]() {
|
||||
if (m_taskSwitcherState->gestureInProgress()) {
|
||||
invokeEffect();
|
||||
}
|
||||
});
|
||||
|
||||
// configure close timer
|
||||
m_shutdownTimer->setSingleShot(true);
|
||||
connect(m_shutdownTimer, &QTimer::timeout, this, &MobileTaskSwitcherEffect::realDeactivate);
|
||||
|
||||
// toggle action
|
||||
const QKeySequence defaultToggleShortcut = Qt::META | Qt::Key_C;
|
||||
|
||||
m_toggleAction.get()->setObjectName(QStringLiteral("Mobile Task Switcher"));
|
||||
m_toggleAction.get()->setText(i18n("Toggle Mobile Task Switcher"));
|
||||
KGlobalAccel::self()->setDefaultShortcut(m_toggleAction.get(), {defaultToggleShortcut});
|
||||
KGlobalAccel::self()->setShortcut(m_toggleAction.get(), {defaultToggleShortcut});
|
||||
connect(m_toggleAction.get(), &QAction::triggered, this, &MobileTaskSwitcherEffect::toggle);
|
||||
|
||||
connect(effects, &EffectsHandler::screenAboutToLock, this, &MobileTaskSwitcherEffect::realDeactivate);
|
||||
|
||||
setSource(QUrl::fromLocalFile(
|
||||
QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/effects/mobiletaskswitcher/qml/TaskSwitcher.qml"))));
|
||||
reconfigure(ReconfigureFlag::ReconfigureAll);
|
||||
}
|
||||
|
||||
MobileTaskSwitcherEffect::~MobileTaskSwitcherEffect()
|
||||
{
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::reconfigure(ReconfigureFlags)
|
||||
{
|
||||
setAnimationDuration(animationTime(300ms));
|
||||
m_border->setBorders(m_borderActivate);
|
||||
}
|
||||
|
||||
int MobileTaskSwitcherEffect::requestedEffectChainPosition() const
|
||||
{
|
||||
return 70;
|
||||
}
|
||||
|
||||
bool MobileTaskSwitcherEffect::borderActivated(ElectricBorder border)
|
||||
{
|
||||
return m_borderActivate.contains(border);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::grabbedKeyboardEvent(QKeyEvent *keyEvent)
|
||||
{
|
||||
if (m_toggleShortcut.contains(keyEvent->key() | keyEvent->modifiers())) {
|
||||
if (keyEvent->type() == QEvent::KeyPress) {
|
||||
toggle();
|
||||
}
|
||||
if (!m_effect) {
|
||||
return;
|
||||
}
|
||||
QuickSceneEffect::grabbedKeyboardEvent(keyEvent);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::toggle()
|
||||
{
|
||||
if (!isRunning()) {
|
||||
m_taskSwitcherState->restartDoubleClickTimer();
|
||||
if (!m_effect->isRunning()) {
|
||||
restartDoubleClickTimer();
|
||||
activate();
|
||||
} else {
|
||||
deactivate(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::activate()
|
||||
void MobileTaskSwitcherState::activate()
|
||||
{
|
||||
if (effects->isScreenLocked()) {
|
||||
return;
|
||||
|
|
@ -301,44 +293,39 @@ void MobileTaskSwitcherEffect::activate()
|
|||
invokeEffect();
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::deactivate(bool deactivateInstantly)
|
||||
void MobileTaskSwitcherState::deactivate(bool deactivateInstantly)
|
||||
{
|
||||
if (!m_effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto screens = effects->screens();
|
||||
for (const auto screen : screens) {
|
||||
if (QuickSceneView *view = viewForScreen(screen)) {
|
||||
if (QuickSceneView *view = m_effect->viewForScreen(screen)) {
|
||||
QMetaObject::invokeMethod(view->rootItem(), "hideAnimation");
|
||||
}
|
||||
}
|
||||
m_shutdownTimer->start(animationTime(deactivateInstantly ? 0ms : 200ms));
|
||||
m_shutdownTimer->start(m_effect->animationTime(deactivateInstantly ? 0ms : 200ms));
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::realDeactivate()
|
||||
void MobileTaskSwitcherState::realDeactivate()
|
||||
{
|
||||
if (!m_effect || !m_effectState) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_effectState->setInProgress(false);
|
||||
m_taskSwitcherState->setStatus(MobileTaskSwitcherState::Status::Inactive);
|
||||
setRunning(false);
|
||||
setStatus(MobileTaskSwitcherState::Status::Inactive);
|
||||
m_effect->setRunning(false);
|
||||
setDBusState(false);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::quickDeactivate()
|
||||
void MobileTaskSwitcherState::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();
|
||||
}
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::setDBusState(bool active)
|
||||
void MobileTaskSwitcherState::setDBusState(bool active)
|
||||
{
|
||||
QDBusMessage request = QDBusMessage::createMethodCall(QStringLiteral("org.kde.plasmashell"),
|
||||
QStringLiteral("/Mobile"),
|
||||
|
|
@ -350,11 +337,10 @@ void MobileTaskSwitcherEffect::setDBusState(bool active)
|
|||
QDBusConnection::sessionBus().send(request);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::invokeEffect()
|
||||
void MobileTaskSwitcherState::invokeEffect()
|
||||
{
|
||||
m_taskSwitcherState->setInitialTaskIndex(
|
||||
m_taskSwitcherState->currentTaskIndex()); // TODO! this is only until the crashing bug is fixed and recency sorting is in
|
||||
setRunning(true);
|
||||
setInitialTaskIndex(currentTaskIndex()); // TODO! this is only until the crashing bug is fixed and recency sorting is in
|
||||
m_effect->setRunning(true);
|
||||
setDBusState(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,8 @@ namespace KWin
|
|||
class MobileTaskSwitcherState : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool gestureEnabled READ gestureEnabled WRITE setGestureEnabled NOTIFY gestureEnabledChanged)
|
||||
|
||||
Q_PROPERTY(bool wasInActiveTask READ wasInActiveTask WRITE setWasInActiveTask NOTIFY wasInActiveTaskChanged)
|
||||
Q_PROPERTY(int currentTaskIndex READ currentTaskIndex WRITE setCurrentTaskIndex NOTIFY currentTaskIndexChanged)
|
||||
Q_PROPERTY(int initialTaskIndex READ initialTaskIndex WRITE setInitialTaskIndex NOTIFY initialTaskIndexChanged)
|
||||
|
|
@ -51,6 +53,9 @@ class MobileTaskSwitcherState : public QObject
|
|||
Q_PROPERTY(qint64 elapsedTimeSinceStart READ getElapsedTimeSinceStart)
|
||||
Q_PROPERTY(qint64 doubleClickInterval READ getDoubleClickInterval) // is there a better way than to forward this?
|
||||
|
||||
Q_PROPERTY(TaskModel *taskModel READ taskModel CONSTANT)
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
enum class Status {
|
||||
// TODO! I could (should?) re-add the activating and deactivating states again to match EffectTogglableState. could help with/tie into
|
||||
|
|
@ -61,7 +66,12 @@ public:
|
|||
};
|
||||
Q_ENUM(Status)
|
||||
|
||||
MobileTaskSwitcherState(EffectTouchBorderState *effectState);
|
||||
MobileTaskSwitcherState(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void init(KWin::QuickSceneEffect *parent);
|
||||
|
||||
bool gestureEnabled() const;
|
||||
void setGestureEnabled(bool gestureEnabled);
|
||||
|
||||
bool gestureInProgress() const;
|
||||
void setGestureInProgress(bool gestureInProgress);
|
||||
|
|
@ -82,30 +92,34 @@ public:
|
|||
qreal yPosition() const;
|
||||
void setYPosition(qreal positionY);
|
||||
|
||||
Status status() const;
|
||||
void setStatus(Status status);
|
||||
Status status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
int currentTaskIndex() const;
|
||||
void setCurrentTaskIndex(int newTaskIndex);
|
||||
int currentTaskIndex() const
|
||||
{
|
||||
return m_currentTaskIndex;
|
||||
}
|
||||
|
||||
int initialTaskIndex() const;
|
||||
void setInitialTaskIndex(int newTaskIndex);
|
||||
int initialTaskIndex() const
|
||||
{
|
||||
return m_initialTaskIndex;
|
||||
}
|
||||
|
||||
void restartDoubleClickTimer();
|
||||
|
||||
int animationDuration() const;
|
||||
void setDBusState(bool active);
|
||||
|
||||
TaskModel *taskModel() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void processTouchPositionChanged(qreal primaryPosition, qreal orthogonalPosition);
|
||||
|
||||
void activate();
|
||||
void realDeactivate();
|
||||
void deactivate(bool deactivateInstantly);
|
||||
void quickDeactivate();
|
||||
void toggle();
|
||||
|
||||
Q_SIGNALS:
|
||||
void gestureEnabledChanged();
|
||||
|
||||
void activated();
|
||||
void deactivated();
|
||||
|
||||
|
|
@ -125,9 +139,19 @@ Q_SIGNALS:
|
|||
void xPositionChanged();
|
||||
void yPositionChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void refreshBorders();
|
||||
|
||||
private:
|
||||
void invokeEffect();
|
||||
|
||||
bool m_gestureEnabled{false};
|
||||
EffectTouchBorderState *m_effectState{nullptr};
|
||||
EffectTouchBorder *m_border{nullptr};
|
||||
TaskModel *m_taskModel{nullptr};
|
||||
KWin::QuickSceneEffect *m_effect{nullptr};
|
||||
|
||||
Status m_status = Status::Inactive;
|
||||
EffectTouchBorderState *m_effectState;
|
||||
bool m_gestureInProgress = false;
|
||||
|
||||
int m_currentTaskIndex;
|
||||
|
|
@ -161,53 +185,8 @@ private:
|
|||
{
|
||||
return qApp->doubleClickInterval();
|
||||
}
|
||||
};
|
||||
|
||||
class MobileTaskSwitcherEffect : public QuickSceneEffect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Status { Inactive, Activating, Deactivating, Active };
|
||||
MobileTaskSwitcherEffect();
|
||||
~MobileTaskSwitcherEffect() override;
|
||||
|
||||
int animationDuration() const;
|
||||
void setAnimationDuration(int duration);
|
||||
|
||||
int requestedEffectChainPosition() const override;
|
||||
bool borderActivated(ElectricBorder border) override;
|
||||
void reconfigure(ReconfigureFlags flags) override;
|
||||
void grabbedKeyboardEvent(QKeyEvent *keyEvent) override;
|
||||
|
||||
void setDBusState(bool active);
|
||||
|
||||
public Q_SLOTS:
|
||||
void activate();
|
||||
void realDeactivate();
|
||||
void deactivate(bool deactivateInstantly);
|
||||
void quickDeactivate();
|
||||
void toggle();
|
||||
|
||||
Q_SIGNALS:
|
||||
void animationDurationChanged();
|
||||
void gestureInProgressChanged();
|
||||
|
||||
private:
|
||||
void invokeEffect();
|
||||
|
||||
EffectTouchBorderState *const m_effectState;
|
||||
MobileTaskSwitcherState *const m_taskSwitcherState;
|
||||
TaskModel *const m_taskModel;
|
||||
EffectTouchBorder *const m_border;
|
||||
QList<int> m_borderActivate = {ElectricBorder::ElectricBottom};
|
||||
|
||||
std::unique_ptr<QAction> m_toggleAction;
|
||||
QList<QKeySequence> m_toggleShortcut;
|
||||
|
||||
QTimer *m_shutdownTimer;
|
||||
|
||||
int m_animationDuration = 400;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <QAbstractListModel>
|
||||
#include <QHash>
|
||||
#include <QQmlEngine>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QVariant>
|
||||
|
||||
|
|
@ -21,6 +22,7 @@ class TaskFilterModel : public QSortFilterProxyModel
|
|||
Q_OBJECT
|
||||
Q_PROPERTY(TaskModel *windowModel READ windowModel WRITE setWindowModel NOTIFY windowModelChanged)
|
||||
Q_PROPERTY(QString screenName READ screenName WRITE setScreenName NOTIFY screenNameChanged)
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
explicit TaskFilterModel(QObject *parent = nullptr);
|
||||
|
|
@ -19,7 +19,13 @@ class TaskModel : public QAbstractListModel
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles { WindowRole = Qt::UserRole + 1, OutputRole, DesktopRole, ActivityRole, LastActivatedRole };
|
||||
enum Roles {
|
||||
WindowRole = Qt::UserRole + 1,
|
||||
OutputRole,
|
||||
DesktopRole,
|
||||
ActivityRole,
|
||||
LastActivatedRole
|
||||
};
|
||||
|
||||
explicit TaskModel(QObject *parent = nullptr);
|
||||
|
||||
Loading…
Reference in a new issue