mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
add double tap to switch between 2 most recent apps in swicher
also simplified openApp signature and fixed a typo in code FEATURE: 486555
This commit is contained in:
parent
d7ae1917af
commit
16192c5f71
5 changed files with 50 additions and 12 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
// SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||||
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
||||||
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@server23.cc>
|
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@kdemail.net>
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "mobiletaskswitchereffect.h"
|
#include "mobiletaskswitchereffect.h"
|
||||||
|
|
@ -20,6 +20,7 @@ namespace KWin
|
||||||
|
|
||||||
MobileTaskSwitcherState::MobileTaskSwitcherState(EffectTouchBorderState *effectState)
|
MobileTaskSwitcherState::MobileTaskSwitcherState(EffectTouchBorderState *effectState)
|
||||||
: m_effectState{effectState}
|
: m_effectState{effectState}
|
||||||
|
, m_doubleClickTimer{new QElapsedTimer{}}
|
||||||
{
|
{
|
||||||
connect(m_effectState, &EffectTouchBorderState::inProgressChanged, this, &MobileTaskSwitcherState::gestureInProgressChanged);
|
connect(m_effectState, &EffectTouchBorderState::inProgressChanged, this, &MobileTaskSwitcherState::gestureInProgressChanged);
|
||||||
}
|
}
|
||||||
|
|
@ -150,6 +151,11 @@ void MobileTaskSwitcherState::setInitialTaskIndex(int newTaskIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MobileTaskSwitcherState::restartDoubleClickTimer()
|
||||||
|
{
|
||||||
|
m_doubleClickTimer->restart();
|
||||||
|
}
|
||||||
|
|
||||||
void MobileTaskSwitcherState::calculateFilteredVelocity(qreal primaryDelta, qreal orthogonalDelta)
|
void MobileTaskSwitcherState::calculateFilteredVelocity(qreal primaryDelta, qreal orthogonalDelta)
|
||||||
{
|
{
|
||||||
static qreal prevPrimaryDelta = 0;
|
static qreal prevPrimaryDelta = 0;
|
||||||
|
|
@ -190,6 +196,15 @@ void MobileTaskSwitcherState::processTouchPositionChanged(qreal primaryDelta, qr
|
||||||
Q_EMIT touchPositionChanged();
|
Q_EMIT touchPositionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qint64 MobileTaskSwitcherState::getElapsedTimeSinceStart()
|
||||||
|
{
|
||||||
|
if (m_doubleClickTimer->isValid())
|
||||||
|
{
|
||||||
|
return m_doubleClickTimer->elapsed();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
MobileTaskSwitcherEffect::MobileTaskSwitcherEffect()
|
MobileTaskSwitcherEffect::MobileTaskSwitcherEffect()
|
||||||
: m_effectState{new EffectTouchBorderState(this)}
|
: m_effectState{new EffectTouchBorderState(this)}
|
||||||
, m_taskSwitcherState{new MobileTaskSwitcherState(m_effectState)}
|
, m_taskSwitcherState{new MobileTaskSwitcherState(m_effectState)}
|
||||||
|
|
@ -269,6 +284,7 @@ void MobileTaskSwitcherEffect::grabbedKeyboardEvent(QKeyEvent *keyEvent)
|
||||||
void MobileTaskSwitcherEffect::toggle()
|
void MobileTaskSwitcherEffect::toggle()
|
||||||
{
|
{
|
||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
|
m_taskSwitcherState->restartDoubleClickTimer();
|
||||||
activate();
|
activate();
|
||||||
} else {
|
} else {
|
||||||
deactivate(false);
|
deactivate(false);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
// SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||||
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
|
||||||
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@server23.cc>
|
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@kdemail.net>
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
@ -48,6 +48,9 @@ class MobileTaskSwitcherState : public QObject
|
||||||
Q_PROPERTY(bool gestureInProgress READ gestureInProgress NOTIFY gestureInProgressChanged)
|
Q_PROPERTY(bool gestureInProgress READ gestureInProgress NOTIFY gestureInProgressChanged)
|
||||||
Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged)
|
Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(qint64 elapsedTimeSinceStart READ getElapsedTimeSinceStart)
|
||||||
|
Q_PROPERTY(qint64 doubleClickInterval READ getDoubleClickInterval) // is there a better way than to forward this?
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class Status {
|
enum class Status {
|
||||||
// TODO! I could (should?) re-add the activating and deactivating states again to match EffectTogglableState. could help with/tie into
|
// TODO! I could (should?) re-add the activating and deactivating states again to match EffectTogglableState. could help with/tie into
|
||||||
|
|
@ -97,6 +100,8 @@ public:
|
||||||
return m_initialTaskIndex;
|
return m_initialTaskIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void restartDoubleClickTimer();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void processTouchPositionChanged(qreal primaryPosition, qreal orthogonalPosition);
|
void processTouchPositionChanged(qreal primaryPosition, qreal orthogonalPosition);
|
||||||
|
|
||||||
|
|
@ -130,6 +135,7 @@ private:
|
||||||
|
|
||||||
void clearVelocityFilter();
|
void clearVelocityFilter();
|
||||||
void calculateFilteredVelocity(qreal primaryPosition, qreal orthogonalPosition);
|
void calculateFilteredVelocity(qreal primaryPosition, qreal orthogonalPosition);
|
||||||
|
qint64 getElapsedTimeSinceStart();
|
||||||
|
|
||||||
// velocities in (logical) pixels/msec
|
// velocities in (logical) pixels/msec
|
||||||
QElapsedTimer m_frameTimer;
|
QElapsedTimer m_frameTimer;
|
||||||
|
|
@ -149,6 +155,12 @@ private:
|
||||||
qreal m_yPosition = 0;
|
qreal m_yPosition = 0;
|
||||||
|
|
||||||
bool m_wasInActiveTask;
|
bool m_wasInActiveTask;
|
||||||
|
|
||||||
|
QElapsedTimer *m_doubleClickTimer;
|
||||||
|
qint64 getDoubleClickInterval() const
|
||||||
|
{
|
||||||
|
return qApp->doubleClickInterval();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MobileTaskSwitcherEffect : public QuickSceneEffect
|
class MobileTaskSwitcherEffect : public QuickSceneEffect
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
// SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||||
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
|
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
|
||||||
|
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@kdemail.net>
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
@ -48,7 +49,7 @@ Item {
|
||||||
if (!ShellSettings.Settings.convergenceModeEnabled) {
|
if (!ShellSettings.Settings.convergenceModeEnabled) {
|
||||||
delegate.window.setMaximize(true, true);
|
delegate.window.setMaximize(true, true);
|
||||||
}
|
}
|
||||||
taskSwitcherHelpers.openApp(model.index, delegate.window);
|
taskSwitcherHelpers.openApp(model.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
function minimizeApp() {
|
function minimizeApp() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
// SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||||
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
// SPDX-FileCopyrightText: 2021-2024 Devin Lin <devin@kde.org>
|
||||||
|
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@kdemail.net>
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
@ -37,6 +38,7 @@ FocusScope {
|
||||||
property var taskSwitcherHelpers: TaskSwitcherHelpers {
|
property var taskSwitcherHelpers: TaskSwitcherHelpers {
|
||||||
taskSwitcher: root
|
taskSwitcher: root
|
||||||
stateClass: TaskSwitcherData.TaskSwitcherState
|
stateClass: TaskSwitcherData.TaskSwitcherState
|
||||||
|
taskList: taskList
|
||||||
}
|
}
|
||||||
|
|
||||||
MobileShell.HapticsEffect {
|
MobileShell.HapticsEffect {
|
||||||
|
|
@ -308,8 +310,7 @@ FocusScope {
|
||||||
// if accidentally invoked, but can also be used to switch to an adjacent app and then open it
|
// if accidentally invoked, but can also be used to switch to an adjacent app and then open it
|
||||||
function returnToApp() {
|
function returnToApp() {
|
||||||
let newIndex = taskSwitcherHelpers.getNearestTaskIndex();
|
let newIndex = taskSwitcherHelpers.getNearestTaskIndex();
|
||||||
let appAtNewIndex = taskList.getTaskAt(newIndex).window;
|
taskSwitcherHelpers.openApp(newIndex);
|
||||||
taskSwitcherHelpers.openApp(newIndex, appAtNewIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// diagonal quick switch gesture logic
|
// diagonal quick switch gesture logic
|
||||||
|
|
@ -338,15 +339,14 @@ FocusScope {
|
||||||
} else {
|
} else {
|
||||||
// flick to the left on the home screen, dismiss the gesture
|
// flick to the left on the home screen, dismiss the gesture
|
||||||
taskSwitcherHelpers.close();
|
taskSwitcherHelpers.close();
|
||||||
retrun;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldSwitch) {
|
if (shouldSwitch) {
|
||||||
if (!taskSwitcherHelpers.taskDrawerOpened && unmodifiedYposition < taskSwitcherHelpers.openedYPosition) {
|
if (!taskSwitcherHelpers.taskDrawerOpened && unmodifiedYposition < taskSwitcherHelpers.openedYPosition) {
|
||||||
// if in a app, switch it to the new task when it is under the openedYPosition
|
// if in a app, switch it to the new task when it is under the openedYPosition
|
||||||
taskList.setTaskOffsetValue(0, unmodifiedYposition < taskSwitcherHelpers.openedYPosition && taskSwitcherHelpers.notHomeScreenState);
|
taskList.setTaskOffsetValue(0, unmodifiedYposition < taskSwitcherHelpers.openedYPosition && taskSwitcherHelpers.notHomeScreenState);
|
||||||
let appAtNewIndex = taskList.getTaskAt(newIndex).window;
|
taskSwitcherHelpers.openApp(newIndex, Kirigami.Units.longDuration * 4, Easing.OutExpo);
|
||||||
taskSwitcherHelpers.openApp(newIndex, appAtNewIndex, Kirigami.Units.longDuration * 4, Easing.OutExpo);
|
|
||||||
} else {
|
} else {
|
||||||
// if already in the task switcher or above the openedYPosition, only change the focus to the new task
|
// if already in the task switcher or above the openedYPosition, only change the focus to the new task
|
||||||
taskSwitcherHelpers.animateGoToTaskIndex(newIndex);
|
taskSwitcherHelpers.animateGoToTaskIndex(newIndex);
|
||||||
|
|
@ -380,7 +380,7 @@ FocusScope {
|
||||||
taskSwitcherHelpers.open();
|
taskSwitcherHelpers.open();
|
||||||
taskSwitcherHelpers.isInTaskScrubMode = false;
|
taskSwitcherHelpers.isInTaskScrubMode = false;
|
||||||
} else {
|
} else {
|
||||||
taskSwitcherHelpers.openApp(state.currentTaskIndex, taskList.getTaskAt(state.currentTaskIndex).window);
|
taskSwitcherHelpers.openApp(state.currentTaskIndex);
|
||||||
}
|
}
|
||||||
} else if (taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.Undecided) {
|
} else if (taskSwitcherHelpers.gestureState == TaskSwitcherHelpers.GestureStates.Undecided) {
|
||||||
if (taskSwitcherHelpers.taskDrawerOpened) {
|
if (taskSwitcherHelpers.taskDrawerOpened) {
|
||||||
|
|
@ -499,8 +499,15 @@ FocusScope {
|
||||||
if (taskList.count === 0) {
|
if (taskList.count === 0) {
|
||||||
root.hide();
|
root.hide();
|
||||||
} else {
|
} else {
|
||||||
|
if (taskList.count > 1 &&
|
||||||
|
state.elapsedTimeSinceStart != -1 &&
|
||||||
|
state.elapsedTimeSinceStart < state.doubleClickInterval) {
|
||||||
|
taskSwitcherHelpers.openApp(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const currentIndex = state.currentTaskIndex;
|
const currentIndex = state.currentTaskIndex;
|
||||||
taskSwitcherHelpers.openApp(state.currentTaskIndex, taskList.getTaskAt(currentIndex).window);
|
taskSwitcherHelpers.openApp(state.currentTaskIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
// SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||||
|
// SPDX-FileCopyrightText: 2024 Luis Büchi <luis.buechi@kdemail.net>
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import QtQuick 2.15
|
import QtQuick 2.15
|
||||||
|
|
@ -19,6 +20,7 @@ QtObject {
|
||||||
required property var taskSwitcher
|
required property var taskSwitcher
|
||||||
property var state: taskSwitcher.state
|
property var state: taskSwitcher.state
|
||||||
required property var stateClass
|
required property var stateClass
|
||||||
|
required property var taskList
|
||||||
|
|
||||||
// task switcher peek and pop setting for when it is toggled from the home screen
|
// task switcher peek and pop setting for when it is toggled from the home screen
|
||||||
readonly property real peekOffsetValue: 1.85
|
readonly property real peekOffsetValue: 1.85
|
||||||
|
|
@ -217,14 +219,14 @@ QtObject {
|
||||||
closeFactorAnim.restart();
|
closeFactorAnim.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function openApp(index, window, duration = Kirigami.Units.shortDuration, horizontalEasing = Easing.OutBack) {
|
function openApp(index, duration = Kirigami.Units.shortDuration, horizontalEasing = Easing.OutBack) {
|
||||||
// cancel any opening animations ongoing
|
// cancel any opening animations ongoing
|
||||||
openAnim.stop();
|
openAnim.stop();
|
||||||
cancelAnimations();
|
cancelAnimations();
|
||||||
|
|
||||||
animateGoToTaskIndex(index, duration);
|
animateGoToTaskIndex(index, duration);
|
||||||
openAppAnim.restart();
|
openAppAnim.restart();
|
||||||
KWinComponents.Workspace.activeWindow = window
|
KWinComponents.Workspace.activeWindow = taskList.getTaskAt(index).window;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the xPosition where the task will be centered on the screen
|
// get the xPosition where the task will be centered on the screen
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue