mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
taskswitcher: Port to kwin effect
This commit is contained in:
parent
f87c7c5526
commit
eb03fe8c94
27 changed files with 912 additions and 675 deletions
|
|
@ -14,7 +14,7 @@ set(QT_MIN_VERSION "6.4.0")
|
|||
set(KF6_MIN_VERSION "5.240.0")
|
||||
set(KDE_COMPILERSETTINGS_LEVEL "5.82")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(ECM ${KF6_MIN_VERSION} REQUIRED NO_MODULE)
|
||||
|
|
@ -53,6 +53,7 @@ find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} CONFIG REQUIRED
|
|||
|
||||
find_package(KF6 ${KF6_MIN_VERSION} REQUIRED COMPONENTS
|
||||
I18n
|
||||
GlobalAccel
|
||||
KIO
|
||||
Config
|
||||
DBusAddons
|
||||
|
|
@ -74,6 +75,12 @@ pkg_check_modules(GOBJECT gobject-2.0 REQUIRED IMPORTED_TARGET)
|
|||
pkg_check_modules(GIO gio-2.0 REQUIRED IMPORTED_TARGET)
|
||||
|
||||
find_package(KF6KirigamiAddons 0.6 REQUIRED)
|
||||
find_package(epoxy REQUIRED)
|
||||
find_package(XCB REQUIRED COMPONENTS XCB)
|
||||
find_package(KWinEffects 5.27.0 REQUIRED COMPONENTS
|
||||
kwineffects
|
||||
)
|
||||
|
||||
find_package(LibKWorkspace CONFIG REQUIRED)
|
||||
|
||||
find_package(KWinDBusInterface)
|
||||
|
|
|
|||
|
|
@ -95,9 +95,6 @@ void MobileShellPlugin::registerTypes(const char *uri)
|
|||
// /statusbar
|
||||
qmlRegisterType(resolvePath("statusbar/StatusBar.qml"), uri, 1, 0, "StatusBar");
|
||||
|
||||
// /taskswitcher
|
||||
qmlRegisterType(resolvePath("taskswitcher/TaskSwitcher.qml"), uri, 1, 0, "TaskSwitcher");
|
||||
|
||||
// /widgets
|
||||
qmlRegisterType(resolvePath("widgets/krunner/KRunnerWidget.qml"), uri, 1, 0, "KRunnerWidget");
|
||||
qmlRegisterType(resolvePath("widgets/mediacontrols/MediaControlsWidget.qml"), uri, 1, 0, "MediaControlsWidget");
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ MouseArea { // use mousearea to ensure clicks don't go behind
|
|||
}
|
||||
|
||||
background.state = "open";
|
||||
|
||||
MobileShellState.HomeScreenControls.taskSwitcher.minimizeAll();
|
||||
}
|
||||
|
||||
function close() {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ Item {
|
|||
* Whether a component is being shown on top of the homescreen within the same
|
||||
* window.
|
||||
*/
|
||||
readonly property bool overlayShown: taskSwitcher.visible || startupFeedback.visible
|
||||
readonly property bool overlayShown: startupFeedback.visible
|
||||
|
||||
/**
|
||||
* Margins for the homescreen, taking panels into account.
|
||||
|
|
@ -82,8 +82,9 @@ Item {
|
|||
}
|
||||
|
||||
MobileShellState.HomeScreenControls.resetHomeScreenPosition();
|
||||
taskSwitcher.visible = false; // will trigger homescreen open
|
||||
taskSwitcher.minimizeAll();
|
||||
|
||||
MobileShell.WindowUtil.unsetAllMinimizedGeometries(root);
|
||||
MobileShell.WindowUtil.minimizeAll();
|
||||
|
||||
root.homeTriggered();
|
||||
}
|
||||
|
|
@ -109,7 +110,6 @@ Item {
|
|||
|
||||
Plasmoid.onScreenChanged: {
|
||||
if (plasmoid.screen == 0) {
|
||||
MobileShellState.HomeScreenControls.taskSwitcher = taskSwitcher;
|
||||
MobileShellState.HomeScreenControls.homeScreenWindow = root.Window.window;
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +127,6 @@ Item {
|
|||
|
||||
// set API variables
|
||||
if (plasmoid.screen == 0) {
|
||||
MobileShellState.HomeScreenControls.taskSwitcher = taskSwitcher;
|
||||
MobileShellState.HomeScreenControls.homeScreenWindow = root.Window.window;
|
||||
}
|
||||
}
|
||||
|
|
@ -203,14 +202,12 @@ Item {
|
|||
|
||||
function evaluateAnimChange() {
|
||||
// only animate if homescreen is visible
|
||||
if (!taskSwitcher.visible) {
|
||||
if (!visibleMaximizedWindowsModel.isWindowMaximized || MobileShell.WindowUtil.activeWindowIsShell) {
|
||||
itemContainer.zoomIn();
|
||||
} else {
|
||||
itemContainer.zoomOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: MobileShell.WindowUtil
|
||||
|
|
@ -234,45 +231,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// task switcher component
|
||||
MobileShell.TaskSwitcher {
|
||||
id: taskSwitcher
|
||||
z: 999999
|
||||
|
||||
topMargin: root.topMargin
|
||||
bottomMargin: root.bottomMargin
|
||||
leftMargin: root.leftMargin
|
||||
rightMargin: root.rightMargin
|
||||
|
||||
tasksModel: TaskManager.TasksModel {
|
||||
groupMode: TaskManager.TasksModel.GroupDisabled
|
||||
|
||||
screenGeometry: plasmoid.screenGeometry
|
||||
sortMode: TaskManager.TasksModel.SortLastActivated
|
||||
|
||||
virtualDesktop: virtualDesktopInfo.currentDesktop
|
||||
activity: activityInfo.currentActivity
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
// hide homescreen elements to make use of wallpaper
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
startupFeedback.visible = false;
|
||||
|
||||
// hide immediately when going from homescreen
|
||||
if (!taskSwitcher.wasInActiveTask) {
|
||||
itemContainer.opacity = 0;
|
||||
}
|
||||
itemContainer.zoomOut();
|
||||
|
||||
} else {
|
||||
itemContainer.zoomIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// start app animation component
|
||||
MobileShell.StartupFeedback {
|
||||
id: startupFeedback
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
implicitWidth: PlasmaCore.Units.iconSizes.enormous
|
||||
implicitHeight: PlasmaCore.Units.iconSizes.enormous
|
||||
usesPlasmaTheme: false
|
||||
source: model.decoration
|
||||
}
|
||||
|
|
@ -1,283 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2021-2022 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.15
|
||||
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
import org.kde.plasma.core 2.1 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
|
||||
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
|
||||
|
||||
import "../components" as Components
|
||||
|
||||
/**
|
||||
* Component that provides a task switcher.
|
||||
*/
|
||||
Item {
|
||||
id: root
|
||||
visible: false
|
||||
opacity: 0
|
||||
|
||||
/**
|
||||
* Margins for the content (taking shell panels into account).
|
||||
*/
|
||||
required property real topMargin
|
||||
required property real bottomMargin
|
||||
required property real leftMargin
|
||||
required property real rightMargin
|
||||
|
||||
// state object
|
||||
property var taskSwitcherState: TaskSwitcherState {
|
||||
taskSwitcher: root
|
||||
}
|
||||
|
||||
/**
|
||||
* The task manager model to use for the tasks switcher.
|
||||
*/
|
||||
property TaskManager.TasksModel tasksModel
|
||||
|
||||
/**
|
||||
* The number of tasks in the given task manager model.
|
||||
*/
|
||||
readonly property int tasksCount: tasksModel.count
|
||||
|
||||
/**
|
||||
* The screen model to be used for moving windows between screens.
|
||||
*/
|
||||
property var displaysModel: MobileShell.DisplaysModel {}
|
||||
|
||||
/**
|
||||
* Whether the window is active.
|
||||
*/
|
||||
property bool windowActive: Window.active
|
||||
onWindowActiveChanged: {
|
||||
// if a window has popped up in front, close the task switcher
|
||||
if (visible && !windowActive) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
// update API property
|
||||
onVisibleChanged: MobileShellState.HomeScreenControls.taskSwitcherVisible = visible;
|
||||
|
||||
// keep track of task list events
|
||||
property int oldTasksCount: tasksCount
|
||||
onTasksCountChanged: {
|
||||
if (tasksCount == 0) {
|
||||
hide();
|
||||
} else if (tasksCount < oldTasksCount && taskSwitcherState.currentTaskIndex >= tasksCount - 1) {
|
||||
// if the user is on the last task, and it is closed, scroll left
|
||||
taskSwitcherState.animateGoToTaskIndex(tasksCount - 1, PlasmaCore.Units.longDuration);
|
||||
}
|
||||
|
||||
oldTasksCount = tasksCount;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: reorderTimer
|
||||
|
||||
interval: 5000
|
||||
|
||||
onTriggered: tasksModel.taskReorderingEnabled = true
|
||||
}
|
||||
|
||||
//BEGIN functions
|
||||
|
||||
function show(animation) {
|
||||
// reset values
|
||||
taskSwitcherState.cancelAnimations();
|
||||
taskSwitcherState.yPosition = 0;
|
||||
taskSwitcherState.xPosition = 0;
|
||||
taskSwitcherState.wasInActiveTask = tasksModel.activeTask.row >= 0;
|
||||
taskSwitcherState.currentlyBeingOpened = true;
|
||||
|
||||
reorderTimer.stop();
|
||||
tasksModel.taskReorderingEnabled = false;
|
||||
|
||||
// skip to first active task
|
||||
if (taskSwitcherState.wasInActiveTask) {
|
||||
taskSwitcherState.goToTaskIndex(tasksModel.activeTask.row);
|
||||
} else {
|
||||
taskSwitcherState.goToTaskIndex(0);
|
||||
}
|
||||
|
||||
// show task switcher, hide all running apps
|
||||
visible = true;
|
||||
opacity = 1;
|
||||
minimizeAll();
|
||||
|
||||
// fully open the panel (if this is a button press, not gesture)
|
||||
if (animation) {
|
||||
taskSwitcherState.open();
|
||||
}
|
||||
}
|
||||
|
||||
function instantHide() {
|
||||
opacity = 0;
|
||||
visible = false;
|
||||
closeAllButton.closeRequested = false;
|
||||
}
|
||||
|
||||
function hide() {
|
||||
closeAnim.restart();
|
||||
}
|
||||
|
||||
// scroll to delegate index, and activate it
|
||||
function activateWindow(id) {
|
||||
taskSwitcherState.openApp(id);
|
||||
}
|
||||
|
||||
function setSingleActiveWindow(id) {
|
||||
if (id < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var newActiveIdx = tasksModel.index(id, 0)
|
||||
var newActiveGeo = tasksModel.data(newActiveIdx, TaskManager.AbstractTasksModel.ScreenGeometry)
|
||||
for (var i = 0 ; i < tasksModel.count; i++) {
|
||||
var idx = tasksModel.index(i, 0)
|
||||
if (i == id) {
|
||||
tasksModel.requestActivate(idx);
|
||||
// ensure the window is in maximized state
|
||||
if (!tasksModel.data(idx, TaskManager.AbstractTasksModel.IsMaximized)) {
|
||||
tasksModel.requestToggleMaximized(idx);
|
||||
}
|
||||
} else if (!tasksModel.data(idx, TaskManager.AbstractTasksModel.IsMinimized)) {
|
||||
var geo = tasksModel.data(idx, TaskManager.AbstractTasksModel.ScreenGeometry)
|
||||
// only minimize the other windows in the same screen
|
||||
if (geo === newActiveGeo) {
|
||||
tasksModel.requestToggleMinimized(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instantHide();
|
||||
|
||||
if (taskSwitcherState.wasInActiveTask) {
|
||||
reorderTimer.restart();
|
||||
} else {
|
||||
tasksModel.taskReorderingEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function minimizeAll() {
|
||||
MobileShell.WindowUtil.unsetAllMinimizedGeometries(root);
|
||||
MobileShell.WindowUtil.minimizeAll();
|
||||
}
|
||||
|
||||
//END functions
|
||||
|
||||
NumberAnimation on opacity {
|
||||
id: closeAnim
|
||||
to: 0
|
||||
duration: PlasmaCore.Units.shortDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
|
||||
onFinished: {
|
||||
root.visible = false;
|
||||
tasksModel.taskReorderingEnabled = true;
|
||||
closeAllButton.closeRequested = false;
|
||||
}
|
||||
}
|
||||
|
||||
// background colour
|
||||
Rectangle {
|
||||
id: backgroundRect
|
||||
anchors.fill: parent
|
||||
|
||||
color: {
|
||||
// animate background colour only if we are *not* opening from the homescreen
|
||||
if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) {
|
||||
return Qt.rgba(0, 0, 0, 0.6);
|
||||
} else {
|
||||
return Qt.rgba(0, 0, 0, 0.6 * Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: container
|
||||
|
||||
// provide shell margins
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: root.leftMargin
|
||||
anchors.rightMargin: root.rightMargin
|
||||
anchors.bottomMargin: root.bottomMargin
|
||||
anchors.topMargin: root.topMargin
|
||||
|
||||
FlickContainer {
|
||||
id: flickable
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
taskSwitcherState: root.taskSwitcherState
|
||||
|
||||
// the item is effectively anchored to the flickable bounds
|
||||
TaskList {
|
||||
id: taskList
|
||||
shellTopMargin: root.topMargin
|
||||
shellBottomMargin: root.bottomMargin
|
||||
|
||||
taskSwitcher: root
|
||||
|
||||
opacity: {
|
||||
// animate opacity only if we are *not* opening from the homescreen
|
||||
if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) {
|
||||
return 1;
|
||||
} else {
|
||||
Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition);
|
||||
}
|
||||
}
|
||||
|
||||
x: flickable.contentX
|
||||
width: flickable.width
|
||||
height: flickable.height
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
id: closeAllButton
|
||||
|
||||
property bool closeRequested: false
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: taskList.taskY / 2
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
PlasmaCore.ColorScope.colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||
PlasmaCore.ColorScope.inherit: false
|
||||
|
||||
opacity: taskSwitcherState.currentlyBeingOpened || taskSwitcherState.currentlyBeingClosed || !root.visible ? 0.0 : 1.0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: PlasmaCore.Units.shortDuration
|
||||
}
|
||||
}
|
||||
|
||||
icon.name: "edit-clear-history"
|
||||
font.bold: true
|
||||
|
||||
text: closeRequested ? "Confirm Close All" : "Close All"
|
||||
|
||||
onClicked: {
|
||||
if (closeRequested) {
|
||||
taskList.closeAll();
|
||||
} else {
|
||||
closeRequested = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Marco Martin <notmart@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.2
|
||||
|
||||
import org.kde.pipewire 0.1 as PipeWire
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
|
||||
PipeWire.PipeWireSourceItem {
|
||||
id: root
|
||||
visible: nodeId > 0
|
||||
nodeId: waylandItem.nodeId
|
||||
|
||||
readonly property alias uuid: waylandItem.uuid
|
||||
|
||||
function refresh() {
|
||||
if (model.WinIdList) {
|
||||
waylandItem.uuid = model.WinIdList[0];
|
||||
}
|
||||
}
|
||||
|
||||
TaskManager.ScreencastingRequest {
|
||||
id: waylandItem
|
||||
uuid: ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -63,14 +63,6 @@
|
|||
<file>qml/statusbar/StatusBar.qml</file>
|
||||
<file>qml/statusbar/TaskWidget.qml</file>
|
||||
|
||||
<file>qml/taskswitcher/FlickContainer.qml</file>
|
||||
<file>qml/taskswitcher/Task.qml</file>
|
||||
<file>qml/taskswitcher/TaskIcon.qml</file>
|
||||
<file>qml/taskswitcher/TaskList.qml</file>
|
||||
<file>qml/taskswitcher/TaskSwitcher.qml</file>
|
||||
<file>qml/taskswitcher/TaskSwitcherState.qml</file>
|
||||
<file>qml/taskswitcher/Thumbnail.qml</file>
|
||||
|
||||
<file>qml/widgets/krunner/KRunnerWidget.qml</file>
|
||||
|
||||
<file>qml/widgets/mediacontrols/BlurredBackground.qml</file>
|
||||
|
|
|
|||
|
|
@ -12,11 +12,6 @@ pragma Singleton
|
|||
QtObject {
|
||||
id: delegate
|
||||
|
||||
/**
|
||||
* Whether the task switcher is open.
|
||||
*/
|
||||
readonly property bool taskSwitcherVisible: HomeScreenControls.taskSwitcherVisible
|
||||
|
||||
/**
|
||||
* Whether the homescreen is currently visible.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -52,11 +52,7 @@ ContainmentLayoutManager.ItemContainer {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!MobileShellState.Shell.taskSwitcherVisible) {
|
||||
desktopModel.setMinimizedDelegate(index, delegate);
|
||||
} else {
|
||||
desktopModel.unsetMinimizedDelegate(index, delegate);
|
||||
}
|
||||
}
|
||||
|
||||
function launchApp() {
|
||||
|
|
|
|||
|
|
@ -37,11 +37,9 @@ Item {
|
|||
}
|
||||
|
||||
function openConfigure() {
|
||||
if (!MobileShellState.Shell.taskSwitcherVisible) {
|
||||
plasmoid.action("configure").trigger();
|
||||
plasmoid.editMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: MobileShellState.HomeScreenControls
|
||||
|
|
|
|||
|
|
@ -48,7 +48,12 @@ MobileShell.HomeScreen {
|
|||
if (!MobileShell.WindowUtil.showDesktop && !MobileShellState.Shell.homeScreenVisible
|
||||
|| search.isOpen
|
||||
) {
|
||||
// Always close the search widget
|
||||
// Always close action drawer
|
||||
if (MobileShellState.Shell.actionDrawerVisible) {
|
||||
MobileShellState.Shell.closeActionDrawer();
|
||||
}
|
||||
|
||||
// Always close the search widget as well
|
||||
if (search.isOpen) {
|
||||
search.close();
|
||||
}
|
||||
|
|
@ -90,14 +95,6 @@ MobileShell.HomeScreen {
|
|||
bottomMargin: root.bottomMargin
|
||||
leftMargin: root.leftMargin
|
||||
rightMargin: root.rightMargin
|
||||
|
||||
// close search component when task switcher is shown or hidden
|
||||
Connections {
|
||||
target: MobileShellState.HomeScreenControls.taskSwitcher
|
||||
function onVisibleChanged() {
|
||||
search.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick 2.4
|
||||
import QtQuick.Layouts 1.1
|
||||
|
|
@ -14,6 +11,7 @@ import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards
|
|||
|
||||
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
|
||||
MobileShell.NavigationPanel {
|
||||
id: root
|
||||
|
|
@ -23,19 +21,35 @@ MobileShell.NavigationPanel {
|
|||
// - opaque if an app is shown or vkbd is shown
|
||||
// - translucent if the task switcher is open
|
||||
// - transparent if on the homescreen
|
||||
backgroundColor: {
|
||||
if (root.taskSwitcher.visible) {
|
||||
return Qt.rgba(0, 0, 0, 0.1);
|
||||
} else {
|
||||
return (Keyboards.KWinVirtualKeyboard.visible || opaqueBar) ? PlasmaCore.ColorScope.backgroundColor : "transparent";
|
||||
}
|
||||
}
|
||||
foregroundColorGroup: (!root.taskSwitcher.visible && opaqueBar) ? PlasmaCore.Theme.NormalColorGroup : PlasmaCore.Theme.ComplementaryColorGroup
|
||||
backgroundColor: (Keyboards.KWinVirtualKeyboard.visible || opaqueBar) ? PlasmaCore.ColorScope.backgroundColor : "transparent";
|
||||
foregroundColorGroup: opaqueBar ? PlasmaCore.Theme.NormalColorGroup : PlasmaCore.Theme.ComplementaryColorGroup
|
||||
shadow: !opaqueBar
|
||||
|
||||
// do not enable drag gesture when task switcher is already open
|
||||
// also don't disable drag gesture mid-drag
|
||||
dragGestureEnabled: !root.taskSwitcher.visible || root.taskSwitcher.taskSwitcherState.currentlyBeingOpened
|
||||
dragGestureEnabled: false // !root.taskSwitcher.visible || root.taskSwitcher.taskSwitcherState.currentlyBeingOpened
|
||||
|
||||
TaskManager.VirtualDesktopInfo {
|
||||
id: virtualDesktopInfo
|
||||
}
|
||||
|
||||
TaskManager.ActivityInfo {
|
||||
id: activityInfo
|
||||
}
|
||||
|
||||
TaskManager.TasksModel {
|
||||
id: tasksModel
|
||||
filterByVirtualDesktop: true
|
||||
filterByActivity: true
|
||||
filterNotMaximized: true
|
||||
filterByScreen: true
|
||||
filterHidden: true
|
||||
|
||||
virtualDesktop: virtualDesktopInfo.currentDesktop
|
||||
activity: activityInfo.currentActivity
|
||||
|
||||
groupMode: TaskManager.TasksModel.GroupDisabled
|
||||
}
|
||||
|
||||
// ~~~~
|
||||
// navigation panel actions
|
||||
|
|
@ -44,24 +58,12 @@ MobileShell.NavigationPanel {
|
|||
leftAction: MobileShell.NavigationPanelAction {
|
||||
id: taskSwitcherAction
|
||||
|
||||
enabled: (root.taskSwitcher.tasksCount > 0) || root.taskSwitcher.visible
|
||||
enabled: true
|
||||
iconSource: "mobile-task-switcher"
|
||||
iconSizeFactor: 0.75
|
||||
|
||||
onTriggered: {
|
||||
MobileShell.WindowUtil.showDesktop = false;
|
||||
|
||||
if (!root.taskSwitcher.visible) {
|
||||
root.taskSwitcher.show(true);
|
||||
} else {
|
||||
// when task switcher is open
|
||||
if (root.taskSwitcher.taskSwitcherState.wasInActiveTask) {
|
||||
// restore active window
|
||||
root.taskSwitcher.activateWindow(taskSwitcher.taskSwitcherState.currentTaskIndex);
|
||||
} else {
|
||||
root.taskSwitcher.hide();
|
||||
}
|
||||
}
|
||||
plasmoid.nativeInterface.triggerTaskSwitcher();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +85,7 @@ MobileShell.NavigationPanel {
|
|||
rightAction: MobileShell.NavigationPanelAction {
|
||||
id: closeAppAction
|
||||
|
||||
enabled: Keyboards.KWinVirtualKeyboard.visible || root.taskSwitcher.visible || MobileShell.WindowUtil.hasCloseableActiveWindow
|
||||
enabled: Keyboards.KWinVirtualKeyboard.visible || MobileShell.WindowUtil.hasCloseableActiveWindow
|
||||
iconSource: Keyboards.KWinVirtualKeyboard.visible ? "go-down-symbolic" : "mobile-close-app"
|
||||
// mobile-close-app (from plasma-frameworks) seems to have less margins than icons from breeze-icons
|
||||
iconSizeFactor: Keyboards.KWinVirtualKeyboard.visible ? 1 : 0.75
|
||||
|
|
@ -92,15 +94,10 @@ MobileShell.NavigationPanel {
|
|||
if (Keyboards.KWinVirtualKeyboard.active) {
|
||||
// close keyboard if it is open
|
||||
Keyboards.KWinVirtualKeyboard.active = false;
|
||||
} else if (taskSwitcher.visible) {
|
||||
// if task switcher is open, close the current window shown
|
||||
let indexToClose = root.taskSwitcher.tasksModel.index(root.taskSwitcher.currentTaskIndex, 0);
|
||||
root.taskSwitcher.tasksModel.requestClose(indexToClose);
|
||||
|
||||
} else if (MobileShell.WindowUtil.hasCloseableActiveWindow) {
|
||||
// if task switcher is closed, but there is an active window
|
||||
if (root.taskSwitcher.tasksModel.activeTask !== 0) {
|
||||
root.taskSwitcher.tasksModel.requestClose(root.taskSwitcher.tasksModel.activeTask);
|
||||
if (tasksModel.activeTask !== 0) {
|
||||
tasksModel.requestClose(tasksModel.activeTask);
|
||||
}
|
||||
MobileShellState.Shell.closeAppLaunchAnimation();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,6 @@ PlasmaCore.ColorScope {
|
|||
Component {
|
||||
id: navigationPanel
|
||||
NavigationPanelComponent {
|
||||
taskSwitcher: MobileShellState.HomeScreenControls.taskSwitcher
|
||||
opaqueBar: root.opaqueBar
|
||||
}
|
||||
}
|
||||
|
|
@ -150,9 +149,7 @@ PlasmaCore.ColorScope {
|
|||
// bottom navigation gesture area component
|
||||
Component {
|
||||
id: navigationGesture
|
||||
MobileShell.NavigationGestureArea {
|
||||
taskSwitcher: MobileShellState.HomeScreenControls.taskSwitcher
|
||||
}
|
||||
MobileShell.NavigationGestureArea {}
|
||||
}
|
||||
|
||||
// load appropriate system navigation component
|
||||
|
|
|
|||
|
|
@ -120,6 +120,15 @@ void TaskPanel::updatePanelVisibility()
|
|||
}
|
||||
}
|
||||
|
||||
void TaskPanel::triggerTaskSwitcher() const
|
||||
{
|
||||
QDBusMessage message = QDBusMessage::createMethodCall("org.kde.kglobalaccel", "/component/kwin", "org.kde.kglobalaccel.Component", "invokeShortcut");
|
||||
message.setArguments({QStringLiteral("Mobile Task Switcher")});
|
||||
|
||||
// this does not block, so it won't necessarily be called before the method returns
|
||||
QDBusConnection::sessionBus().send(message);
|
||||
}
|
||||
|
||||
K_PLUGIN_CLASS_WITH_JSON(TaskPanel, "package/metadata.json")
|
||||
|
||||
#include "taskpanel.moc"
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ public:
|
|||
|
||||
QAbstractItemModel *outputs() const;
|
||||
|
||||
Q_INVOKABLE void triggerTaskSwitcher() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void panelChanged();
|
||||
void locationChanged();
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
add_subdirectory(scripts)
|
||||
add_subdirectory(mobiletaskswitcher)
|
||||
25
kwin/mobiletaskswitcher/CMakeLists.txt
Normal file
25
kwin/mobiletaskswitcher/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
kcoreaddons_add_plugin(kwin4_effect_mobiletaskswitcher INSTALL_NAMESPACE "kwin/effects/plugins")
|
||||
target_sources(kwin4_effect_mobiletaskswitcher PRIVATE
|
||||
main.cpp
|
||||
mobiletaskswitchereffect.cpp
|
||||
)
|
||||
install(FILES metadata.json DESTINATION ${KDE_INSTALL_DATADIR}/kwin/builtin-effects/kwin4_effect_mobiletaskswitcher/)
|
||||
|
||||
target_link_libraries(kwin4_effect_mobiletaskswitcher
|
||||
KF6::ConfigGui
|
||||
KF6::GlobalAccel
|
||||
KF6::I18n
|
||||
KF6::CoreAddons
|
||||
KF6::WindowSystem
|
||||
|
||||
Qt::Quick
|
||||
Qt::Core
|
||||
|
||||
KWinEffects::kwineffects
|
||||
)
|
||||
|
||||
# install(TARGETS kwin4_effect_taskswitcher DESTINATION ${PLUGIN_INSTALL_DIR}/kwin/effects/plugins)
|
||||
install(DIRECTORY qml DESTINATION ${KDE_INSTALL_DATADIR}/kwin/effects/mobiletaskswitcher)
|
||||
13
kwin/mobiletaskswitcher/main.cpp
Normal file
13
kwin/mobiletaskswitcher/main.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// 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, "metadata.json", return MobileTaskSwitcherEffect::supported();)
|
||||
|
||||
} // namespace KWin
|
||||
|
||||
#include "main.moc"
|
||||
12
kwin/mobiletaskswitcher/metadata.json
Normal file
12
kwin/mobiletaskswitcher/metadata.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"KPlugin": {
|
||||
"Category": "Window Management",
|
||||
"Description": "Allows you to switch between running tasks with a mobile interface.",
|
||||
"EnabledByDefault": true,
|
||||
"Id": "mobiletaskswitcher",
|
||||
"License": "GPL",
|
||||
"Name": "Mobile Task Switcher"
|
||||
},
|
||||
"X-KWin-Border-Activate": true
|
||||
}
|
||||
|
||||
252
kwin/mobiletaskswitcher/mobiletaskswitchereffect.cpp
Normal file
252
kwin/mobiletaskswitcher/mobiletaskswitchereffect.cpp
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
// 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"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMetaObject>
|
||||
#include <QQuickItem>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
MobileTaskSwitcherEffect::MobileTaskSwitcherEffect()
|
||||
: m_shutdownTimer(new QTimer(this))
|
||||
{
|
||||
m_shutdownTimer->setSingleShot(true);
|
||||
connect(m_shutdownTimer, &QTimer::timeout, this, &MobileTaskSwitcherEffect::realDeactivate);
|
||||
|
||||
const QKeySequence defaultToggleShortcut = Qt::META | Qt::Key_C;
|
||||
|
||||
m_toggleAction = new QAction(this);
|
||||
m_toggleAction->setObjectName(QStringLiteral("Mobile Task Switcher"));
|
||||
m_toggleAction->setText(i18n("Toggle Mobile Task Switcher"));
|
||||
|
||||
connect(m_toggleAction, &QAction::triggered, this, &MobileTaskSwitcherEffect::toggle);
|
||||
|
||||
KGlobalAccel::self()->setDefaultShortcut(m_toggleAction, {defaultToggleShortcut});
|
||||
KGlobalAccel::self()->setShortcut(m_toggleAction, {defaultToggleShortcut});
|
||||
|
||||
m_realtimeToggleAction = new QAction(this);
|
||||
connect(m_realtimeToggleAction, &QAction::triggered, this, [this]() {
|
||||
if (m_status == Status::Deactivating) {
|
||||
if (m_partialActivationFactor < 0.5) {
|
||||
deactivate(false);
|
||||
} else {
|
||||
cancelPartialDeactivate();
|
||||
}
|
||||
} else if (m_status == Status::Activating) {
|
||||
if (m_partialActivationFactor > 0.5) {
|
||||
activate();
|
||||
} else {
|
||||
cancelPartialActivate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
auto progressCallback = [this](qreal progress) {
|
||||
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == this) {
|
||||
switch (m_status) {
|
||||
case Status::Inactive:
|
||||
case Status::Activating:
|
||||
partialActivate(progress);
|
||||
break;
|
||||
case Status::Active:
|
||||
case Status::Deactivating:
|
||||
partialDeactivate(progress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
effects->registerTouchpadPinchShortcut(PinchDirection::Contracting, 4, m_realtimeToggleAction, progressCallback);
|
||||
effects->registerTouchscreenSwipeShortcut(SwipeDirection::Up, 3, m_realtimeToggleAction, progressCallback);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for (const ElectricBorder &border : std::as_const(m_touchBorderActivate)) {
|
||||
effects->unregisterTouchBorder(border, m_toggleAction);
|
||||
}
|
||||
|
||||
m_borderActivate.clear();
|
||||
m_touchBorderActivate.clear();
|
||||
|
||||
const QList<int> activateBorders = {ElectricBorder::ElectricBottom};
|
||||
for (const int &border : activateBorders) {
|
||||
m_borderActivate.append(ElectricBorder(border));
|
||||
effects->reserveElectricBorder(ElectricBorder(border), this);
|
||||
}
|
||||
|
||||
const QList<int> touchActivateBorders = {ElectricBorder::ElectricBottom};
|
||||
for (const int &border : touchActivateBorders) {
|
||||
m_touchBorderActivate.append(ElectricBorder(border));
|
||||
effects->registerRealtimeTouchBorder(ElectricBorder(border),
|
||||
m_realtimeToggleAction,
|
||||
[this](ElectricBorder border, const QPointF &deltaProgress, const EffectScreen *screen) {
|
||||
if (m_status == Status::Active) {
|
||||
return;
|
||||
}
|
||||
const int maxDelta = 500; // Arbitrary logical pixels value seems to behave better than scaledScreenSize
|
||||
if (border == ElectricTop || border == ElectricBottom) {
|
||||
partialActivate(std::min(1.0, std::abs(deltaProgress.y()) / maxDelta));
|
||||
} else {
|
||||
partialActivate(std::min(1.0, std::abs(deltaProgress.x()) / maxDelta));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int MobileTaskSwitcherEffect::requestedEffectChainPosition() const
|
||||
{
|
||||
return 70;
|
||||
}
|
||||
|
||||
bool MobileTaskSwitcherEffect::borderActivated(ElectricBorder border)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
m_status = Status::Active;
|
||||
setRunning(true);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
setGestureInProgress(false);
|
||||
setPartialActivationFactor(0.0);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::partialActivate(qreal factor)
|
||||
{
|
||||
if (effects->isScreenLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_status = Status::Activating;
|
||||
|
||||
setPartialActivationFactor(factor);
|
||||
setGestureInProgress(true);
|
||||
|
||||
setRunning(true);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::partialDeactivate(qreal factor)
|
||||
{
|
||||
m_status = Status::Deactivating;
|
||||
|
||||
setPartialActivationFactor(1.0 - factor);
|
||||
setGestureInProgress(true);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::cancelPartialDeactivate()
|
||||
{
|
||||
activate();
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::cancelPartialActivate()
|
||||
{
|
||||
deactivate(false);
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::realDeactivate()
|
||||
{
|
||||
setRunning(false);
|
||||
m_status = Status::Inactive;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return m_gestureInProgress;
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::setGestureInProgress(bool gesture)
|
||||
{
|
||||
if (m_gestureInProgress != gesture) {
|
||||
m_gestureInProgress = gesture;
|
||||
Q_EMIT gestureInProgressChanged();
|
||||
}
|
||||
}
|
||||
|
||||
qreal MobileTaskSwitcherEffect::partialActivationFactor() const
|
||||
{
|
||||
return m_partialActivationFactor;
|
||||
}
|
||||
|
||||
void MobileTaskSwitcherEffect::setPartialActivationFactor(qreal factor)
|
||||
{
|
||||
if (m_partialActivationFactor != factor) {
|
||||
qDebug() << factor;
|
||||
m_partialActivationFactor = factor;
|
||||
Q_EMIT partialActivationFactorChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
77
kwin/mobiletaskswitcher/mobiletaskswitchereffect.h
Normal file
77
kwin/mobiletaskswitcher/mobiletaskswitchereffect.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kwinquickeffect.h>
|
||||
|
||||
#include <span>
|
||||
|
||||
#include <QAction>
|
||||
#include <QKeySequence>
|
||||
#include <QTimer>
|
||||
|
||||
#include <KGlobalAccel>
|
||||
#include <KLocalizedString>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class MobileTaskSwitcherEffect : public QuickSceneEffect
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qreal partialActivationFactor READ partialActivationFactor NOTIFY partialActivationFactorChanged)
|
||||
Q_PROPERTY(bool gestureInProgress READ gestureInProgress NOTIFY gestureInProgressChanged)
|
||||
|
||||
public:
|
||||
enum class Status { Inactive, Activating, Deactivating, Active };
|
||||
MobileTaskSwitcherEffect();
|
||||
~MobileTaskSwitcherEffect() override;
|
||||
|
||||
int animationDuration() const;
|
||||
void setAnimationDuration(int duration);
|
||||
|
||||
bool gestureInProgress() const;
|
||||
void setGestureInProgress(bool gesture);
|
||||
|
||||
qreal partialActivationFactor() const;
|
||||
void setPartialActivationFactor(qreal factor);
|
||||
|
||||
int requestedEffectChainPosition() const override;
|
||||
bool borderActivated(ElectricBorder border) override;
|
||||
void reconfigure(ReconfigureFlags flags) override;
|
||||
void grabbedKeyboardEvent(QKeyEvent *keyEvent) override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void activate();
|
||||
void realDeactivate();
|
||||
void partialActivate(qreal factor);
|
||||
void cancelPartialActivate();
|
||||
void partialDeactivate(qreal factor);
|
||||
void cancelPartialDeactivate();
|
||||
void deactivate(bool deactivateInstantly);
|
||||
void quickDeactivate();
|
||||
void toggle();
|
||||
|
||||
Q_SIGNALS:
|
||||
void animationDurationChanged();
|
||||
void gestureInProgressChanged();
|
||||
void partialActivationFactorChanged();
|
||||
|
||||
private:
|
||||
QAction *m_realtimeToggleAction = nullptr;
|
||||
QAction *m_toggleAction = nullptr;
|
||||
QList<QKeySequence> m_toggleShortcut;
|
||||
Status m_status = Status::Inactive;
|
||||
;
|
||||
QTimer *m_shutdownTimer;
|
||||
QList<ElectricBorder> m_borderActivate;
|
||||
QList<ElectricBorder> m_touchBorderActivate;
|
||||
|
||||
int m_animationDuration = 400;
|
||||
qreal m_partialActivationFactor = 0;
|
||||
bool m_gestureInProgress = false;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
|
@ -10,8 +7,6 @@ import QtQuick.Layouts 1.15
|
|||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
import org.kde.plasma.core 2.1 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
|
||||
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||
|
||||
Flickable {
|
||||
id: root
|
||||
|
|
@ -1,31 +1,30 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
// SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 2.2 as QQC2
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
|
||||
Item {
|
||||
id: delegate
|
||||
|
||||
required property var taskSwitcher
|
||||
|
||||
required property QtObject window
|
||||
required property int index
|
||||
|
||||
required property var model
|
||||
required property var displaysModel
|
||||
|
||||
required property real previewHeight
|
||||
required property real previewWidth
|
||||
|
||||
readonly property point taskScreenPoint: (model && model.ScreenGeometry) ? Qt.point(model.ScreenGeometry.x, model.ScreenGeometry.y) : Qt.point(0, 0)
|
||||
readonly property real dragOffset: -control.y
|
||||
|
||||
property bool showHeader: true
|
||||
|
|
@ -34,32 +33,21 @@ Item {
|
|||
opacity: 1 - dragOffset / taskSwitcher.height
|
||||
|
||||
//BEGIN functions
|
||||
function syncDelegateGeometry() {
|
||||
let pos = pipeWireLoader.mapToItem(delegate, 0, 0);
|
||||
if (taskSwitcher.visible) {
|
||||
tasksModel.requestPublishDelegateGeometry(tasksModel.index(model.index, 0), Qt.rect(pos.x, pos.y, pipeWireLoader.width, pipeWireLoader.height), pipeWireLoader);
|
||||
}
|
||||
}
|
||||
|
||||
function closeApp() {
|
||||
tasksModel.requestClose(tasksModel.index(model.index, 0));
|
||||
delegate.window.closeWindow();
|
||||
}
|
||||
|
||||
function activateApp() {
|
||||
taskSwitcherState.wasInActiveTask = false;
|
||||
taskSwitcher.activateWindow(model.index);
|
||||
taskSwitcher.activateWindow(model.index, delegate.window);
|
||||
window.setMaximize(true, true);
|
||||
}
|
||||
|
||||
function minimizeApp() {
|
||||
delegate.window.minimized = true;
|
||||
}
|
||||
//END functions
|
||||
|
||||
Component.onCompleted: syncDelegateGeometry();
|
||||
|
||||
Connections {
|
||||
target: taskSwitcher
|
||||
function onVisibleChanged() {
|
||||
syncDelegateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: control
|
||||
width: parent.width
|
||||
|
|
@ -149,33 +137,17 @@ Item {
|
|||
Layout.preferredWidth: PlasmaCore.Units.iconSizes.smallMedium
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
usesPlasmaTheme: false
|
||||
source: model.decoration
|
||||
source: delegate.window.icon
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
text: model.AppName
|
||||
text: delegate.window.caption
|
||||
color: "white"
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: rep
|
||||
model: displaysModel
|
||||
delegate: PlasmaComponents.ToolButton {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: model.modelName
|
||||
visible: model.position !== delegate.taskScreenPoint
|
||||
display: rep.count < 3 ? QQC2.Button.IconOnly : QQC2.Button.TextBesideIcon
|
||||
icon.name: "tv" //TODO provide a more adequate icon
|
||||
|
||||
onClicked: {
|
||||
displaysModel.sendWindowToOutput(delegate.model.WinIdList[0], model.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
z: 99
|
||||
|
|
@ -194,11 +166,11 @@ Item {
|
|||
Layout.maximumWidth: delegate.previewWidth
|
||||
Layout.maximumHeight: delegate.previewHeight
|
||||
|
||||
color: PlasmaCore.Theme.backgroundColor
|
||||
color: "transparent"
|
||||
clip: true
|
||||
|
||||
// scale animation on press
|
||||
property real zoomScale: (MobileShell.MobileShellSettings.animationsEnabled && tapHandler.pressed) ? 0.9 : 1
|
||||
property real zoomScale: tapHandler.pressed ? 0.9 : 1
|
||||
Behavior on zoomScale {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
|
|
@ -217,30 +189,17 @@ Item {
|
|||
id: item
|
||||
anchors.fill: parent
|
||||
|
||||
// app icon (behind window preview in-case it doesn't load)
|
||||
TaskIcon {
|
||||
// decrease the opacity faster
|
||||
opacity: pipeWireLoader.item && pipeWireLoader.item.uuid ? 0 : delegate.opacity
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
// attempt to load window preview
|
||||
Loader {
|
||||
id: pipeWireLoader
|
||||
active: (taskSwitcher.visible || taskSwitcher.tasksModel.taskReorderingEnabled) && MobileShell.MobileShellSettings.taskSwitcherPreviewsEnabled
|
||||
KWinComponents.WindowThumbnail {
|
||||
id: thumbSource
|
||||
wId: delegate.window.internalId
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl("./Thumbnail.qml")
|
||||
|
||||
asynchronous: true
|
||||
|
||||
onLoaded: this.item.refresh()
|
||||
layer {
|
||||
enabled: true
|
||||
effect: ColorOverlay {
|
||||
color: Qt.rgba(0, 0, 0, delegate.darken)
|
||||
}
|
||||
}
|
||||
|
||||
// darken effect
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "black"
|
||||
opacity: delegate.darken
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
|
|
@ -254,3 +213,4 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
// SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.1
|
||||
|
|
@ -10,10 +7,13 @@ import QtQuick.Layouts 1.1
|
|||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
import org.kde.plasma.core 2.1 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
|
||||
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property int count: repeater.count
|
||||
|
||||
required property real shellTopMargin
|
||||
required property real shellBottomMargin
|
||||
|
||||
|
|
@ -28,7 +28,38 @@ Item {
|
|||
|
||||
let baseY = (taskSwitcher.height / 2) - (taskSwitcherState.taskHeight / 2) - (taskSwitcherState.taskHeaderHeight / 2)
|
||||
|
||||
return baseY + diff / 2 - MobileShellState.TopPanelControls.panelHeight;
|
||||
return baseY + diff / 2;
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
repeater.itemAt(i).closeApp();
|
||||
}
|
||||
}
|
||||
|
||||
function minimizeAll() {
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
let item = repeater.itemAt(i);
|
||||
|
||||
// update property
|
||||
if (!item.window.minimized) {
|
||||
taskSwitcherState.wasInActiveTask = true;
|
||||
}
|
||||
|
||||
// minimize window immediately if it shows up
|
||||
item.minimizeApp();
|
||||
}
|
||||
}
|
||||
|
||||
function jumpToFirstVisibleWindow() {
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
let item = repeater.itemAt(i);
|
||||
|
||||
if (!item.window.minimized) {
|
||||
taskSwitcherState.goToTaskIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transform: Scale {
|
||||
|
|
@ -38,12 +69,6 @@ Item {
|
|||
yScale: taskSwitcherState.currentScale
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
repeater.itemAt(i).closeApp();
|
||||
}
|
||||
}
|
||||
|
||||
// taphandler activates even if delegate touched
|
||||
TapHandler {
|
||||
enabled: !taskSwitcherState.currentlyBeingOpened
|
||||
|
|
@ -54,6 +79,7 @@ Item {
|
|||
taskSwitcher.hide();
|
||||
}
|
||||
}
|
||||
|
||||
onPressedChanged: {
|
||||
if (pressed) {
|
||||
// ensure animations aren't running when finger is pressed
|
||||
|
|
@ -71,7 +97,6 @@ Item {
|
|||
|
||||
delegate: Task {
|
||||
id: task
|
||||
|
||||
readonly property int currentIndex: model.index
|
||||
|
||||
// this is the x-position with respect to the list
|
||||
|
|
@ -86,7 +111,6 @@ Item {
|
|||
|
||||
// this is the actual displayed x-position on screen
|
||||
x: listX + repeater.leftMargin - taskSwitcherState.xPosition
|
||||
|
||||
y: root.taskY
|
||||
|
||||
// ensure current task is above others
|
||||
|
|
@ -108,7 +132,6 @@ Item {
|
|||
previewHeight: taskSwitcherState.previewHeight
|
||||
|
||||
taskSwitcher: root.taskSwitcher
|
||||
displaysModel: root.taskSwitcher.displaysModel
|
||||
}
|
||||
}
|
||||
}
|
||||
269
kwin/mobiletaskswitcher/qml/TaskSwitcher.qml
Normal file
269
kwin/mobiletaskswitcher/qml/TaskSwitcher.qml
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
// SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2021-2023 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.15
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import org.kde.taskmanager 0.1 as TaskManager
|
||||
import org.kde.plasma.core 2.1 as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
import org.kde.kwin.private.effects 1.0
|
||||
|
||||
/**
|
||||
* Component that provides a task switcher.
|
||||
*/
|
||||
FocusScope {
|
||||
id: root
|
||||
focus: true
|
||||
|
||||
readonly property QtObject effect: KWinComponents.SceneView.effect
|
||||
readonly property QtObject targetScreen: KWinComponents.SceneView.screen
|
||||
|
||||
readonly property real topMargin: 0
|
||||
readonly property real bottomMargin: 0
|
||||
readonly property real leftMargin: 0
|
||||
readonly property real rightMargin: 0
|
||||
|
||||
property var taskSwitcherState: TaskSwitcherState {
|
||||
taskSwitcher: root
|
||||
}
|
||||
|
||||
KWinComponents.WindowModel {
|
||||
id: stackModel
|
||||
}
|
||||
|
||||
KWinComponents.VirtualDesktopModel {
|
||||
id: desktopModel
|
||||
}
|
||||
|
||||
property var tasksModel: KWinComponents.WindowFilterModel {
|
||||
activity: KWinComponents.Workspace.currentActivity
|
||||
desktop: KWinComponents.Workspace.currentDesktop
|
||||
screenName: root.targetScreen.name
|
||||
windowModel: stackModel
|
||||
minimizedWindows: true
|
||||
windowType: ~KWinComponents.WindowFilterModel.Dock &
|
||||
~KWinComponents.WindowFilterModel.Desktop &
|
||||
~KWinComponents.WindowFilterModel.Notification &
|
||||
~KWinComponents.WindowFilterModel.CriticalNotification
|
||||
}
|
||||
|
||||
readonly property int tasksCount: taskList.count
|
||||
|
||||
// keep track of task list events
|
||||
property int oldTasksCount: tasksCount
|
||||
onTasksCountChanged: {
|
||||
if (tasksCount === 0 && oldTasksCount !== 0) {
|
||||
hide();
|
||||
} else if (tasksCount < oldTasksCount && taskSwitcherState.currentTaskIndex >= tasksCount - 1) {
|
||||
// if the user is on the last task, and it is closed, scroll left
|
||||
taskSwitcherState.animateGoToTaskIndex(tasksCount - 1, PlasmaCore.Units.longDuration);
|
||||
}
|
||||
|
||||
oldTasksCount = tasksCount;
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: hide();
|
||||
|
||||
Component.onCompleted: {
|
||||
taskList.jumpToFirstVisibleWindow();
|
||||
taskList.minimizeAll();
|
||||
|
||||
taskSwitcherState.currentlyBeingOpened = true;
|
||||
|
||||
// fully open the panel (if this is a button press, not gesture)
|
||||
if (!root.effect.gestureInProgress) {
|
||||
taskSwitcherState.open();
|
||||
}
|
||||
}
|
||||
|
||||
// called by c++ plugin
|
||||
function hideAnimation() {
|
||||
closeAnim.restart();
|
||||
}
|
||||
|
||||
function instantHide() {
|
||||
root.effect.deactivate(true);
|
||||
}
|
||||
|
||||
function hide() {
|
||||
root.effect.deactivate(false);
|
||||
}
|
||||
|
||||
// scroll to delegate index, and activate it
|
||||
function activateWindow(index, window) {
|
||||
KWinComponents.Workspace.activeClient = window;
|
||||
taskSwitcherState.openApp(index, window);
|
||||
}
|
||||
|
||||
function setSingleActiveWindow(id) {
|
||||
instantHide();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.effect
|
||||
|
||||
function onPartialActivationFactorChanged() {
|
||||
taskSwitcherState.positionY = taskSwitcherState.openedYPosition * root.effect.partialActivationFactor;
|
||||
}
|
||||
|
||||
function onGestureInProgressChanged() {
|
||||
if (!root.effect.gestureInProgress) {
|
||||
taskSwitcherState.updateState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KWinComponents.DesktopBackground {
|
||||
id: backgroundItem
|
||||
activity: KWinComponents.Workspace.currentActivity
|
||||
desktop: KWinComponents.Workspace.currentDesktop
|
||||
outputName: targetScreen.name
|
||||
}
|
||||
|
||||
FastBlur {
|
||||
source: backgroundItem
|
||||
anchors.fill: parent
|
||||
opacity: container.opacity
|
||||
radius: 50
|
||||
cached: true
|
||||
}
|
||||
|
||||
// background colour
|
||||
Rectangle {
|
||||
id: backgroundRect
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: container.opacity
|
||||
color: {
|
||||
// animate background colour only if we are *not* opening from the homescreen
|
||||
if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) {
|
||||
return Qt.rgba(0, 0, 0, 0.6);
|
||||
} else {
|
||||
return Qt.rgba(0, 0, 0, 0.6 * Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: container
|
||||
|
||||
// provide shell margins
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: root.leftMargin
|
||||
anchors.rightMargin: root.rightMargin
|
||||
anchors.bottomMargin: root.bottomMargin
|
||||
anchors.topMargin: root.topMargin
|
||||
|
||||
NumberAnimation on opacity {
|
||||
id: closeAnim
|
||||
running: false
|
||||
to: 0
|
||||
duration: 200
|
||||
easing.type: Easing.InOutQuad
|
||||
|
||||
onFinished: {
|
||||
closeAllButton.closeRequested = false;
|
||||
}
|
||||
}
|
||||
|
||||
// placeholder message
|
||||
ColumnLayout {
|
||||
id: placeholder
|
||||
spacing: PlasmaCore.Units.gridUnit
|
||||
opacity: (root.tasksCount === 0 && !taskSwitcherState.currentlyBeingClosed) ? 0.9 : 0
|
||||
Behavior on opacity { NumberAnimation { duration: 500 } }
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
Kirigami.Icon {
|
||||
id: icon
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
implicitWidth: PlasmaCore.Units.iconSizes.large
|
||||
implicitHeight: PlasmaCore.Units.iconSizes.large
|
||||
source: "window"
|
||||
color: "white"
|
||||
}
|
||||
|
||||
PlasmaExtras.Heading {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: root.width * 0.75
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: "white"
|
||||
level: 3
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: i18n("No applications are running.")
|
||||
}
|
||||
}
|
||||
|
||||
// flicking area for task switcher
|
||||
FlickContainer {
|
||||
id: flickable
|
||||
anchors.fill: parent
|
||||
|
||||
taskSwitcherState: root.taskSwitcherState
|
||||
|
||||
// the item is effectively anchored to the flickable bounds
|
||||
TaskList {
|
||||
id: taskList
|
||||
taskSwitcher: root
|
||||
shellTopMargin: root.topMargin
|
||||
shellBottomMargin: root.bottomMargin
|
||||
|
||||
opacity: {
|
||||
// animate opacity only if we are *not* opening from the homescreen
|
||||
if (taskSwitcherState.wasInActiveTask || !taskSwitcherState.currentlyBeingOpened) {
|
||||
return 1;
|
||||
} else {
|
||||
return Math.min(1, taskSwitcherState.yPosition / taskSwitcherState.openedYPosition);
|
||||
}
|
||||
}
|
||||
|
||||
x: flickable.contentX
|
||||
width: flickable.width
|
||||
height: flickable.height
|
||||
|
||||
PlasmaComponents.ToolButton {
|
||||
id: closeAllButton
|
||||
property bool closeRequested: false
|
||||
visible: root.tasksCount !== 0
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: taskList.taskY / 2
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
PlasmaCore.ColorScope.colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||
PlasmaCore.ColorScope.inherit: false
|
||||
|
||||
opacity: (taskSwitcherState.currentlyBeingOpened || taskSwitcherState.currentlyBeingClosed) ? 0.0 : 1.0
|
||||
Behavior on opacity { NumberAnimation { duration: PlasmaCore.Units.shortDuration } }
|
||||
|
||||
icon.name: "edit-clear-history"
|
||||
font.bold: true
|
||||
|
||||
text: closeRequested ? i18n("Confirm Close All") : i18n("Close All")
|
||||
|
||||
onClicked: {
|
||||
if (closeRequested) {
|
||||
taskList.closeAll();
|
||||
} else {
|
||||
closeRequested = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,15 +1,11 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
// SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import QtQuick 2.15
|
||||
|
||||
import org.kde.plasma.core 2.1 as PlasmaCore
|
||||
|
||||
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
|
||||
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
|
||||
/**
|
||||
* State object for the task switcher.
|
||||
|
|
@ -139,9 +135,10 @@ QtObject {
|
|||
closeAnim.restart();
|
||||
}
|
||||
|
||||
function openApp(index) {
|
||||
function openApp(index, window) {
|
||||
animateGoToTaskIndex(index, PlasmaCore.Units.shortDuration);
|
||||
openAppAnim.restart();
|
||||
KWinComponents.Workspace.activeClient = window
|
||||
}
|
||||
|
||||
// get the xPosition where the task will be centered on the screen
|
||||
|
|
@ -208,7 +205,7 @@ QtObject {
|
|||
target: root
|
||||
property: "yPosition"
|
||||
to: openedYPosition
|
||||
duration: MobileShell.MobileShellSettings.animationsEnabled ? 300 : 0
|
||||
duration: 300
|
||||
easing.type: Easing.OutBack
|
||||
|
||||
onFinished: {
|
||||
|
|
@ -220,10 +217,13 @@ QtObject {
|
|||
target: root
|
||||
property: "yPosition"
|
||||
to: 0
|
||||
duration: MobileShell.MobileShellSettings.animationsEnabled ? PlasmaCore.Units.longDuration : 0
|
||||
duration: PlasmaCore.Units.longDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
|
||||
onStarted: root.currentlyBeingClosed = true
|
||||
|
||||
onFinished: {
|
||||
root.currentlyBeingClosed = false;
|
||||
root.currentlyBeingOpened = false;
|
||||
scrollingTasks = false;
|
||||
taskSwitcher.instantHide();
|
||||
|
|
@ -238,7 +238,7 @@ QtObject {
|
|||
target: root
|
||||
property: "yPosition"
|
||||
to: 0
|
||||
duration: MobileShell.MobileShellSettings.animationsEnabled ? 300 : 0
|
||||
duration: 300
|
||||
easing.type: Easing.OutQuint
|
||||
|
||||
onStarted: root.currentlyBeingClosed = true
|
||||
Loading…
Reference in a new issue