mirror of
https://gitgud.io/wackyideas/aerothemeplasma.git
synced 2024-08-15 00:43:43 +00:00
537 lines
16 KiB
QML
537 lines
16 KiB
QML
|
/*
|
||
|
SPDX-FileCopyrightText: 2012-2016 Eike Hein <hein@kde.org>
|
||
|
|
||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
*/
|
||
|
|
||
|
import QtQuick 2.0
|
||
|
import QtQuick.Layouts 1.1
|
||
|
import QtQml 2.15
|
||
|
|
||
|
import org.kde.plasma.plasmoid 2.0
|
||
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
||
|
|
||
|
import org.kde.taskmanager 0.1 as TaskManager
|
||
|
import org.kde.plasma.private.taskmanager 0.1 as TaskManagerApplet
|
||
|
|
||
|
import "code/layout.js" as LayoutManager
|
||
|
import "code/tools.js" as TaskTools
|
||
|
|
||
|
MouseArea {
|
||
|
id: tasks
|
||
|
|
||
|
anchors.fill: parent
|
||
|
hoverEnabled: true
|
||
|
|
||
|
property bool vertical: (plasmoid.formFactor === PlasmaCore.Types.Vertical)
|
||
|
property bool iconsOnly: !plasmoid.configuration.labelVisible//(plasmoid.pluginName === "org.kde.plasma.icontasks")
|
||
|
|
||
|
property QtObject contextMenuComponent: Qt.createComponent("ContextMenu.qml");
|
||
|
property QtObject pulseAudioComponent: Qt.createComponent("PulseAudio.qml");
|
||
|
|
||
|
property bool needLayoutRefresh: false;
|
||
|
property variant taskClosedWithMouseMiddleButton: []
|
||
|
|
||
|
Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation
|
||
|
|
||
|
Plasmoid.constraintHints: PlasmaCore.Types.CanFillArea
|
||
|
|
||
|
Plasmoid.onUserConfiguringChanged: {
|
||
|
if (plasmoid.userConfiguring) {
|
||
|
groupDialog.visible = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Layout.fillWidth: true
|
||
|
Layout.fillHeight: true
|
||
|
Layout.minimumWidth: tasks.vertical ? 0 : LayoutManager.preferredMinWidth()
|
||
|
Layout.minimumHeight: !tasks.vertical ? 0 : LayoutManager.preferredMinHeight()
|
||
|
|
||
|
//BEGIN TODO: this is not precise enough: launchers are smaller than full tasks
|
||
|
Layout.preferredWidth: tasks.vertical ? PlasmaCore.Units.gridUnit * 10 : ((LayoutManager.logicalTaskCount() * LayoutManager.preferredMaxWidth()) / LayoutManager.calculateStripes());
|
||
|
Layout.preferredHeight: tasks.vertical ? ((LayoutManager.logicalTaskCount() * LayoutManager.preferredMaxHeight()) / LayoutManager.calculateStripes()) : PlasmaCore.Units.gridUnit * 2;
|
||
|
//END TODO
|
||
|
|
||
|
property Item dragSource: null
|
||
|
|
||
|
signal requestLayout
|
||
|
signal windowsHovered(variant winIds, bool hovered)
|
||
|
signal presentWindows(variant winIds)
|
||
|
|
||
|
states: State {
|
||
|
name: "iconsOnlyChanged"; when: iconsOnly
|
||
|
StateChangeScript {
|
||
|
script: taskList.updateHoverFunc();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
onWidthChanged: {
|
||
|
taskList.width = LayoutManager.layoutWidth();
|
||
|
|
||
|
if (plasmoid.configuration.forceStripes) {
|
||
|
taskList.height = LayoutManager.layoutHeight();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onHeightChanged: {
|
||
|
if (plasmoid.configuration.forceStripes) {
|
||
|
taskList.width = LayoutManager.layoutWidth();
|
||
|
}
|
||
|
|
||
|
taskList.height = LayoutManager.layoutHeight();
|
||
|
}
|
||
|
|
||
|
onDragSourceChanged: {
|
||
|
if (dragSource == null) {
|
||
|
tasksModel.syncLaunchers();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onExited: {
|
||
|
if (needLayoutRefresh) {
|
||
|
LayoutManager.layout(taskRepeater)
|
||
|
needLayoutRefresh = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
TaskManager.TasksModel {
|
||
|
id: tasksModel
|
||
|
|
||
|
readonly property int logicalLauncherCount: {
|
||
|
if (plasmoid.configuration.separateLaunchers) {
|
||
|
return launcherCount;
|
||
|
}
|
||
|
|
||
|
var startupsWithLaunchers = 0;
|
||
|
|
||
|
for (var i = 0; i < taskRepeater.count; ++i) {
|
||
|
var item = taskRepeater.itemAt(i);
|
||
|
|
||
|
if (item && item.m.IsStartup === true && item.m.HasLauncher === true) {
|
||
|
++startupsWithLaunchers;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return launcherCount + startupsWithLaunchers;
|
||
|
}
|
||
|
|
||
|
virtualDesktop: virtualDesktopInfo.currentDesktop
|
||
|
screenGeometry: plasmoid.screenGeometry
|
||
|
activity: activityInfo.currentActivity
|
||
|
|
||
|
filterByVirtualDesktop: plasmoid.configuration.showOnlyCurrentDesktop
|
||
|
filterByScreen: plasmoid.configuration.showOnlyCurrentScreen
|
||
|
filterByActivity: plasmoid.configuration.showOnlyCurrentActivity
|
||
|
filterNotMinimized: plasmoid.configuration.showOnlyMinimized
|
||
|
|
||
|
sortMode: sortModeEnumValue(plasmoid.configuration.sortingStrategy)
|
||
|
launchInPlace: iconsOnly && plasmoid.configuration.sortingStrategy === 1
|
||
|
separateLaunchers: {
|
||
|
if (!iconsOnly && !plasmoid.configuration.separateLaunchers
|
||
|
&& plasmoid.configuration.sortingStrategy === 1) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
groupMode: groupModeEnumValue(plasmoid.configuration.groupingStrategy)
|
||
|
groupInline: !plasmoid.configuration.groupPopups
|
||
|
groupingWindowTasksThreshold: (plasmoid.configuration.onlyGroupWhenFull && !iconsOnly
|
||
|
? LayoutManager.optimumCapacity(width, height) + 1 : -1)
|
||
|
|
||
|
onLauncherListChanged: {
|
||
|
layoutTimer.restart();
|
||
|
plasmoid.configuration.launchers = launcherList;
|
||
|
taskList.updateHoverFunc();
|
||
|
//This could be a good hover change
|
||
|
}
|
||
|
|
||
|
onGroupingAppIdBlacklistChanged: {
|
||
|
plasmoid.configuration.groupingAppIdBlacklist = groupingAppIdBlacklist;
|
||
|
}
|
||
|
|
||
|
onGroupingLauncherUrlBlacklistChanged: {
|
||
|
plasmoid.configuration.groupingLauncherUrlBlacklist = groupingLauncherUrlBlacklist;
|
||
|
}
|
||
|
|
||
|
function sortModeEnumValue(index) {
|
||
|
switch (index) {
|
||
|
case 0:
|
||
|
return TaskManager.TasksModel.SortDisabled;
|
||
|
case 1:
|
||
|
return TaskManager.TasksModel.SortManual;
|
||
|
case 2:
|
||
|
return TaskManager.TasksModel.SortAlpha;
|
||
|
case 3:
|
||
|
return TaskManager.TasksModel.SortVirtualDesktop;
|
||
|
case 4:
|
||
|
return TaskManager.TasksModel.SortActivity;
|
||
|
default:
|
||
|
return TaskManager.TasksModel.SortDisabled;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function groupModeEnumValue(index) {
|
||
|
switch (index) {
|
||
|
case 0:
|
||
|
return TaskManager.TasksModel.GroupDisabled;
|
||
|
case 1:
|
||
|
return TaskManager.TasksModel.GroupApplications;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Component.onCompleted: {
|
||
|
launcherList = plasmoid.configuration.launchers;
|
||
|
groupingAppIdBlacklist = plasmoid.configuration.groupingAppIdBlacklist;
|
||
|
groupingLauncherUrlBlacklist = plasmoid.configuration.groupingLauncherUrlBlacklist;
|
||
|
|
||
|
// Only hook up view only after the above churn is done.
|
||
|
taskRepeater.model = tasksModel;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Connections {
|
||
|
target: tasksModel
|
||
|
|
||
|
function onActiveTaskChanged() {
|
||
|
if (!plasmoid.configuration.groupPopups) {
|
||
|
return;
|
||
|
}
|
||
|
if (tasksModel.activeTask.parent.valid) {
|
||
|
groupDialog.activeTask = tasksModel.activeTask;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TaskManager.VirtualDesktopInfo {
|
||
|
id: virtualDesktopInfo
|
||
|
}
|
||
|
|
||
|
TaskManager.ActivityInfo {
|
||
|
id: activityInfo
|
||
|
}
|
||
|
|
||
|
TaskManagerApplet.Backend {
|
||
|
id: backend
|
||
|
|
||
|
taskManagerItem: tasks
|
||
|
groupDialog: groupDialog
|
||
|
highlightWindows: plasmoid.configuration.highlightWindows
|
||
|
|
||
|
onAddLauncher: {
|
||
|
tasks.addLauncher(url);
|
||
|
//Here too
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PlasmaCore.DataSource {
|
||
|
id: mpris2Source
|
||
|
engine: "mpris2"
|
||
|
connectedSources: sources
|
||
|
function sourceNameForLauncherUrl(launcherUrl, pid) {
|
||
|
if (!launcherUrl || launcherUrl === "") {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
// MPRIS spec explicitly mentions that "DesktopEntry" is with .desktop extension trimmed
|
||
|
// Moreover, remove URL parameters, like wmClass (part after the question mark)
|
||
|
var desktopFileName = launcherUrl.toString().split('/').pop().split('?')[0].replace(".desktop", "")
|
||
|
if (desktopFileName.indexOf("applications:") === 0) {
|
||
|
desktopFileName = desktopFileName.substr(13)
|
||
|
}
|
||
|
|
||
|
for (var i = 0, length = connectedSources.length; i < length; ++i) {
|
||
|
var source = connectedSources[i];
|
||
|
// we intend to connect directly, otherwise the multiplexer steals the connection away
|
||
|
if (source === "@multiplex") {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
var sourceData = data[source];
|
||
|
if (!sourceData) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (sourceData.DesktopEntry === desktopFileName || (pid && sourceData.InstancePid === pid)) {
|
||
|
return source;
|
||
|
}
|
||
|
|
||
|
var metadata = sourceData.Metadata;
|
||
|
if (metadata) {
|
||
|
var kdePid = metadata["kde:pid"];
|
||
|
if (kdePid && pid === kdePid) {
|
||
|
return source;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
function startOperation(source, op) {
|
||
|
var service = serviceForSource(source)
|
||
|
var operation = service.operationDescription(op)
|
||
|
return service.startOperationCall(operation)
|
||
|
}
|
||
|
|
||
|
function goPrevious(source) {
|
||
|
startOperation(source, "Previous");
|
||
|
}
|
||
|
function goNext(source) {
|
||
|
startOperation(source, "Next");
|
||
|
}
|
||
|
function play(source) {
|
||
|
startOperation(source, "Play");
|
||
|
}
|
||
|
function pause(source) {
|
||
|
startOperation(source, "Pause");
|
||
|
}
|
||
|
function playPause(source) {
|
||
|
startOperation(source, "PlayPause");
|
||
|
}
|
||
|
function stop(source) {
|
||
|
startOperation(source, "Stop");
|
||
|
}
|
||
|
function raise(source) {
|
||
|
startOperation(source, "Raise");
|
||
|
}
|
||
|
function quit(source) {
|
||
|
startOperation(source, "Quit");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Loader {
|
||
|
id: pulseAudio
|
||
|
sourceComponent: pulseAudioComponent
|
||
|
active: pulseAudioComponent.status === Component.Ready
|
||
|
}
|
||
|
|
||
|
Timer {
|
||
|
id: iconGeometryTimer
|
||
|
|
||
|
interval: 500
|
||
|
repeat: false
|
||
|
|
||
|
onTriggered: {
|
||
|
TaskTools.publishIconGeometries(taskList.children);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Binding {
|
||
|
target: plasmoid
|
||
|
property: "status"
|
||
|
value: (tasksModel.anyTaskDemandsAttention && plasmoid.configuration.unhideOnAttention
|
||
|
? PlasmaCore.Types.NeedsAttentionStatus : PlasmaCore.Types.PassiveStatus)
|
||
|
restoreMode: Binding.RestoreBinding
|
||
|
}
|
||
|
|
||
|
Connections {
|
||
|
target: plasmoid
|
||
|
|
||
|
function onLocationChanged() {
|
||
|
// This is on a timer because the panel may not have
|
||
|
// settled into position yet when the location prop-
|
||
|
// erty updates.
|
||
|
iconGeometryTimer.start();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Connections {
|
||
|
target: plasmoid.configuration
|
||
|
|
||
|
function onLaunchersChanged() {
|
||
|
tasksModel.launcherList = plasmoid.configuration.launchers
|
||
|
}
|
||
|
function onGroupingAppIdBlacklistChanged() {
|
||
|
tasksModel.groupingAppIdBlacklist = plasmoid.configuration.groupingAppIdBlacklist;
|
||
|
}
|
||
|
function onGroupingLauncherUrlBlacklistChanged() {
|
||
|
tasksModel.groupingLauncherUrlBlacklist = plasmoid.configuration.groupingLauncherUrlBlacklist;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TaskManagerApplet.DragHelper {
|
||
|
id: dragHelper
|
||
|
|
||
|
dragIconSize: PlasmaCore.Units.iconSizes.medium
|
||
|
}
|
||
|
|
||
|
PlasmaCore.FrameSvgItem {
|
||
|
id: taskFrame
|
||
|
|
||
|
visible: false;
|
||
|
|
||
|
imagePath: "widgets/tasks";
|
||
|
prefix: "normal"
|
||
|
}
|
||
|
|
||
|
PlasmaCore.Svg {
|
||
|
id: taskSvg
|
||
|
|
||
|
imagePath: "widgets/tasks"
|
||
|
}
|
||
|
|
||
|
MouseHandler {
|
||
|
id: mouseHandler
|
||
|
|
||
|
anchors.fill: parent
|
||
|
|
||
|
target: taskList
|
||
|
|
||
|
onUrlsDropped: {
|
||
|
// If all dropped URLs point to application desktop files, we'll add a launcher for each of them.
|
||
|
var createLaunchers = urls.every(function (item) {
|
||
|
return backend.isApplication(item)
|
||
|
});
|
||
|
|
||
|
if (createLaunchers) {
|
||
|
urls.forEach(function (item) {
|
||
|
addLauncher(item);
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!hoveredItem) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// DeclarativeMimeData urls is a QJsonArray but requestOpenUrls expects a proper QList<QUrl>.
|
||
|
var urlsList = backend.jsonArrayToUrlList(urls);
|
||
|
|
||
|
// Otherwise we'll just start a new instance of the application with the URLs as argument,
|
||
|
// as you probably don't expect some of your files to open in the app and others to spawn launchers.
|
||
|
tasksModel.requestOpenUrls(hoveredItem.modelIndex(), urlsList);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ToolTipDelegate {
|
||
|
id: openWindowToolTipDelegate
|
||
|
visible: false
|
||
|
}
|
||
|
|
||
|
ToolTipDelegate {
|
||
|
id: pinnedAppToolTipDelegate
|
||
|
visible: false
|
||
|
}
|
||
|
|
||
|
TaskList {
|
||
|
id: taskList
|
||
|
anchors {
|
||
|
left: parent.left
|
||
|
top: parent.top
|
||
|
}
|
||
|
property bool firstTimeHover: false
|
||
|
onWidthChanged: LayoutManager.layout(taskRepeater)
|
||
|
onHeightChanged: LayoutManager.layout(taskRepeater)
|
||
|
|
||
|
flow: {
|
||
|
if (tasks.vertical) {
|
||
|
return plasmoid.configuration.forceStripes ? Flow.LeftToRight : Flow.TopToBottom
|
||
|
}
|
||
|
return plasmoid.configuration.forceStripes ? Flow.TopToBottom : Flow.LeftToRight
|
||
|
}
|
||
|
|
||
|
onAnimatingChanged: {
|
||
|
if (!animating) {
|
||
|
TaskTools.publishIconGeometries(children);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function layout() {
|
||
|
taskList.width = LayoutManager.layoutWidth();
|
||
|
taskList.height = LayoutManager.layoutHeight();
|
||
|
LayoutManager.layout(taskRepeater);
|
||
|
//taskList.updateHoverFunc();
|
||
|
}
|
||
|
function updateHoverFunc()
|
||
|
{
|
||
|
for(var i = 0; i < taskRepeater.count; i++)
|
||
|
{
|
||
|
taskRepeater.itemAt(i).updateHoverColor();
|
||
|
}
|
||
|
tasks.state = "";
|
||
|
console.log("Updated hovers");
|
||
|
}
|
||
|
|
||
|
Timer {
|
||
|
id: layoutTimer
|
||
|
|
||
|
interval: 0
|
||
|
repeat: false
|
||
|
|
||
|
onTriggered: taskList.layout()
|
||
|
}
|
||
|
|
||
|
Repeater {
|
||
|
id: taskRepeater
|
||
|
|
||
|
|
||
|
delegate: Task { id: task }
|
||
|
onItemAdded: {
|
||
|
taskList.layout()
|
||
|
taskList.updateHoverFunc();
|
||
|
}
|
||
|
onItemRemoved: {
|
||
|
if (tasks.containsMouse && index != taskRepeater.count &&
|
||
|
item.winIdList && item.winIdList.length > 0 &&
|
||
|
taskClosedWithMouseMiddleButton.indexOf(item.winIdList[0]) > -1) {
|
||
|
needLayoutRefresh = true;
|
||
|
} else {
|
||
|
taskList.layout();
|
||
|
}
|
||
|
taskClosedWithMouseMiddleButton = [];
|
||
|
taskList.updateHoverFunc();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GroupDialog { id: groupDialog }
|
||
|
function hasLauncher(url) {
|
||
|
return tasksModel.launcherPosition(url) != -1;
|
||
|
}
|
||
|
|
||
|
function addLauncher(url) {
|
||
|
if (plasmoid.immutability !== PlasmaCore.Types.SystemImmutable) {
|
||
|
tasksModel.requestAddLauncher(url);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This is called by plasmashell in response to a Meta+number shortcut.
|
||
|
function activateTaskAtIndex(index) {
|
||
|
if (typeof index !== "number") {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var task = taskRepeater.itemAt(index);
|
||
|
if (task) {
|
||
|
TaskTools.activateTask(task.modelIndex(), task.m, null, task);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function resetDragSource() {
|
||
|
dragSource = null;
|
||
|
}
|
||
|
|
||
|
function createContextMenu(rootTask, modelIndex, args) {
|
||
|
var initialArgs = args || {}
|
||
|
initialArgs.visualParent = rootTask;
|
||
|
initialArgs.modelIndex = modelIndex;
|
||
|
initialArgs.mpris2Source = mpris2Source;
|
||
|
initialArgs.backend = backend;
|
||
|
|
||
|
return tasks.contextMenuComponent.createObject(rootTask, initialArgs);
|
||
|
}
|
||
|
|
||
|
Component.onCompleted: {
|
||
|
tasks.requestLayout.connect(layoutTimer.restart);
|
||
|
tasks.requestLayout.connect(iconGeometryTimer.restart);
|
||
|
tasks.windowsHovered.connect(backend.windowsHovered);
|
||
|
tasks.presentWindows.connect(backend.presentWindows);
|
||
|
dragHelper.dropped.connect(resetDragSource);
|
||
|
taskList.updateHoverFunc();
|
||
|
}
|
||
|
}
|