diff --git a/plasmoid/package/contents/ui/ContextMenu.qml b/plasmoid/package/contents/ui/ContextMenu.qml index aaa0d921..6586ec20 100644 --- a/plasmoid/package/contents/ui/ContextMenu.qml +++ b/plasmoid/package/contents/ui/ContextMenu.qml @@ -1,903 +1,905 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.0 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.activities 0.1 as Activities import org.kde.taskmanager 0.1 as TaskManager import org.kde.latte 0.1 as Latte import "../code/activitiesTools.js" as ActivitiesTools PlasmaComponents.ContextMenu { id: menu property bool changingLayout: false property QtObject mpris2Source property QtObject backend property var modelIndex readonly property var atm: TaskManager.AbstractTasksModel placement: { if (plasmoid.location == PlasmaCore.Types.LeftEdge) { return PlasmaCore.Types.RightPosedTopAlignedPopup; } else if (plasmoid.location == PlasmaCore.Types.TopEdge) { return PlasmaCore.Types.BottomPosedLeftAlignedPopup; } else { return PlasmaCore.Types.TopPosedLeftAlignedPopup; } } minimumWidth: visualParent ? visualParent.width : 1 property bool isOnAllActivitiesLauncher: true property bool showAllPlaces: false property int activitiesCount: 0 onStatusChanged: { if (visualParent && get(atm.LauncherUrlWithoutIcon) != null && status == PlasmaComponents.DialogStatus.Open) { launcherToggleAction.checked = (tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) != -1); activitiesDesktopsMenu.refresh(); } else if (status == PlasmaComponents.DialogStatus.Closed) { root.startCheckRestoreZoomTimer(100); + root.contextMenu = null; menu.destroy(); backend.ungrabMouse(visualParent); } } function get(modelProp) { return tasksModel.data(modelIndex, modelProp) } function show() { //trying to use the dragging mechanism in order to not hide the dock root.disableRestoreZoom = true; root.signalActionsBlockHiding(1); //root.signalDraggingState(true); loadDynamicLaunchActions(visualParent.m.LauncherUrlWithoutIcon); // backend.ungrabMouse(visualParent); openRelative(); + windowsPreviewDlg.contextMenu = true; - windowsPreviewDlg.hide(); + windowsPreviewDlg.hide("8.2"); icList.directRender = false; if (root.latteDock){ root.latteDock.hideTooltipLabel(); root.latteDock.globalDirectRender = false; } } function newMenuItem(parent) { return Qt.createQmlObject( "import org.kde.plasma.components 2.0 as PlasmaComponents;" + "PlasmaComponents.MenuItem {}", parent); } function newSeparator(parent) { return Qt.createQmlObject( "import org.kde.plasma.components 2.0 as PlasmaComponents;" + "PlasmaComponents.MenuItem { separator: true }", parent); } function loadDynamicLaunchActions(launcherUrl) { var lists = []; //From Plasma 5.10 and frameworks 5.34, places are also supported if (Latte.WindowSystem.frameworksVersion >= 336384 && (typeof backend.placesActions === "function")) { lists = [ backend.jumpListActions(launcherUrl, menu), backend.placesActions(launcherUrl, showAllPlaces, menu), backend.recentDocumentActions(launcherUrl, menu) ] } else { lists = [ backend.jumpListActions(launcherUrl, menu), backend.recentDocumentActions(launcherUrl, menu) ]; } lists.forEach(function (list) { for (var i = 0; i < list.length; ++i) { var item = newMenuItem(menu); item.action = list[i]; menu.addMenuItem(item, virtualDesktopsMenuItem); } if (list.length > 0) { menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem); } }); // Add Media Player control actions var sourceName = mpris2Source.sourceNameForLauncherUrl(launcherUrl, get(atm.AppPid)); if (sourceName && !(get(atm.LegacyWinIdList) != undefined && get(atm.LegacyWinIdList).length > 1)) { var playerData = mpris2Source.data[sourceName] if (playerData.CanControl) { var menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Play previous track", "Previous Track"); menuItem.icon = "media-skip-backward"; menuItem.enabled = Qt.binding(function() { return playerData.CanGoPrevious; }); menuItem.clicked.connect(function() { mpris2Source.goPrevious(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); menuItem = menu.newMenuItem(menu); // PlasmaCore Menu doesn't actually handle icons or labels changing at runtime... menuItem.text = Qt.binding(function() { return playerData.PlaybackStatus === "Playing" ? i18nc("Pause playback", "Pause") : i18nc("Start playback", "Play"); }); menuItem.icon = Qt.binding(function() { return playerData.PlaybackStatus === "Playing" ? "media-playback-pause" : "media-playback-start"; }); menuItem.enabled = Qt.binding(function() { return playerData.PlaybackStatus === "Playing" ? playerData.CanPause : playerData.CanPlay; }); menuItem.clicked.connect(function() { mpris2Source.playPause(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Play next track", "Next Track"); menuItem.icon = "media-skip-forward"; menuItem.enabled = Qt.binding(function() { return playerData.CanGoNext; }); menuItem.clicked.connect(function() { mpris2Source.goNext(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Stop playback", "Stop"); menuItem.icon = "media-playback-stop"; menuItem.clicked.connect(function() { mpris2Source.stop(sourceName); }); menu.addMenuItem(menuItem, virtualDesktopsMenuItem); // Technically media controls and audio streams are separate but for the user they're // semantically related, don't add a separator inbetween. if (!menu.visualParent.hasAudioStream) { menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem); } // If we don't have a window associated with the player but we can quit // it through MPRIS we'll offer a "Quit" option instead of "Close" if (!closeWindowItem.visible && playerData.CanQuit) { menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Quit media player app", "Quit"); menuItem.icon = "application-exit"; menuItem.visible = Qt.binding(function() { return !closeWindowItem.visible; }); menuItem.clicked.connect(function() { mpris2Source.quit(sourceName); }); menu.addMenuItem(menuItem); } // If we don't have a window associated with the player but we can raise // it through MPRIS we'll offer a "Restore" option if (!startNewInstanceItem.visible && playerData.CanRaise) { menuItem = menu.newMenuItem(menu); menuItem.text = i18nc("Open or bring to the front window of media player app", "Restore"); menuItem.icon = playerData["Desktop Icon Name"]; menuItem.visible = Qt.binding(function() { return !startNewInstanceItem.visible; }); menuItem.clicked.connect(function() { mpris2Source.raise(sourceName); }); menu.addMenuItem(menuItem, startNewInstanceItem); } } } // We allow mute/unmute whenever an application has a stream, regardless of whether it // is actually playing sound. // This way you can unmute, e.g. a telephony app, even after the conversation has ended, // so you still have it ringing later on. if (menu.visualParent.hasAudioStream) { var muteItem = menu.newMenuItem(menu); muteItem.checkable = true; muteItem.checked = Qt.binding(function() { return menu.visualParent && menu.visualParent.muted; }); muteItem.clicked.connect(function() { menu.visualParent.toggleMuted(); }); muteItem.text = i18n("Mute"); muteItem.icon = "audio-volume-muted"; menu.addMenuItem(muteItem, virtualDesktopsMenuItem); menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem); } } ///REMOVE function updateOnAllActivitiesLauncher(){ //isOnAllActivitiesLauncher = ActivitiesTools.isOnAllActivities(visualParent.m.LauncherUrlWithoutIcon); } Component.onCompleted: { ActivitiesTools.launchersOnActivities = root.launchersOnActivities ActivitiesTools.currentActivity = activityInfo.currentActivity; ActivitiesTools.plasmoid = plasmoid; //From Plasma 5.10 and frameworks 5.34 jumpLists and //places are supported if (Latte.WindowSystem.frameworksVersion >= 336384) { // Cannot have "Connections" as child of PlasmaCoponents.ContextMenu. backend.showAllPlaces.connect(function() { visualParent.showContextMenu({showAllPlaces: true}); }); } // updateOnAllActivitiesLauncher(); } Component.onDestruction: { if (!changingLayout) { windowsPreviewDlg.contextMenu = false; root.contextMenu = null; backend.ungrabMouse(visualParent); root.signalActionsBlockHiding(-1); //root.signalDraggingState(false); root.disableRestoreZoom = false; root.startCheckRestoreZoomTimer(100); } } /// Sub Items PlasmaComponents.MenuItem { id: virtualDesktopsMenuItem visible: virtualDesktopInfo.numberOfDesktops > 1 && (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && visualParent.m.IsVirtualDesktopChangeable === true) enabled: visible text: i18n("Move To Desktop") Connections { target: virtualDesktopInfo onNumberOfDesktopsChanged: virtualDesktopsMenu.refresh() onDesktopNamesChanged: virtualDesktopsMenu.refresh() } PlasmaComponents.ContextMenu { id: virtualDesktopsMenu visualParent: virtualDesktopsMenuItem.action function refresh() { clearMenuItems(); if (virtualDesktopInfo.numberOfDesktops <= 1) { return; } var menuItem = menu.newMenuItem(virtualDesktopsMenu); menuItem.text = i18n("Move To Current Desktop"); menuItem.enabled = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.VirtualDesktop != virtualDesktopInfo.currentDesktop; }); menuItem.clicked.connect(function() { tasksModel.requestVirtualDesktop(menu.modelIndex, 0); }); menuItem = menu.newMenuItem(virtualDesktopsMenu); menuItem.text = i18n("All Desktops"); menuItem.checkable = true; menuItem.checked = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.IsOnAllVirtualDesktops === true; }); menuItem.clicked.connect(function() { tasksModel.requestVirtualDesktop(menu.modelIndex, 0); }); backend.setActionGroup(menuItem.action); menu.newSeparator(virtualDesktopsMenu); for (var i = 0; i < virtualDesktopInfo.desktopNames.length; ++i) { menuItem = menu.newMenuItem(virtualDesktopsMenu); //menuItem.text = i18nc("1 = number of desktop, 2 = desktop name", "%1 Desktop %2", i + 1, virtualDesktopInfo.desktopNames[i]); menuItem.text = (i + 1) + ". " + virtualDesktopInfo.desktopNames[i]; menuItem.checkable = true; menuItem.checked = Qt.binding((function(i) { return function() { return menu.visualParent && menu.visualParent.m.VirtualDesktop == (i + 1) }; })(i)); menuItem.clicked.connect((function(i) { return function() { return tasksModel.requestVirtualDesktop(menu.modelIndex, i + 1); }; })(i)); backend.setActionGroup(menuItem.action); } menu.newSeparator(virtualDesktopsMenu); menuItem = menu.newMenuItem(virtualDesktopsMenu); menuItem.text = i18n("New Desktop"); menuItem.clicked.connect(function() { tasksModel.requestVirtualDesktop(menu.modelIndex, virtualDesktopInfo.numberOfDesktops + 1) }); } Component.onCompleted: refresh() } } PlasmaComponents.MenuItem { id: activitiesDesktopsMenuItem visible: activityInfo.numberOfRunningActivities > 1 && (visualParent && !visualParent.m.IsLauncher && !visualParent.m.IsStartup) && !root.disableAllWindowsFunctionality enabled: visible text: i18n("Move To &Activity") Connections { target: activityInfo onNumberOfRunningActivitiesChanged: activitiesDesktopsMenu.refresh() } PlasmaComponents.ContextMenu { id: activitiesDesktopsMenu visualParent: activitiesDesktopsMenuItem.action function refresh() { clearMenuItems(); if (activityInfo.numberOfRunningActivities <= 1) { return; } var menuItem = menu.newMenuItem(activitiesDesktopsMenu); menuItem.text = i18n("Add To Current Activity"); menuItem.enabled = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.Activities.length > 0 && menu.visualParent.m.Activities.indexOf(activityInfo.currentActivity) < 0; }); menuItem.clicked.connect(function() { tasksModel.requestActivities(menu.modelIndex, menu.visualParent.m.Activities.concat(activityInfo.currentActivity)); }); menuItem = menu.newMenuItem(activitiesDesktopsMenu); menuItem.text = i18n("All Activities"); menuItem.checkable = true; menuItem.checked = Qt.binding(function() { return menu.visualParent && menu.visualParent.m.Activities.length === 0; }); menuItem.clicked.connect(function() { var checked = menuItem.checked; var newActivities = menu.visualParent.m.Activities; var size = newActivities.length; newActivities = undefined; // will cast to an empty QStringList i.e all activities if (size === 0) { newActivities = new Array(activityInfo.currentActivity); } tasksModel.requestActivities(menu.modelIndex, newActivities); }); menu.newSeparator(activitiesDesktopsMenu); var runningActivities = activityInfo.runningActivities(); for (var i = 0; i < runningActivities.length; ++i) { var activityId = runningActivities[i]; menuItem = menu.newMenuItem(activitiesDesktopsMenu); menuItem.text = activityInfo.activityName(runningActivities[i]); menuItem.checkable = true; menuItem.checked = Qt.binding( (function(activityId) { return function() { return menu.visualParent && menu.visualParent.m.Activities.indexOf(activityId) >= 0; }; })(activityId)); menuItem.clicked.connect((function(activityId) { return function () { var checked = menuItem.checked; var newActivities = menu.visualParent.m.Activities; var index = newActivities.indexOf(activityId) if (index < 0) { newActivities = newActivities.concat(activityId); } else { //newActivities = newActivities.splice(index, 1); //this does not work!!! newActivities.splice(index, 1); } return tasksModel.requestActivities(menu.modelIndex, newActivities); }; })(activityId)); } menu.newSeparator(activitiesDesktopsMenu); } Component.onCompleted: refresh() } } PlasmaComponents.MenuItem { visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions && !root.disableAllWindowsFunctionality) enabled: visualParent && visualParent.m.IsMinimizable === true checkable: true checked: visualParent && visualParent.m.IsMinimized === true text: i18n("Minimize") onClicked: tasksModel.requestToggleMinimized(menu.modelIndex) } PlasmaComponents.MenuItem { visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions && !root.disableAllWindowsFunctionality) enabled: visualParent && visualParent.m.IsMaximizable === true checkable: true checked: visualParent && visualParent.m.IsMaximized === true text: i18n("Maximize") onClicked: tasksModel.requestToggleMaximized(menu.modelIndex) } PlasmaComponents.MenuItem { id: moreActionsMenuItem visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions && !root.disableAllWindowsFunctionality) enabled: visible text: i18n("More Actions") PlasmaComponents.ContextMenu { visualParent: moreActionsMenuItem.action PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsMovable === true text: i18n("Move") icon: "transform-move" onClicked: tasksModel.requestMove(menu.modelIndex) } PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsResizable === true text: i18n("Resize") onClicked: tasksModel.requestResize(menu.modelIndex) } PlasmaComponents.MenuItem { checkable: true checked: menu.visualParent && menu.visualParent.m.IsKeepAbove === true text: i18n("Keep Above Others") icon: "go-up" onClicked: tasksModel.requestToggleKeepAbove(menu.modelIndex) } PlasmaComponents.MenuItem { checkable: true checked: menu.visualParent && menu.visualParent.m.IsKeepBelow === true text: i18n("Keep Below Others") icon: "go-down" onClicked: tasksModel.requestToggleKeepBelow(menu.modelIndex) } PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsFullScreenable === true checkable: true checked: menu.visualParent && menu.visualParent.m.IsFullScreen === true text: i18n("Fullscreen") icon: "view-fullscreen" onClicked: tasksModel.requestToggleFullScreen(menu.modelIndex) } PlasmaComponents.MenuItem { enabled: menu.visualParent && menu.visualParent.m.IsShadeable === true checkable: true checked: menu.visualParent && menu.visualParent.m.IsShaded === true text: i18n("Shade") onClicked: tasksModel.requestToggleShaded(menu.modelIndex) } PlasmaComponents.MenuItem { separator: true } PlasmaComponents.MenuItem { visible: (plasmoid.configuration.groupingStrategy != 0) && menu.visualParent.m.IsWindow === true checkable: true checked: menu.visualParent && menu.visualParent.m.IsGroupable === true text: i18n("Allow this program to be grouped") onClicked: tasksModel.requestToggleGrouping(menu.modelIndex) } } } PlasmaComponents.MenuItem { id: startNewInstanceItem visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true) enabled: visualParent && visualParent.m.LauncherUrlWithoutIcon != null text: i18n("Start New Instance") icon: "system-run" onClicked: tasksModel.requestNewInstance(menu.modelIndex) } PlasmaComponents.MenuItem { separator: true visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true && root.showWindowActions) } //// NEW Launchers Mechanism PlasmaComponents.MenuItem { id: launcherToggleAction visible: visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true && (activityInfo.numberOfRunningActivities < 2) //&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable enabled: visualParent && get(atm.LauncherUrlWithoutIcon) !== "" checkable: true text: i18nc("Toggle action for showing a launcher button while the application is not running", "&Pin") onClicked: { if (tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) != -1) { var launcher = get(atm.LauncherUrl); if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, latteDock.launchersGroup, launcher); } else { root.launcherForRemoval = launcher; tasksModel.requestRemoveLauncher(launcher); root.launchersUpdatedFor(launcher); } } else { var launcher = get(atm.LauncherUrl); if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.addLauncher(root.managedLayoutName, latteDock.launchersGroup, launcher); } else { tasksModel.requestAddLauncher(launcher); root.launchersUpdatedFor(launcher); } } } } PlasmaComponents.MenuItem { id: showLauncherInActivitiesItem text: i18n("&Pin") visible: visualParent && (!visualParent.isSeparator || (visualParent.isSeparator && root.editMode)) // && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable && (activityInfo.numberOfRunningActivities >= 2) Connections { target: activityInfo onNumberOfRunningActivitiesChanged: activitiesDesktopsMenu.refresh() } PlasmaComponents.ContextMenu { id: activitiesLaunchersMenu visualParent: showLauncherInActivitiesItem.action function refresh() { clearMenuItems(); if (menu.visualParent === null) return; var createNewItem = function(id, title, url, activities) { var result = menu.newMenuItem(activitiesLaunchersMenu); result.text = title; result.visible = true; result.checkable = true; result.checked = activities.some(function(activity) { return activity === id }); result.clicked.connect( function() { if (result.checked) { if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.addLauncherToActivity(root.managedLayoutName, latteDock.launchersGroup, url, id); } else { if (id !== tasksModel.activity && (activities[0] === "00000000-0000-0000-0000-000000000000")) { root.launcherForRemoval = url; } tasksModel.requestAddLauncherToActivity(url, id); root.launchersUpdatedFor(url); } } else { if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.removeLauncherFromActivity(root.managedLayoutName, latteDock.launchersGroup, url, id); } else { if (id === tasksModel.activity) { root.launcherForRemoval = url; } tasksModel.requestRemoveLauncherFromActivity(url, id); root.launchersUpdatedFor(url); } } } ); return result; } if (menu.visualParent === null) return; var url = menu.get(atm.LauncherUrlWithoutIcon); var activities = tasksModel.launcherActivities(url); var NULL_UUID = "00000000-0000-0000-0000-000000000000"; createNewItem(NULL_UUID, i18n("On All Activities"), url, activities); if (activityInfo.numberOfRunningActivities <= 1) { return; } createNewItem(activityInfo.currentActivity, i18n("On The Current Activity"), url, activities); menu.newSeparator(activitiesLaunchersMenu); var runningActivities = activityInfo.runningActivities(); runningActivities.forEach(function(id) { createNewItem(id, activityInfo.activityName(id), url, activities); }); } Component.onCompleted: { menu.onVisualParentChanged.connect(refresh); refresh(); } } } PlasmaComponents.MenuItem { visible: (visualParent && !visualParent.isSeparator && get(atm.IsLauncher) === true) && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable text: i18nc("Remove launcher button for application shown while it is not running", "Unpin") onClicked: { var launcher = get(atm.LauncherUrlWithoutIcon); if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, latteDock.launchersGroup, launcher); } else { root.launcherForRemoval = launcher tasksModel.requestRemoveLauncher(launcher); root.launchersUpdatedFor(launcher); } } } //////END OF NEW ARCHITECTURE PlasmaComponents.MenuItem { separator: true } PlasmaComponents.MenuItem { id: addInternalSeparatorItem visible: root.editMode icon: "add" text: i18n("Add Separator") onClicked: { var pos=visualParent.itemIndex; root.addInternalSeparatorAtPos(pos); } } PlasmaComponents.MenuItem { id: removeInternalSeparatorItem visible: root.editMode && visualParent.isSeparator icon: "remove" text: i18n("Remove Separator") enabled: parabolicManager.hasInternalSeparator onClicked: { //root.removeLastSeparator(); var launcher = get(atm.LauncherUrlWithoutIcon); if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, latteDock.launchersGroup, launcher); } else { root.launcherForRemoval = launcher; tasksModel.requestRemoveLauncher(launcher); root.launchersUpdatedFor(launcher); } } } PlasmaComponents.MenuItem { separator: true visible: root.editMode } PlasmaComponents.MenuItem { id: layoutsMenuItem action: latteDock ? latteDock.containmentActions()[1] : plasmoid.action("configure") enabled: visible visible: latteDock && latteDock.universalLayoutManager.menuLayouts.length>1 } PlasmaComponents.MenuItem { id: alternativesMenuItem visible: root.editMode && !visualParent.isSeparator text: plasmoid.action("alternatives").text icon: plasmoid.action("alternatives").icon onClicked: plasmoid.action("alternatives").trigger(); } PlasmaComponents.MenuItem { id: addWidgets action: latteDock ? latteDock.containmentActions()[2] : plasmoid.action("configure"); visible: latteDock } PlasmaComponents.MenuItem { id: configureItem action: latteDock ? latteDock.containmentActions()[3] : plasmoid.action("configure") } //! BEGIN: Plasmoid actions when it isnt inside a Latte dock PlasmaComponents.MenuItem { id: removePlasmoid visible: !latteDock && !plasmoid.immutable text: plasmoid.action("remove").text icon: plasmoid.action("remove").icon onClicked: plasmoid.action("remove").trigger(); } PlasmaComponents.MenuItem { id: configurePlasmoid visible: !latteDock && !plasmoid.immutable text: plasmoid.action("configure").text icon: plasmoid.action("configure").icon onClicked: plasmoid.action("configure").trigger(); } //! END: Plasmoid actions when it isnt inside a Latte dock PlasmaComponents.MenuItem { separator: true visible: closeWindowItem.visible } //!move window Close button at the very bottom in order to not alter users workflow //!comparing with the design decisions of other taskmanagers PlasmaComponents.MenuItem { id: closeWindowItem visible: (visualParent && visualParent.m.IsLauncher !== true && visualParent.m.IsStartup !== true) enabled: visualParent && visualParent.m.IsClosable === true text: i18n("Close") icon: "window-close" onClicked: { if (root.zoomFactor>1) { delayWindowRemovalTimer.modelIndex = menu.modelIndex; delayWindowRemovalTimer.start(); } else { tasksModel.requestClose(menu.modelIndex); } } } } diff --git a/plasmoid/package/contents/ui/task/TaskDelegate.qml b/plasmoid/package/contents/ui/task/TaskDelegate.qml index 8b55e151..3f004002 100644 --- a/plasmoid/package/contents/ui/task/TaskDelegate.qml +++ b/plasmoid/package/contents/ui/task/TaskDelegate.qml @@ -1,1565 +1,1569 @@ /* * Copyright 2016 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.0 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.private.taskmanager 0.1 as TaskManagerApplet import org.kde.latte 0.1 as Latte import "animations" as TaskAnimations MouseArea{ id: mainItemContainer visible: false //true//(isStartup && root.durationTime !== 0) ? false : true anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? parent.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? parent.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? parent.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? parent.right : undefined objectName: "TaskDelegate" width: { if (!visible) return 0; if (isSeparator) return root.vertical ? separatorItem.width : (root.dragSource || root.editMode ? 5+root.iconMargin : 0); if (root.vertical) { if (!inAttentionAnimation) return wrapper.width; else return wrapper.maxThickness; } else { return hiddenSpacerLeft.width+wrapper.width+hiddenSpacerRight.width; } } /*onWidthChanged: { console.log("T: " + itemIndex + " - " + launcherUrl + " - " + width + " _ "+ hiddenSpacerLeft.width + " _ " + wrapper.width + " _ " + hiddenSpacerRight.width); }*/ height: { if (!visible) return 0; if (isSeparator) return !root.vertical ? separatorItem.height : (root.dragSource || root.editMode ? 5+root.iconMargin: 0); if (root.vertical) { return hiddenSpacerLeft.height + wrapper.height + hiddenSpacerRight.height; } else { if (!inAttentionAnimation) return wrapper.height; else return wrapper.maxThickness; } } acceptedButtons: Qt.LeftButton | Qt.MidButton | Qt.RightButton hoverEnabled: visible && (!inAnimation) && (!IsStartup) && (!root.taskInAnimation) && (!root.editMode || root.debugLocation)&&(!inBouncingAnimation) && !isSeparator // hoverEnabled: false //opacity : isSeparator && (hiddenSpacerLeft.neighbourSeparator || hiddenSpacerRight.neighbourSeparator) ? 0 : 1 property bool blockWheel: false property bool buffersAreReady: false property bool delayingRemove: ListView.delayRemove property bool scalesUpdatedOnce: false //states that exist in windows in a Group of windows property bool hasActive: isActive property bool hasMinimized: (IsGroupParent === true) ? tasksWindows.hasMinimized : isMinimized property bool hasShown: (IsGroupParent === true) ? tasksWindows.hasShown : !isMinimized property bool inAddRemoveAnimation: true property bool inAnimation: true property bool inAttentionAnimation: false property bool inBlockingAnimation: false property bool inBouncingAnimation: false property bool inFastRestoreAnimation: false property bool inMimicParabolicAnimation: false property real mimicParabolicScale: -1 property bool inPopup: false property bool inRemoveStage: false property bool inWheelAction: false property bool isActive: (IsActive === true) ? true : false property bool isDemandingAttention: (IsDemandingAttention === true) ? true : false property bool isDragged: false property bool isGroupable: (IsGroupable === true) ? true : false property bool isGroupParent: (IsGroupParent === true) ? true : false property bool isForcedHidden: false property bool isLauncher: (IsLauncher === true) ? true : false property bool isMinimized: (IsMinimized === true) ? true : false property bool isSeparator: false property bool isStartup: (IsStartup === true) ? true : false property bool isWindow: (IsWindow === true) ? true : false property bool isZoomed: false property bool canPublishGeometries: (isWindow || isStartup || isGroupParent) && visible && width>=root.iconSize && height>=root.iconSize && !mainItemContainer.delayingRemove && (wrapper.mScale===1 || wrapper.mScale===root.zoomFactor) //dont publish during zoomFactor property bool pressed: false readonly property bool showAttention: isDemandingAttention && plasmoid.status === PlasmaCore.Types.RequiresAttentionStatus ? true : false property int animationTime: root.durationTime * 1.2 * units.shortDuration property int badgeIndicator: 0 //it is used from external apps property int hoveredIndex: icList.hoveredIndex property int itemIndex: index property int lastValidIndex: -1 //used for the removal animation property int lastButtonClicked: -1; property int pressX: -1 property int pressY: -1 property int resistanceDelay: 450 property int spacersMaxSize: Math.max(0,Math.ceil(0.55*root.iconSize) - root.iconMargin) property string activity: tasksModel.activity readonly property var m: model readonly property int pid: model && model.AppPid ? model.AppPid : -1 readonly property string appName: model && model.AppName ? model.AppName : "" property string modelLauncherUrl: (LauncherUrlWithoutIcon && LauncherUrlWithoutIcon !== null) ? LauncherUrlWithoutIcon : "" property string modelLauncherUrlWithIcon: (LauncherUrl && LauncherUrl !== null) ? LauncherUrl : "" property string launcherUrl: "" property string launcherUrlWithIcon: "" property string launcherName: "" property Item tooltipVisualParent: wrapper.titleTooltipVisualParent property Item previewsVisualParent: wrapper.previewsTooltipVisualParent onModelLauncherUrlChanged: { if (modelLauncherUrl !== ""){ launcherUrl = modelLauncherUrl; //!extract the launcherName if possible var nameStarts = launcherUrl.lastIndexOf("/"); if (nameStarts === -1){ nameStarts = launcherUrl.lastIndexOf(":"); } var nameEnds = launcherUrl.lastIndexOf(".desktop"); if (nameStarts!==-1 && nameEnds!==-1 && nameStarts 0 && !isLauncher readonly property bool playingAudio: hasAudioStream && audioStreams.some(function (item) { return !item.corked }) readonly property bool muted: hasAudioStream && audioStreams.every(function (item) { return item.muted }) readonly property int volume: { if (!hasAudioStream){ return 0; } var maxVolume = 0; for (var i=0; i maxVolume) maxVolume = audioStreams[i].volume; } return maxVolume; } ////// property QtObject contextMenu: null property QtObject draggingResistaner: null property QtObject hoveredTimerObj: null signal groupWindowAdded(); signal groupWindowRemoved(); signal checkWindowsStates(); Behavior on opacity { // NumberAnimation { duration: (IsStartup || (IsLauncher) ) ? 0 : 400 } NumberAnimation { duration: root.durationTime*units.longDuration } } TaskWindows{ id: tasksWindows property int previousCount: 0 onWindowsCountChanged: { if (root.showWindowsOnlyFromLaunchers && root.activeIndicator === Latte.Dock.NoneIndicator) { return; } if ((windowsCount >= 2) && (windowsCount > previousCount) && !(mainItemContainer.containsMouse || parabolicManager.neighbourIsHovered(itemIndex)) ){ if(root.dragSource == null) mainItemContainer.groupWindowAdded(); } else if ((windowsCount >=1) &&(windowsCount < previousCount)){ //sometimes this is triggered in dragging with no reason if(root.dragSource == null && !mainItemContainer.delayingRemove) mainItemContainer.groupWindowRemoved(); } if (windowsCount>=1) { mainItemContainer.slotPublishGeometries(); } previousCount = windowsCount; } } Loader { id: isSeparatorRectangle active: (opacityN>0) width: mainItemContainer.width height: mainItemContainer.height anchors.centerIn: separatorItem property real opacityN: isSeparator && root.contextMenu && root.contextMenu.visualParent === mainItemContainer ? 1 : 0 Behavior on opacityN { NumberAnimation { duration: root.durationTime*units.longDuration } } sourceComponent: Rectangle{ anchors.fill: parent opacity: isSeparatorRectangle.opacityN radius: 3 property color tempColor: theme.highlightColor color: tempColor border.width: 1 border.color: theme.highlightColor onTempColorChanged: tempColor.a = 0.35; } } Item{ id:separatorItem anchors.rightMargin: root.position === PlasmaCore.Types.RightPositioned ? localThickMargin : 0 anchors.leftMargin: root.position === PlasmaCore.Types.LeftPositioned ? localThickMargin : 0 anchors.bottomMargin: root.position === PlasmaCore.Types.BottomPositioned ? localThickMargin : 0 anchors.topMargin: root.position === PlasmaCore.Types.TopPositioned ? localThickMargin : 0 anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined anchors.right: root.position === PlasmaCore.Types.RightPositioned ? parent.right : undefined; anchors.left: root.position === PlasmaCore.Types.LeftPositioned ? parent.left : undefined; anchors.top: root.position === PlasmaCore.Types.TopPositioned ? parent.top : undefined; anchors.bottom: root.position === PlasmaCore.Types.BottomPositioned ? parent.bottom : undefined; //opacity: separatorShadow.active || root.internalSeparatorHidden ? 0 : 0.4 opacity: separatorShadow.active || forceHiddenState ? 0 : 0.4 visible: mainItemContainer.isSeparator width: root.vertical ? root.iconSize : (root.dragSource || root.editMode) ? 5+root.iconMargin: 1 height: !root.vertical ? root.iconSize : (root.dragSource || root.editMode) ? 5+root.iconMargin: 1 property int localThickMargin: !root.reverseLinesPosition ? root.statesLineSize + root.thickMarginBase + 4 : root.thickMarginBase + 4 property bool forceHiddenState: false Behavior on opacity { NumberAnimation { duration: root.durationTime*units.longDuration } } function updateForceHiddenState() { if (!isSeparator || root.editMode || root.dragSource) { forceHiddenState = false; } else { var firstPosition = (index>=0) && (index < parabolicManager.firstRealTaskIndex); var sepNeighbour = mainItemContainer.hasNeighbourSeparator(index-1, false); var firstSepFromLastSeparatorsGroup = (index>=0) && (index > parabolicManager.lastRealTaskIndex); forceHiddenState = (firstPosition || sepNeighbour || firstSepFromLastSeparatorsGroup); } } Component.onCompleted: { updateForceHiddenState(); root.hiddenTasksUpdated.connect(updateForceHiddenState); } Component.onDestruction: { root.hiddenTasksUpdated.disconnect(updateForceHiddenState); } onForceHiddenStateChanged: root.separatorsUpdated(); Connections{ target: root onEditModeChanged: separatorItem.updateForceHiddenState(); onDragSourceChanged: separatorItem.updateForceHiddenState(); onSeparatorsUpdated: separatorItem.updateForceHiddenState(); //! During dock sliding-in because the parabolic effect isnt trigerred //! immediately but we wait first the dock to go to its final normal //! place we might miss the activation of the parabolic effect. //! By catching that signal we are trying to solve this. onDockIsShownCompletelyChanged: { if (dockIsShownCompletely && mainItemContainer.containsMouse) { if (root.vertical) { mainItemContainer.mousePosChanged(mainItemContainer.mouseY); } else { mainItemContainer.mousePosChanged(mainItemContainer.mouseX); } } } onGlobalDirectRenderChanged:{ if (root.globalDirectRender && restoreAnimation.running) { // console.log("Cleat Task Scale !!!!"); restoreAnimation.stop(); } } onShowWindowsOnlyFromLaunchersChanged: { if (!root.editMode) { return; } mainItemContainer.updateVisibilityBasedOnLaunchers(); } onInActivityChangeChanged: { if (root.showWindowsOnlyFromLaunchers && !root.inActivityChange) { mainItemContainer.updateVisibilityBasedOnLaunchers(); } } } Rectangle { anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined anchors.right: root.position === PlasmaCore.Types.RightPositioned ? parent.right : undefined; anchors.left: root.position === PlasmaCore.Types.LeftPositioned ? parent.left : undefined; anchors.top: root.position === PlasmaCore.Types.TopPositioned ? parent.top : undefined; anchors.bottom: root.position === PlasmaCore.Types.BottomPositioned ? parent.bottom : undefined; radius: 2 width: root.vertical ? root.iconSize - 8 : 1 height: !root.vertical ? root.iconSize - 8 : 1 color: theme.textColor } } ///Shadow in tasks Loader{ id: separatorShadow anchors.fill: separatorItem active: root.enableShadows && isSeparator opacity: separatorItem.forceHiddenState ? 0 : 0.4 Behavior on opacity { NumberAnimation { duration: root.durationTime*units.longDuration } } sourceComponent: DropShadow{ anchors.fill: parent color: root.appShadowColor fast: true samples: 2 * radius source: separatorItem radius: root.appShadowSize verticalOffset: 2 } } /* Rectangle{ anchors.fill: parent color: "transparent" border.width: 1 border.color: "blue" } */ Flow{ id: taskFlow width: parent.width height: parent.height // a hidden spacer for the first element to add stability // IMPORTANT: hidden spacers must be tested on vertical !!! TaskHiddenSpacer{ id:hiddenSpacerLeft;} TaskWrapper{ id: wrapper } // a hidden spacer on the right for the last item to add stability TaskHiddenSpacer{ id:hiddenSpacerRight; rightSpacer: true } }// Flow with hidden spacers inside /*Rectangle{ anchors.fill: taskFlow color: "transparent" border.width: 1 border.color: "blue" }*/ Component { id: taskInitComponent Timer { id: timer interval: 800 repeat: false onTriggered: { // mainItemContainer.hoverEnabled = true; slotPublishGeometries(); if (latteDock && latteDock.debugModeTimers) { console.log("plasmoid timer: taskInitComponentTimer called..."); } timer.destroy(); } Component.onCompleted: timer.start() } } ////// Values Changes ///// //restore scales when there is no zoom factor for that item or //the mouse is out of the ListView // onItemIndexChanged: { // } onAppNameChanged: updateAudioStreams() onPidChanged: updateAudioStreams() onHasAudioStreamChanged: updateAudioStreams() onCanPublishGeometriesChanged: { if (canPublishGeometries) { slotPublishGeometries(); taskInitComponent.createObject(mainItemContainer); } } onHoveredIndexChanged: { var distanceFromHovered = Math.abs(index - icList.hoveredIndex); /*if( (distanceFromHovered > 1) && (hoveredIndex !== -1)){ if(!isDragged) wrapper.mScale = 1; }*/ if (distanceFromHovered >= 1 && !inAttentionAnimation && !inFastRestoreAnimation && !inMimicParabolicAnimation) { hiddenSpacerLeft.nScale = 0; hiddenSpacerRight.nScale = 0; } } onItemIndexChanged: { if (isSeparator) { root.separatorsUpdated(); } if (itemIndex>=0) lastValidTimer.start(); } onLastValidIndexChanged: { if (lastValidIndex>=0 && lastValidIndex parabolicManager.lastRealTaskIndex)) { parabolicManager.updateTasksEdgesIndexes(); } } if (parabolicManager.hasInternalSeparator) { root.separatorsUpdated(); } } onIsDraggedChanged: { if(isDragged && (!root.editMode)){ root.dragSource = mainItemContainer; dragHelper.startDrag(mainItemContainer, model.MimeType, model.MimeData, model.LauncherUrlWithoutIcon, model.decoration); pressX = -1; pressY = -1; } } onIsMinimizedChanged: { checkWindowsStates(); } onIsActiveChanged: { checkWindowsStates(); } onIsForcedHiddenChanged: root.hiddenTasksUpdated(); onIsSeparatorChanged: { if (isSeparator) { root.separatorsUpdated(); if (parabolicManager.isLauncherToBeMoved(launcherUrl) && itemIndex>=0) { parabolicManager.moveLauncherToCorrectPos(launcherUrl, itemIndex); } } else { root.separatorsUpdated(); } } onLauncherUrlChanged: updateBadge(); ////// End of Values Changes ///// ///////////////// Mouse Area Events /////////////////// onEntered: { if (root.editMode) return; root.stopCheckRestoreZoomTimer(); if (restoreAnimation.running) { restoreAnimation.stop(); } // console.log("entered task:" + icList.hoveredIndex); if (icList.hoveredIndex === -1 && root.dockHoveredIndex ===-1) { root.startDirectRenderDelayerDuringEntering(); } if ((icList.hoveredIndex !== itemIndex) && isLauncher && windowsPreviewDlg.visible) { windowsPreviewDlg.hide(1); } if (!latteDock || (latteDock && !(latteDock.dockIsHidden || latteDock.inSlidingIn || latteDock.inSlidingOut))){ icList.hoveredIndex = index; } if (root.latteDock && (!root.showPreviews)){ var displayText = isWindow ? model.display : model.AppName; var maxCharacters = 80; var fixedDisplayText = displayText.length>maxCharacters ? displayText.substring(0,maxCharacters-1) + "..." : displayText; root.latteDock.showTooltipLabel(mainItemContainer, fixedDisplayText); } if (root.latteDock && root.latteDock.isHalfShown) { return; } /* if((!inAnimation)&&(root.dragSource == null)&&(!root.taskInAnimation) && hoverEnabled){ if (inAttentionAnimation) { var subSpacerScale = (root.zoomFactor-1)/2; hiddenSpacerLeft.nScale = subSpacerScale; hiddenSpacerRight.nScale = subSpacerScale; } if (!inBlockingAnimation || inAttentionAnimation) { if (icList.orientation == Qt.Horizontal){ icList.currentSpot = mouseX; wrapper.calculateScales(mouseX); } else{ icList.currentSpot = mouseY; wrapper.calculateScales(mouseY); } } }*/ } // IMPORTANT: This must be improved ! even for small miliseconds it reduces performance onExited: { mainItemContainer.scalesUpdatedOnce = false; if (root.latteDock && (!root.showPreviews || (root.showPreviews && isLauncher))){ root.latteDock.hideTooltipLabel(); } if(mainItemContainer.contextMenu && mainItemContainer.contextMenu.status == PlasmaComponents.DialogStatus.Open){ ///dont check to restore zooms } else{ if(!inAnimation){ root.startCheckRestoreZoomTimer(); } } /* if(draggingResistaner != null){ draggingResistaner.destroy(); draggingResistaner = null; isDragged = false; }*/ } //! mouseX-Y values are delayed to be updated onEntered events and at the same time //! onPositionChanged signal may be delayed. we can fix this by dont delay at all //! when mouseX-Y is updated based on the plasmoid formFactor function mousePosChanged(mousePos) { if (root.editMode || mousePos<0 || (inBlockingAnimation && !(inAttentionAnimation||inFastRestoreAnimation||inMimicParabolicAnimation))) return; root.stopCheckRestoreZoomTimer(); if (root.latteDock && root.latteDock.isHalfShown) { return; } //! show previews if(root.showPreviews && !windowsPreviewDlg.visible && windowsPreviewDlg.activeItem !== mainItemContainer){ if (hoveredTimerObj) { //! dont delay showing preview in normal states, //! that is when the dock wasnt hidden if (!hoveredTimerObj.running) { hoveredTimerObj.start(); } } else { if (!root.disableAllWindowsFunctionality) { hoveredTimerObj = hoveredTimerComponent.createObject(mainItemContainer); } } } if((inAnimation == false)&&(!root.taskInAnimation)&&(!root.disableRestoreZoom) && hoverEnabled){ if (icList.hoveredIndex === -1 && root.dockHoveredIndex ===-1) { root.startDirectRenderDelayerDuringEntering(); } if (!latteDock || (latteDock && !(latteDock.dockIsHidden || latteDock.inSlidingIn || latteDock.inSlidingOut))){ icList.hoveredIndex = index; } if (!root.globalDirectRender && !root.directRenderDelayerIsRunning) { root.setGlobalDirectRender(true); } if( ((wrapper.mScale == 1 || wrapper.mScale === root.zoomFactor) && !root.globalDirectRender) || root.globalDirectRender || !scalesUpdatedOnce) { if(root.dragSource == null){ var step = Math.abs(icList.currentSpot-mousePos); if (step >= root.animationStep){ icList.currentSpot = mousePos; wrapper.calculateScales(mousePos); } } } } } onMouseXChanged: { if (!root.vertical) { mousePosChanged(mouseX); } } onMouseYChanged: { if (root.vertical) { mousePosChanged(mouseY); } } onPositionChanged: { if (root.editMode || (inBlockingAnimation && !(inAttentionAnimation||inFastRestoreAnimation||inMimicParabolicAnimation))) return; if (root.latteDock && root.latteDock.isHalfShown) { return; } if((inAnimation == false)&&(!root.taskInAnimation)&&(!root.disableRestoreZoom) && hoverEnabled){ // mouse.button is always 0 here, hence checking with mouse.buttons if (pressX != -1 && mouse.buttons == Qt.LeftButton && isDragged && !root.editMode && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y) ) { root.dragSource = mainItemContainer; dragHelper.startDrag(mainItemContainer, model.MimeType, model.MimeData, model.LauncherUrlWithoutIcon, model.decoration); pressX = -1; pressY = -1; } } } onContainsMouseChanged:{ if(!containsMouse){ // hiddenSpacerLeft.nScale = 0; // hiddenSpacerRight.nScale = 0; if(!inAnimation) pressed=false; } ////window previews///////// if (isWindow) { if(containsMouse && (root.showPreviews || (!root.showPreviews && root.highlightWindows)) && Latte.WindowSystem.compositingActive){ if (hoveredTimerObj) { hoveredTimerObj.restart(); } else { if (!root.disableAllWindowsFunctionality) { hoveredTimerObj = hoveredTimerComponent.createObject(mainItemContainer); } } } else{ if (hoveredTimerObj){ hoveredTimerObj.stop(); hoveredTimerObj.destroy(); } } } ////disable hover effect/// if (isWindow && root.highlightWindows && !containsMouse) { root.windowsHovered(model.LegacyWinIdList, false); } } onPressed: { //console.log("Pressed Task Delegate.."); if (Latte.WindowSystem.compositingActive && !Latte.WindowSystem.isPlatformWayland) { windowsPreviewDlg.hide(2); } var modAccepted = modifierAccepted(mouse); if ((mouse.button == Qt.LeftButton)||(mouse.button == Qt.MidButton) || modAccepted) { lastButtonClicked = mouse.button; pressed = true; pressX = mouse.x; pressY = mouse.y; if(draggingResistaner == null && !modAccepted) draggingResistaner = resistanerTimerComponent.createObject(mainItemContainer); } else if (mouse.button == Qt.RightButton && !modAccepted){ // When we're a launcher, there's no window controls, so we can show all // places without the menu getting super huge. if (model.IsLauncher === true && !isSeparator) { showContextMenu({showAllPlaces: true}) } else { showContextMenu(); } //root.createContextMenu(mainItemContainer).show(); } if (hoveredTimerObj){ hoveredTimerObj.restart(); /*hoveredTimerObj.stop(); hoveredTimerObj.destroy();*/ } } onReleased: { //console.log("Released Task Delegate..."); if (draggingResistaner != null){ draggingResistaner.destroy(); draggingResistaner = null; } if(pressed && (!inBlockingAnimation || inAttentionAnimation) && !isSeparator){ if (modifierAccepted(mouse) && !root.disableAllWindowsFunctionality){ if( !mainItemContainer.isLauncher){ if (root.modifierClickAction == Latte.Dock.NewInstance) { tasksModel.requestNewInstance(modelIndex()); } else if (root.modifierClickAction == Latte.Dock.Close) { tasksModel.requestClose(modelIndex()); } else if (root.modifierClickAction == Latte.Dock.ToggleMinimized) { tasksModel.requestToggleMinimized(modelIndex()); } else if ( root.modifierClickAction == Latte.Dock.CycleThroughTasks) { if (isGroupParent) tasksWindows.activateNextTask(); else activateTask(); } else if (root.modifierClickAction == Latte.Dock.ToggleGrouping) { tasksModel.requestToggleGrouping(modelIndex()); } } else { activateTask(); } } else if (mouse.button == Qt.MidButton && !root.disableAllWindowsFunctionality){ if( !mainItemContainer.isLauncher){ if (root.middleClickAction == Latte.Dock.NewInstance) { tasksModel.requestNewInstance(modelIndex()); } else if (root.middleClickAction == Latte.Dock.Close) { tasksModel.requestClose(modelIndex()); } else if (root.middleClickAction == Latte.Dock.ToggleMinimized) { tasksModel.requestToggleMinimized(modelIndex()); } else if ( root.middleClickAction == Latte.Dock.CycleThroughTasks) { if (isGroupParent) tasksWindows.activateNextTask(); else activateTask(); } else if (root.middleClickAction == Latte.Dock.ToggleGrouping) { tasksModel.requestToggleGrouping(modelIndex()); } } else { activateTask(); } } else if (mouse.button == Qt.LeftButton){ activateTask(); } backend.cancelHighlightWindows(); } pressed = false; if(!inAnimation) { startCheckRestoreZoomTimer(3*units.longDuration); } } onWheel: { if (isSeparator || !root.mouseWheelActions || blockWheel || inWheelAction || inBouncingAnimation || (latteDock && (latteDock.dockIsHidden || latteDock.inSlidingIn || latteDock.inSlidingOut))){ return; } var angle = wheel.angleDelta.y / 8; blockWheel = true; scrollDelayer.start(); //positive direction if (angle > 12) { if (isLauncher || root.disableAllWindowsFunctionality) { inWheelAction = true; wrapper.runLauncherAnimation(); } else if (isGroupParent) { tasksWindows.activateNextTask(); } else { var taskIndex = modelIndex(); if (isMinimized) { inWheelAction = true; tasksModel.requestToggleMinimized(taskIndex); wheelActionDelayer.start(); } tasksModel.requestActivate(taskIndex); } //negative direction } else if (angle < -12) { if (isLauncher || root.disableAllWindowsFunctionality) { // do nothing } else if (isGroupParent) { tasksWindows.activatePreviousTask(); } else { var taskIndex = modelIndex(); if (isMinimized) { inWheelAction = true; tasksModel.requestToggleMinimized(taskIndex); wheelActionDelayer.start(); } tasksModel.requestActivate(taskIndex); } } } //! A timer is needed in order to handle also touchpads that probably //! send too many signals very fast. This way the signals per sec are limited. //! The user needs to have a steady normal scroll in order to not //! notice a annoying delay Timer{ id: scrollDelayer interval: 400 onTriggered: mainItemContainer.blockWheel = false; } ///////////////// End Of Mouse Area Events /////////////////// ///// Handlers for Signals ///// function animationStarted(){ // console.log("Animation started: " + index); inAnimation = true; } function animationEnded(){ // console.log("Animation ended: " + index); inAnimation = false; } function clearZoom(){ if(!root) return; if (root.hoveredIndex === -1 && root.dockHoveredIndex === -1) { restoreAnimation.start(); } } function handlerDraggingFinished(){ isDragged = false; } ///// End of Handlers ////// ///// Helper functions ///// function activateNextTask() { tasksWindows.activateNextTask(); } function activateTask() { if( mainItemContainer.isLauncher || root.disableAllWindowsFunctionality){ if (Latte.WindowSystem.compositingActive) { wrapper.runLauncherAnimation(); } else { launcherAction(); } } else{ if (model.IsGroupParent) { if (Latte.WindowSystem.compositingActive && backend.canPresentWindows()) { root.presentWindows(model.LegacyWinIdList); } else { if ((windowsPreviewDlg.visualParent === previewsVisualParent)&&(windowsPreviewDlg.visible)) { windowsPreviewDlg.hide(3); } else { preparePreviewWindow(false); windowsPreviewDlg.show(mainItemContainer); } } } else { if (IsMinimized === true) { var i = modelIndex(); tasksModel.requestToggleMinimized(i); tasksModel.requestActivate(i); } else if (IsActive === true) { tasksModel.requestToggleMinimized(modelIndex()); } else { tasksModel.requestActivate(modelIndex()); } } } } function hasNeighbourSeparator(ind, positive) { var cursor = ind; while (((!positive && cursor>=0) || (positive && cursor<=root.tasksCount-1)) && parabolicManager.taskIsForcedHidden(cursor) ) { cursor = positive ? cursor + 1 : cursor - 1; } return parabolicManager.taskIsSeparator(cursor); } function preparePreviewWindow(hideClose){ windowsPreviewDlg.visualParent = previewsVisualParent; toolTipDelegate.parentTask = mainItemContainer; toolTipDelegate.rootIndex = tasksModel.makeModelIndex(itemIndex, -1); toolTipDelegate.hideCloseButtons = hideClose; toolTipDelegate.appName = Qt.binding(function() { return model.AppName; }); if (!isLauncher) { toolTipDelegate.pidParent = Qt.binding(function() { return model.AppPid; }); } else { toolTipDelegate.pidParent = -1; } toolTipDelegate.windows = Qt.binding(function() { return model.LegacyWinIdList; }); toolTipDelegate.isGroup = Qt.binding(function() { return model.IsGroupParent == true; }); toolTipDelegate.icon = Qt.binding(function() { return model.decoration; }); toolTipDelegate.launcherUrl = Qt.binding(function() { return model.LauncherUrlWithoutIcon; }); toolTipDelegate.isLauncher = Qt.binding(function() { return model.IsLauncher == true; }); toolTipDelegate.isMinimizedParent = Qt.binding(function() { return model.IsMinimized == true; }); toolTipDelegate.displayParent = Qt.binding(function() { return model.display; }); toolTipDelegate.genericName = Qt.binding(function() { return model.GenericName; }); toolTipDelegate.virtualDesktopParent = Qt.binding(function() { return model.VirtualDesktop != undefined ? model.VirtualDesktop : 0; }); toolTipDelegate.isOnAllVirtualDesktopsParent = Qt.binding(function() { return model.IsOnAllVirtualDesktops == true; }); toolTipDelegate.activitiesParent = Qt.binding(function() { return model.Activities; }); } function launcherAction(){ // if ((lastButtonClicked == Qt.LeftButton)||(lastButtonClicked == Qt.MidButton)){ if (Latte.WindowSystem.compositingActive) { inBouncingAnimation = true; root.addWaitingLauncher(mainItemContainer.launcherUrl); } if (root.disableAllWindowsFunctionality) { tasksModel.requestNewInstance(modelIndex()); } else { tasksModel.requestActivate(modelIndex()); } } ///window previews/// function generateSubText(task) { var subTextEntries = new Array(); if (!plasmoid.configuration.showOnlyCurrentDesktop && virtualDesktopInfo.numberOfDesktops > 1 && model.IsOnAllVirtualDesktops !== true && model.VirtualDesktop != -1 && model.VirtualDesktop != undefined) { subTextEntries.push(i18n("On %1", virtualDesktopInfo.desktopNames[model.VirtualDesktop - 1])); } if (model.Activities == undefined) { return subTextEntries.join("\n"); } if (model.Activities.length == 0 && activityInfo.numberOfRunningActivities > 1) { subTextEntries.push(i18nc("Which virtual desktop a window is currently on", "Available on all activities")); } else if (model.Activities.length > 0) { var activityNames = new Array(); for (var i = 0; i < model.Activities.length; i++) { var activity = model.Activities[i]; if (plasmoid.configuration.showOnlyCurrentActivity) { if (activity != activityInfo.currentActivity) { activityNames.push(activityInfo.activityName(model.Activities[i])); } } else if (activity != activityInfo.currentActivity) { activityNames.push(activityInfo.activityName(model.Activities[i])); } } if (plasmoid.configuration.showOnlyCurrentActivity) { if (activityNames.length > 0) { subTextEntries.push(i18nc("Activities a window is currently on (apart from the current one)", "Also available on %1", activityNames.join(", "))); } } else if (activityNames.length > 0) { subTextEntries.push(i18nc("Which activities a window is currently on", "Available on %1", activityNames.join(", "))); } } return subTextEntries.join("\n"); } ///window previews//// function launcherIsPresent(url) { var activities = tasksModel.launcherActivities(url); var NULL_UUID = "00000000-0000-0000-0000-000000000000"; if (activities.indexOf(NULL_UUID) !== -1 || activities.indexOf(activityInfo.currentActivity) !== -1) return true; return false; } function modelIndex(){ return tasksModel.makeModelIndex(index); } function showContextMenu(args) { if (isSeparator && !root.editMode) return; if (!root.contextMenu) { contextMenu = root.createContextMenu(mainItemContainer, modelIndex(), args); contextMenu.show(); } else { - root.contextMenu.close(); + //! make sure that context menu isnt deleted multiple times and creates a crash + //! bug case: 397635 + var cMenu = root.contextMenu; + root.contextMenu = null; + cMenu.destroy(); } } function modifierAccepted(mouse){ if (mouse.modifiers & root.modifierQt){ if ((mouse.button === Qt.LeftButton && root.modifierClick === Latte.Dock.LeftClick) || (mouse.button === Qt.MiddleButton && root.modifierClick === Latte.Dock.MiddleClick) || (mouse.button === Qt.RightButton && root.modifierClick === Latte.Dock.RightClick)) return true; } return false; } function setBlockingAnimation(value){ inBlockingAnimation = value; } function slotMimicEnterForParabolic(){ if (containsMouse) { if (inMimicParabolicAnimation) { mimicParabolicScale = root.zoomFactor; } wrapper.calculateScales(icList.currentSpot); } } function slotShowPreviewForTasks(group) { if (group === mainItemContainer && !windowsPreviewDlg.visible) { preparePreviewWindow(true); windowsPreviewDlg.show(mainItemContainer); } } function slotPublishGeometries() { //! this way we make sure that layouts that are in different activities that the current layout //! dont publish their geometries if ( canPublishGeometries && (!latteDock || (latteDock && currentLayout && latteDock.universalLayoutManager && currentLayout.name === latteDock.universalLayoutManager.currentLayoutName))) { var globalChoords = backend.globalRect(mainItemContainer); //! Magic Lamp effect doesnt like coordinates outside the screen and //! width,heights of zero value... So we now normalize the geometries //! sent in order to avoid such circumstances if (root.vertical) { globalChoords.width = 1; globalChoords.height = Math.max(root.iconSize, mainItemContainer.height); } else { globalChoords.height = 1; globalChoords.width = Math.max(root.iconSize, mainItemContainer.width); } if (root.position === PlasmaCore.Types.BottomPositioned) { globalChoords.y = plasmoid.screenGeometry.y+plasmoid.screenGeometry.height-1; } else if (root.position === PlasmaCore.Types.TopPositioned) { globalChoords.y = plasmoid.screenGeometry.y+1; } else if (root.position === PlasmaCore.Types.LeftPositioned) { globalChoords.x = plasmoid.screenGeometry.x+1; } else if (root.position === PlasmaCore.Types.RightPositioned) { globalChoords.x = plasmoid.screenGeometry.x+plasmoid.screenGeometry.width - 1; } tasksModel.requestPublishDelegateGeometry(mainItemContainer.modelIndex(), globalChoords, mainItemContainer); } } function slotWaitingLauncherRemoved(launch) { if ((isWindow || isStartup || isLauncher) && !visible && launch === launcherUrl) { wrapper.mScale = 1; visible = true; } } function updateAudioStreams() { if (root.dragSource !== null) { audioStreams = []; return; } var pa = pulseAudio.item; if (!pa) { audioStreams = []; return; } var streams = pa.streamsForPid(mainItemContainer.pid); if (streams.length) { pa.registerPidMatch(mainItemContainer.appName); } else { // We only want to fall back to appName matching if we never managed to map // a PID to an audio stream window. Otherwise if you have two instances of // an application, one playing and the other not, it will look up appName // for the non-playing instance and erroneously show an indicator on both. if (!pa.hasPidMatch(mainItemContainer.appName)) { var streams_result; streams_result = pa.streamsForAppName(mainItemContainer.appName); if (streams_result.length===0 && launcherName !== "") { streams_result = pa.streamsForAppName(launcherName); } streams = streams_result; } } // fix a binding loop concerning audiostreams, the audiostreams // should be updated only when they have changed var changed = false; if (streams.length !== audioStreams.length) { changed = true; } else { for(var i=0; i= 0){ mainItemContainer.lastValidIndex = mainItemContainer.itemIndex; if (root.showWindowsOnlyFromLaunchers) { parabolicManager.updateTasksEdgesIndexes(); } } if (latteDock && latteDock.debugModeTimers) { console.log("plasmoid timer: lastValidTimer called..."); } } } // The best solution in order to catch when the wheel action ended is to // track the isMinimized state, but when the user has enabled window previews // at all times that flag doesnt work Timer { id: wheelActionDelayer interval: 200 onTriggered: { mainItemContainer.inWheelAction = false; if (latteDock && latteDock.debugModeTimers) { console.log("plasmoid timer: wheelActionDelayer called..."); } } } ///Item's Removal Animation ListView.onRemove: TaskAnimations.TaskRealRemovalAnimation{ id: taskRealRemovalAnimation } }// main Item