Warning, /plasma/latte-dock/plasmoid/package/contents/ui/task/TaskItem.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2016 Smith AR <audoban@openmailbox.org>
0003     SPDX-FileCopyrightText: 2016 Michail Vourlakos <mvourlakos@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 import QtQuick 2.0
0008 import QtQuick.Layouts 1.1
0009 import QtGraphicalEffects 1.0
0010 
0011 import org.kde.plasma.core 2.0 as PlasmaCore
0012 import org.kde.plasma.components 2.0 as PlasmaComponents
0013 import org.kde.plasma.plasmoid 2.0
0014 
0015 import org.kde.plasma.private.taskmanager 0.1 as TaskManagerApplet
0016 
0017 import org.kde.latte.core 0.2 as LatteCore
0018 import org.kde.latte.private.tasks 0.1 as LatteTasks
0019 
0020 import org.kde.latte.abilities.items 0.1 as AbilityItem
0021 
0022 import "animations" as TaskAnimations
0023 
0024 AbilityItem.BasicItem {
0025     id: taskItem
0026     visible: false
0027     objectName: "TaskItem"
0028 
0029     isHidden: !visible || isForcedHidden
0030 
0031     isHiddenSpacerForcedShow: taskItem.inAttentionBuiltinAnimation
0032     isHiddenSpacerAnimated: showWindowAnimation.running
0033                             || root.inActivityChange
0034                             || taskItem.inRemoveStage
0035                             || (taskItem.containsMouse && inAttentionBuiltinAnimation && taskItem.parabolicItem.zoom!==taskItem.abilities.parabolic.factor.zoom)
0036 
0037     isMonochromaticForcedContentItem: plasmoid.configuration.forceMonochromaticIcons
0038     monochromizedItem: taskIcon.monochromizedItem
0039 
0040     isSeparatorHidden: isSeparator && (lastValidIndex > taskItem.abilities.indexer.lastVisibleItemIndex)
0041     isSeparatorInRealLength: isSeparator && root.dragSource
0042 
0043     containsMouse: taskMouseArea.containsMouse || parabolicAreaContainsMouse
0044     thinTooltipText: {
0045         if (root.showPreviews && !isLauncher) {
0046             return "";
0047         }
0048 
0049         return isWindow ? model.display : model.AppName;
0050     }
0051 
0052     preserveIndicatorInInitialPosition: inBouncingAnimation || inAttentionBuiltinAnimation || inNewWindowBuiltinAnimation
0053 
0054     parabolicItem.isParabolicEventBlocked: root.dragSource
0055                                            || !hoverEnabled
0056                                            || !taskItem.abilities.myView.isShownFully
0057                                            || inAnimation
0058                                            || (inBlockingAnimation && !inAttentionBuiltinAnimation)
0059     parabolicItem.isUpdatingOnlySpacers: inAttentionBuiltinAnimation || inBouncingAnimation
0060 
0061     property alias hoverEnabled: taskMouseArea.hoverEnabled
0062     property alias pressed: taskMouseArea.pressed
0063 
0064     property bool delayingRemove: ListView.delayRemove
0065     //states that exist in windows in a Group of windows
0066     property bool hasActive: isActive
0067     property bool hasMinimized: (IsGroupParent === true) ? subWindows.hasMinimized : isMinimized
0068     property bool hasShown: (IsGroupParent === true) ? subWindows.hasShown : !isMinimized && isWindow
0069     property bool inAttention: isDemandingAttention && plasmoid.status === PlasmaCore.Types.NeedsAttentionStatus ? true : false
0070 
0071     /*animations flags*/
0072     property bool inAnimation: true
0073     property bool inAddRemoveAnimation: true
0074     property bool inAttentionBuiltinAnimation: false
0075     property bool inBlockingAnimation: false
0076     property bool inBouncingAnimation: false
0077     property bool inNewWindowBuiltinAnimation: false
0078     property bool inPopup: false
0079     property bool inRemoveStage: false
0080 
0081     property bool isLauncherBuiltinAnimationRunning: false
0082     property bool isLauncherAnimationRunning: isLauncherBuiltinAnimationRunning
0083                                               || (taskItem.abilities.indicators.info.providesTaskLauncherAnimation && isIndicatorTaskLauncherAnimationRunning)
0084 
0085     //! after clicking to show/hide preview enter events are trigerred even though the should not
0086     property bool showPreviewsIsBlockedFromReleaseEvent: false
0087 
0088     property bool isAbleToShowPreview: true
0089     property bool isActive: (IsActive === true) ? true : false
0090     property bool isDemandingAttention: (IsDemandingAttention === true) ? true : false
0091     property bool isDragged: false
0092     property bool isGroupable: (IsGroupable === true) ? true : false
0093     property bool isGroupParent: (IsGroupParent === true) ? true : false
0094     property bool isForcedHidden: false
0095     property bool isLauncher: (IsLauncher === true) ? true : false
0096     property bool hasShownLauncher:  (taskItem.abilities.launchers.inCurrentActivity(taskItem.launcherUrl)
0097                                       || taskItem.abilities.launchers.inCurrentActivity(taskItem.launcherUrlWithIcon))
0098                                      && !root.inActivityChange /*update trigger when changing current activity*/
0099     property bool isMinimized: (IsMinimized === true) ? true : false
0100     property bool isStartup: (IsStartup === true) ? true : false
0101     property bool isWindow: (IsWindow === true) ? true : false
0102 
0103     property bool canPublishGeometries: (isWindow || isStartup || isGroupParent) && visible && width>=taskItem.abilities.metrics.iconSize && height>=taskItem.abilities.metrics.iconSize
0104                                         && !taskItem.delayingRemove
0105                                         && (taskItem.parabolicItem.zoom===1 || taskItem.parabolicItem.zoom===taskItem.abilities.parabolic.factor.zoom) //don't publish during zoom animation
0106 
0107     property bool hoveredFromDragging: (mouseHandler.hoveredItem === taskItem) || (mouseHandler.ignoredItem === taskItem)
0108 
0109     property bool wheelIsBlocked: false
0110     property bool hasAddedWaitingLauncher: false
0111 
0112     property int badgeIndicator: 0 //it is used from external apps
0113     property int lastValidIndex: -1 //used for the removal animation
0114     property int lastButtonClicked: -1;
0115     property int pressX: -1
0116     property int pressY: -1
0117     property int resistanceDelay: 450
0118     property int windowsCount: subWindows.windowsCount
0119     property int windowsMinimizedCount: subWindows.windowsMinimized
0120 
0121     property string activity: tasksModel.activity
0122 
0123     readonly property var m: model
0124     readonly property int pid: model && model.AppPid ? model.AppPid : -1
0125     readonly property string appName: model && model.AppName ? model.AppName : ""
0126 
0127     property string modelLauncherUrl: (LauncherUrlWithoutIcon && LauncherUrlWithoutIcon !== null) ? LauncherUrlWithoutIcon : ""
0128     property string modelLauncherUrlWithIcon: (LauncherUrl && LauncherUrl !== null) ? LauncherUrl : ""
0129     property string launcherUrl: ""
0130     property string launcherUrlWithIcon: ""
0131     property string launcherName: ""
0132 
0133     readonly property alias hoveredTimer: taskMouseArea.hoveredTimer
0134     readonly property alias mouseArea: taskMouseArea
0135     readonly property alias subWindows: subWindows
0136 
0137     readonly property alias showWindowAnimation: _showWindowAnimation
0138 
0139     //! Indicator Properties
0140     indicator.isTask: true
0141     indicator.isLauncher: taskItem.isLauncher || root.disableAllWindowsFunctionality
0142     indicator.isStartup: !root.disableAllWindowsFunctionality && taskItem.isStartup
0143     indicator.isWindow: !root.disableAllWindowsFunctionality && taskItem.isWindow
0144 
0145     indicator.isActive: !root.disableAllWindowsFunctionality && (taskItem.hasActive
0146                                                                  || (root.showPreviews
0147                                                                      && (taskItem.isWindow || taskItem.isGroupParent)
0148                                                                      && windowsPreviewDlg.activeItem
0149                                                                      && (windowsPreviewDlg.activeItem === taskItem)) )
0150 
0151     indicator.isGroup: !root.disableAllWindowsFunctionality && taskItem.isGroupParent
0152     indicator.isHovered: taskItem.containsMouse || (windowsPreviewDlg.containsMouse && (toolTipDelegate.parentTask === taskItem))
0153     indicator.isMinimized: !root.disableAllWindowsFunctionality && taskItem.isMinimized
0154     indicator.isPressed: taskItem.pressed
0155     indicator.inAttention: !root.disableAllWindowsFunctionality && taskItem.inAttention
0156     indicator.inRemoving: taskItem.inRemoveStage
0157 
0158     indicator.isSquare: true
0159 
0160     indicator.hasActive: !root.disableAllWindowsFunctionality && taskItem.hasActive
0161     indicator.hasMinimized: !root.disableAllWindowsFunctionality && taskItem.hasMinimized
0162     indicator.hasShown: !root.disableAllWindowsFunctionality && taskItem.hasShown
0163     indicator.windowsCount: !root.disableAllWindowsFunctionality ? taskItem.windowsCount : 0
0164     indicator.windowsMinimizedCount: !root.disableAllWindowsFunctionality ? taskItem.windowsMinimizedCount : 0
0165 
0166     indicator.scaleFactor: taskItem.parabolicItem.zoom
0167     indicator.panelOpacity: taskItem.abilities.myView.backgroundOpacity
0168     indicator.shadowColor: taskItem.abilities.myView.itemShadow.shadowSolidColor
0169 
0170     indicator.progressVisible: taskIcon.progressVisible /*since 0.9.2*/
0171     indicator.progress: taskIcon.progress /*since 0.9.2*/
0172 
0173     indicator.palette: taskItem.abilities.myView.palette
0174 
0175     indicator.iconBackgroundColor: taskIcon.backgroundColor
0176     indicator.iconGlowColor: taskIcon.glowColor
0177     //! Indicator Properties
0178 
0179     onModelLauncherUrlChanged: {
0180         if (modelLauncherUrl !== ""){
0181             launcherUrl = modelLauncherUrl;
0182 
0183             //!extract the launcherName if possible
0184             var nameStarts = launcherUrl.lastIndexOf("/");
0185             if (nameStarts === -1){
0186                 nameStarts = launcherUrl.lastIndexOf(":");
0187             }
0188 
0189             var nameEnds = launcherUrl.lastIndexOf(".desktop");
0190 
0191             if (nameStarts!==-1 && nameEnds!==-1 && nameStarts<nameEnds) {
0192                 launcherName = launcherUrl.substring(nameStarts+1,nameEnds);
0193             }
0194         }
0195 
0196         if (taskItem.abilities.launchers.isSeparator(modelLauncherUrl)){
0197             isSeparator = true;
0198         } else {
0199             isSeparator = false;
0200         }
0201     }
0202 
0203     onModelLauncherUrlWithIconChanged: {
0204         if (modelLauncherUrlWithIcon !== ""){
0205             launcherUrlWithIcon = modelLauncherUrlWithIcon;
0206         }
0207     }
0208 
0209     onHoveredFromDraggingChanged: {
0210         if (hoveredFromDragging) {
0211             scrollableList.autoScrollFor(taskItem, true);
0212         }
0213     }
0214 
0215     ////// Audio streams //////
0216     property Item audioStreamOverlay
0217     property var audioStreams: []
0218     readonly property bool hasAudioStream: root.showAudioBadge && audioStreams.length > 0 && !isLauncher
0219     readonly property bool playingAudio: hasAudioStream && audioStreams.some(function (item) {
0220         return !item.corked
0221     })
0222 
0223     readonly property bool muted: hasAudioStream && audioStreams.every(function (item) {
0224         return item.muted
0225     })
0226 
0227     readonly property int volume: {
0228         if (!hasAudioStream){
0229             return 0;
0230         }
0231 
0232         var maxVolume = 0;
0233         for (var i=0; i<audioStreams.length; ++i){
0234             if (audioStreams[i].volume > maxVolume)
0235                 maxVolume = audioStreams[i].volume;
0236         }
0237 
0238         return maxVolume;
0239     }
0240 
0241     //! Content Item
0242     contentItem: TaskIcon{
0243         id:taskIcon
0244     }
0245     //////
0246 
0247     property QtObject contextMenu: null
0248 
0249     signal checkWindowsStates();
0250 
0251     SubWindows{
0252         id: subWindows
0253 
0254         property int previousCount: 0
0255 
0256         onWindowsCountChanged: {
0257             if (root.disableAllWindowsFunctionality) {
0258                 return;
0259             }
0260 
0261             if ((windowsCount >= 2)
0262                     && (windowsCount > previousCount)
0263                     && !(taskItem.containsMouse)
0264                     && !root.dragSource ){
0265                 taskItem.taskGroupedWindowAdded();
0266             } else if ((windowsCount >= 1)
0267                        && (windowsCount < previousCount)
0268                        && !root.dragSource
0269                        && !taskItem.delayingRemove){
0270                 //sometimes this is triggered in dragging with no reason
0271                 taskItem.taskGroupedWindowRemoved();
0272             }
0273 
0274             if (windowsCount>=1) {
0275                 taskItem.slotPublishGeometries();
0276             }
0277 
0278             //! workaround in order to update correctly the previousCount
0279             //! windowsCount can not return to zero because is such case
0280             //! the window task is removed and the launcher is added from
0281             //! libtaskmanager
0282             if (windowsCount>=1) {
0283                 previousCount = windowsCount;
0284             }
0285         }
0286     }
0287 
0288     TaskMouseArea {
0289         id: taskMouseArea
0290     }
0291 
0292     Timer {
0293         id: publishGeometryTimer
0294         interval: 800
0295         repeat: false
0296 
0297         onTriggered: {
0298             slotPublishGeometries();
0299 
0300             if (taskItem.abilities.debug.timersEnabled) {
0301                 console.log("plasmoid timer: publishGeometryTimer called...");
0302             }
0303         }
0304     }
0305 
0306     ////// Values Changes /////
0307     //restore scales when there is no zoom factor for that item or
0308     //the mouse is out of the ListView
0309     // onItemIndexChanged: {
0310     //  }
0311 
0312     onAppNameChanged: updateAudioStreams()
0313     onPidChanged: updateAudioStreams()
0314     onHasAudioStreamChanged: updateAudioStreams()
0315 
0316     onCanPublishGeometriesChanged: {
0317         if (canPublishGeometries) {
0318             slotPublishGeometries();
0319             publishGeometryTimer.start();
0320         }
0321     }
0322 
0323     onItemIndexChanged: {
0324         if (itemIndex>=0) {
0325             lastValidTimer.start();
0326         }
0327     }
0328 
0329     onIsDraggedChanged: {
0330         if (isDragged){
0331             taskItem.contentItem.monochromizedItem.grabToImage((result) => {
0332                 root.dragSource = taskItem;
0333                 dragHelper.Drag.imageSource = result.url;
0334                 dragHelper.Drag.mimeData = backend.generateMimeData(model.MimeType, model.MimeData, model.LauncherUrlWithoutIcon);
0335                 dragHelper.Drag.active = true;
0336             });
0337         } else {
0338             dragHelper.Drag.active = false;
0339             dragHelper.Drag.imageSource = "";
0340             pressX = -1;
0341             pressY = -1;
0342         }
0343     }
0344 
0345     onIsMinimizedChanged: {
0346         checkWindowsStates();
0347     }
0348 
0349     onIsActiveChanged: {
0350         checkWindowsStates();
0351         if (isActive) {
0352             scrollableList.focusOn(taskItem);
0353         }
0354     }
0355 
0356     onIsSeparatorChanged: {
0357         if (isSeparator) {
0358             if (tasksExtendedManager.isLauncherToBeMoved(launcherUrl) && itemIndex>=0) {
0359                 tasksExtendedManager.moveLauncherToCorrectPos(launcherUrl, itemIndex);
0360             }
0361         }
0362     }
0363 
0364     onLauncherUrlChanged: updateBadge();
0365 
0366     onShortcutRequestedActivate: {
0367         if (taskItem.isGroupParent) {
0368             taskItem.activateNextTask();
0369         } else {
0370             taskItem.activateTask();
0371         }
0372     }
0373 
0374     onShortcutRequestedNewInstance: {
0375         tasksModel.requestNewInstance(taskItem.modelIndex());
0376     }
0377 
0378     ////// End of Values Changes and Signals /////
0379 
0380 
0381     //! A timer is needed in order to handle also touchpads that probably
0382     //! send too many signals very fast. This way the signals per sec are limited.
0383     //! The user needs to have a steady normal scroll in order to not
0384     //! notice a annoying delay
0385     Timer{
0386         id: scrollDelayer
0387 
0388         interval: 400
0389 
0390         onTriggered: taskItem.wheelIsBlocked = false;
0391     }
0392 
0393     ///////////////// End Of Mouse Area Events ///////////////////
0394 
0395     ///// Handlers for Signals /////
0396     function animationStarted(){
0397         //    console.log("Animation started: " + index);
0398         inAnimation = true;
0399     }
0400 
0401     function animationEnded(){
0402         //   console.log("Animation ended: " + index);
0403         inAnimation = false;
0404     }
0405 
0406     function handlerDraggingFinished(){
0407         isDragged = false;
0408     }
0409     ///// End of Handlers //////
0410 
0411 
0412 
0413     ///// Helper functions /////
0414     function activateNextTask() {
0415         subWindows.activateNextTask();
0416     }
0417 
0418     function activateLauncher() {
0419         if (LatteCore.WindowSystem.compositingActive) {
0420             taskItem.taskLauncherActivated();
0421             hasAddedWaitingLauncher = true;
0422             tasksExtendedManager.addWaitingLauncher(taskItem.launcherUrl);
0423         }
0424 
0425         if (root.disableAllWindowsFunctionality) {
0426             tasksModel.requestNewInstance(modelIndex());
0427         } else {
0428             tasksModel.requestActivate(modelIndex());
0429         }
0430     }
0431 
0432     function activateTask() {
0433         if( taskItem.isLauncher || root.disableAllWindowsFunctionality){
0434             activateLauncher();
0435         } else{
0436             if (model.IsGroupParent) {
0437                 if (root.plasmaAtLeast525) {
0438                     //! At least Plasma 5.25 case
0439                     var isWindowViewAvailable = LatteCore.WindowSystem.compositingActive && backend.windowViewAvailable;
0440                     if (isWindowViewAvailable) {
0441                         root.activateWindowView(model.WinIdList);
0442                     }
0443                 } else {
0444                     //! Plasma 5.24 case
0445                     var isPresentWindowsAvailable = LatteCore.WindowSystem.compositingActive && backend.canPresentWindows;
0446                     if (isPresentWindowsAvailable) {
0447                         root.presentWindows(model.WinIdList);
0448                     }
0449                 }
0450             } else {
0451                 if (windowsPreviewDlg.visible) {
0452                     forceHidePreview(8.3);
0453                 }
0454 
0455                 if (isMinimized) {
0456                     var i = modelIndex();
0457                     tasksModel.requestToggleMinimized(i);
0458                     tasksModel.requestActivate(i);
0459                 } else if (isActive) {
0460                     tasksModel.requestToggleMinimized(modelIndex());
0461                 } else {
0462                     tasksModel.requestActivate(modelIndex());
0463                 }
0464             }
0465         }
0466     }
0467 
0468     function forceHidePreview(debugtext) {
0469         showPreviewsIsBlockedFromReleaseEvent = true;
0470         hoveredTimer.stop();
0471 
0472         root.forcePreviewsHiding(debugtext);
0473     }
0474 
0475     function showPreviewWindow() {
0476         if (root.disableAllWindowsFunctionality || !isAbleToShowPreview) {
0477             return;
0478         }
0479 
0480         if(windowsPreviewDlg.activeItem !== taskItem){
0481             if (!taskItem.abilities.myView.isReady
0482                     || (taskItem.abilities.myView.isReady && taskItem.abilities.myView.isShownFully)) {
0483                 taskItem.preparePreviewWindow(false);
0484                 windowsPreviewDlg.show(taskItem);
0485             }
0486         }
0487     }
0488 
0489     function hidePreviewWindow() {
0490         if(windowsPreviewDlg.activeItem === taskItem){
0491             windowsPreviewDlg.hide("14.1");
0492         }
0493     }
0494 
0495     function preparePreviewWindow(hideClose){
0496         windowsPreviewDlg.visualParent = tooltipVisualParent;
0497         toolTipDelegate.parentTask = taskItem;
0498         toolTipDelegate.rootIndex = tasksModel.makeModelIndex(itemIndex, -1);
0499 
0500         toolTipDelegate.hideCloseButtons = hideClose;
0501 
0502         toolTipDelegate.appName = Qt.binding(function() {
0503             return model.AppName;
0504         });
0505 
0506         if (!isLauncher) {
0507             toolTipDelegate.pidParent = Qt.binding(function() {
0508                 return model.AppPid;
0509             });
0510         } else {
0511             toolTipDelegate.pidParent = -1;
0512         }
0513 
0514         toolTipDelegate.windows = Qt.binding(function() {
0515             return root.plasma515 ? model.WinIdList : model.LegacyWinIdList ;
0516         });
0517         toolTipDelegate.isGroup = Qt.binding(function() {
0518             return model.IsGroupParent == true;
0519         });
0520         toolTipDelegate.icon = Qt.binding(function() {
0521             return model.decoration;
0522         });
0523         toolTipDelegate.launcherUrl = Qt.binding(function() {
0524             return model.LauncherUrlWithoutIcon;
0525         });
0526         toolTipDelegate.isLauncher = Qt.binding(function() {
0527             return model.IsLauncher == true;
0528         });
0529         toolTipDelegate.isMinimizedParent = Qt.binding(function() {
0530             return model.IsMinimized == true;
0531         });
0532         toolTipDelegate.displayParent = Qt.binding(function() {
0533             return model.display;
0534         });
0535         toolTipDelegate.genericName = Qt.binding(function() {
0536             return model.GenericName;
0537         });
0538         toolTipDelegate.virtualDesktopParent = Qt.binding(function() {
0539             return (model.VirtualDesktops !== undefined && model.VirtualDesktops.length > 0) ? model.VirtualDesktops : [0];
0540         });
0541         toolTipDelegate.isOnAllVirtualDesktopsParent = Qt.binding(function() {
0542             return model.IsOnAllVirtualDesktops == true;
0543         });
0544         toolTipDelegate.activitiesParent = Qt.binding(function() {
0545             return model.Activities;
0546         });
0547     }
0548 
0549     ///window previews///
0550     function generateSubText(task) {
0551         var subTextEntries = new Array();
0552 
0553         if (!plasmoid.configuration.showOnlyCurrentDesktop
0554                 && virtualDesktopInfo.numberOfDesktops > 1
0555                 && model.IsOnAllVirtualDesktops !== true
0556                 && model.VirtualDesktop != -1
0557                 && model.VirtualDesktop != undefined) {
0558             subTextEntries.push(i18n("On %1", virtualDesktopInfo.desktopNames[model.VirtualDesktop - 1]));
0559         }
0560 
0561         if (model.Activities == undefined) {
0562             return subTextEntries.join("\n");
0563         }
0564 
0565         if (model.Activities.length == 0 && activityInfo.numberOfRunningActivities > 1) {
0566             subTextEntries.push(i18nc("Which virtual desktop a window is currently on",
0567                                       "Available on all activities"));
0568         } else if (model.Activities.length > 0) {
0569             var activityNames = new Array();
0570 
0571             for (var i = 0; i < model.Activities.length; i++) {
0572                 var activity = model.Activities[i];
0573 
0574                 if (plasmoid.configuration.showOnlyCurrentActivity) {
0575                     if (activity != activityInfo.currentActivity) {
0576                         activityNames.push(activityInfo.activityName(model.Activities[i]));
0577                     }
0578                 } else if (activity != activityInfo.currentActivity) {
0579                     activityNames.push(activityInfo.activityName(model.Activities[i]));
0580                 }
0581             }
0582 
0583             if (plasmoid.configuration.showOnlyCurrentActivity) {
0584                 if (activityNames.length > 0) {
0585                     subTextEntries.push(i18nc("Activities a window is currently on (apart from the current one)",
0586                                               "Also available on %1", activityNames.join(", ")));
0587                 }
0588             } else if (activityNames.length > 0) {
0589                 subTextEntries.push(i18nc("Which activities a window is currently on",
0590                                           "Available on %1", activityNames.join(", ")));
0591             }
0592         }
0593 
0594         return subTextEntries.join("\n");
0595     }
0596     ///window previews////
0597 
0598     function modelIndex(){
0599         return tasksModel.makeModelIndex(index);
0600     }
0601 
0602     function showContextMenu(args) {
0603         if (isSeparator && !root.inEditMode)
0604             return;
0605 
0606         if (!root.contextMenu) {
0607             contextMenu = root.createContextMenu(taskItem, modelIndex(), args);
0608             contextMenu.show();
0609         } else {
0610             //! make sure that context menu isnt deleted multiple times and creates a crash
0611             //! bug case: 397635
0612             var cMenu = root.contextMenu;
0613             root.contextMenu = null;
0614             cMenu.destroy();
0615         }
0616     }
0617 
0618     function modifierAccepted(mouse){
0619         if (mouse.modifiers & root.modifierQt){
0620             if ((mouse.button === Qt.LeftButton && root.modifierClick === LatteTasks.Types.LeftClick)
0621                     || (mouse.button === Qt.MiddleButton && root.modifierClick === LatteTasks.Types.MiddleClick)
0622                     || (mouse.button === Qt.RightButton && root.modifierClick === LatteTasks.Types.RightClick))
0623                 return true;
0624         }
0625 
0626         return false;
0627     }
0628 
0629     function setBlockingAnimation(value){
0630         inBlockingAnimation = value;
0631     }
0632 
0633     function slotShowPreviewForTasks(group) {
0634         if (group === taskItem && !windowsPreviewDlg.visible) {
0635             preparePreviewWindow(true);
0636             windowsPreviewDlg.show(taskItem);
0637         }
0638     }
0639 
0640     function slotPublishGeometries() {
0641         //! this way we make sure that layouts that are in different activities that the current layout
0642         //! don't publish their geometries
0643         if ( canPublishGeometries && (!taskItem.abilities.myView.isReady || (taskItem.abilities.myView.isReady && taskItem.abilities.myView.inCurrentLayout()))) {
0644             var globalChoords = backend.globalRect(taskItem.parabolicItem.contentItemContainer);
0645             var limits = backend.globalRect(scrollableList);
0646 
0647             //! Limit the published geometries boundaries at scrolling area boundaries
0648             var adjX = Math.min(limits.x+limits.width, Math.max(limits.x, globalChoords.x));
0649             var adjY = Math.min(limits.y+limits.height, Math.max(limits.y, globalChoords.y));
0650 
0651             var length = taskItem.abilities.metrics.iconSize * taskItem.parabolicItem.zoom;
0652             var thickness = length;
0653 
0654             //! Magic Lamp effect doesn't like coordinates outside the screen and
0655             //! width,heights of zero value... So we now normalize the geometries
0656             //! sent in order to avoid such circumstances
0657             if (root.vertical) {
0658                 if (adjY !== globalChoords.y) {
0659                     if (((globalChoords.y+globalChoords.height) < limits.y) || (globalChoords.y)>(limits.y+limits.height)) {
0660                         //! totally out of boundaries
0661                         length = 4;
0662                     } else {
0663                         //! semi-part out of boundaries
0664                         length = Math.max(4, Math.abs(adjY - globalChoords.y));
0665                     }
0666 
0667                     globalChoords.height = length;
0668                 }
0669             } else {
0670                 if (adjX !== globalChoords.x) {
0671                     if (((globalChoords.x+globalChoords.width) < limits.x) || (globalChoords.x)>(limits.x+limits.width)) {
0672                         //! totally out of boundaries
0673                         length = 4;
0674                     } else {
0675                         //! semi-part out of boundaries
0676                         length = Math.max(4, Math.abs(adjX - globalChoords.x));
0677                     }
0678 
0679                     globalChoords.width = length;
0680                 }
0681             }
0682 
0683             globalChoords.x = adjX;
0684             globalChoords.y = adjY;
0685 
0686             if (taskItem.abilities.myView.isHidden) {
0687                 if (root.location === PlasmaCore.Types.BottomEdge) {
0688                     globalChoords.y = taskItem.abilities.myView.screenGeometry.y + taskItem.abilities.myView.screenGeometry.height-1;
0689                     globalChoords.height = 1;
0690                 } else if (root.location === PlasmaCore.Types.TopEdge) {
0691                     globalChoords.y = taskItem.abilities.myView.screenGeometry.y+1;
0692                     globalChoords.height = 1;
0693                 } else if (root.location === PlasmaCore.Types.LeftEdge) {
0694                     globalChoords.x = taskItem.abilities.myView.screenGeometry.x+1;
0695                     globalChoords.width = 1;
0696                 } else if (root.location === PlasmaCore.Types.RightEdge) {
0697                     globalChoords.x = taskItem.abilities.myView.screenGeometry.x + taskItem.abilities.myView.screenGeometry.width - 1;
0698                     globalChoords.width = 1;
0699                 }
0700             }
0701 
0702             tasksModel.requestPublishDelegateGeometry(taskItem.modelIndex(), globalChoords, taskItem);
0703         }
0704     }
0705 
0706     function slotWaitingLauncherRemoved(launch) {
0707         if ((isWindow || isStartup || isLauncher) && !visible && launch === launcherUrl) {
0708             if (!taskItem.abilities.indicators.info.providesTaskLauncherAnimation) {
0709                 //! this is needed only from in-built launcher animation to restore zoom smoothly
0710                 taskItem.parabolicItem.zoom = 1;
0711             }
0712             visible = true;
0713         }
0714     }
0715 
0716 
0717     function updateAudioStreams() {
0718         if (root.dragSource !== null) {
0719             audioStreams = [];
0720             return;
0721         }
0722 
0723         var pa = pulseAudio.item;
0724         if (!pa) {
0725             audioStreams = [];
0726             return;
0727         }
0728 
0729         var streams = pa.streamsForPid(taskItem.pid);
0730         if (streams.length) {
0731             pa.registerPidMatch(taskItem.appName);
0732         } else {
0733             // We only want to fall back to appName matching if we never managed to map
0734             // a PID to an audio stream window. Otherwise if you have two instances of
0735             // an application, one playing and the other not, it will look up appName
0736             // for the non-playing instance and erroneously show an indicator on both.
0737             if (!pa.hasPidMatch(taskItem.appName)) {
0738                 streams = pa.streamsForAppName(taskItem.appName);
0739             }
0740         }
0741 
0742         // fix a binding loop concerning audiostreams, the audiostreams
0743         // should be updated only when they have changed
0744         var changed = false;
0745 
0746         if (streams.length !== audioStreams.length) {
0747             changed = true;
0748         } else {
0749             for(var i=0; i<streams.length; ++i) {
0750                 if (streams[i] !== audioStreams[i]) {
0751                     changed = true;
0752                     break;
0753                 }
0754             }
0755         }
0756 
0757         if (changed) {
0758             taskItem.audioStreams = streams;
0759         }
0760     }
0761 
0762     function onLauncherChanged(launcher) {
0763         if ((root.showWindowsOnlyFromLaunchers || root.disableAllWindowsFunctionality) && launcher === launcherUrl) {
0764             updateVisibilityBasedOnLaunchers()
0765         }
0766     }
0767 
0768     function updateVisibilityBasedOnLaunchers(){
0769         var launcherExists = !(((tasksModel.launcherPosition(taskItem.launcherUrl) == -1)
0770                                 && (tasksModel.launcherPosition(taskItem.launcherUrlWithIcon) == -1) )
0771                                || !taskItem.abilities.launchers.inCurrentActivity(taskItem.launcherUrl));
0772 
0773         if (root.showWindowsOnlyFromLaunchers || root.disableAllWindowsFunctionality) {
0774             var hideWindow =  !launcherExists && (taskItem.isWindow || root.disableAllWindowsFunctionality);
0775 
0776             if (hideWindow) {
0777                 isForcedHidden = true;
0778                 taskRealRemovalAnimation.start();
0779             } else if (launcherExists && taskItem.isWindow && !taskItem.isVisible) {
0780                 showWindowAnimation.showWindow();
0781                 isForcedHidden = false;
0782             }
0783         } else {
0784             var showWindow =  !launcherExists && taskItem.isWindow;
0785 
0786             if (showWindow) {
0787                 showWindowAnimation.showWindow();
0788                 isForcedHidden = false;
0789             }
0790         }
0791     }
0792 
0793     function toggleMuted() {
0794         if (muted) {
0795             taskItem.audioStreams.forEach(function (item) { item.unmute(); });
0796         } else {
0797             taskItem.audioStreams.forEach(function (item) { item.mute(); });
0798         }
0799     }
0800 
0801     function increaseVolume() {
0802         taskItem.audioStreams.forEach(function (item) { item.increaseVolume(); });
0803     }
0804 
0805     function decreaseVolume() {
0806         taskItem.audioStreams.forEach(function (item) { item.decreaseVolume(); });
0807     }
0808 
0809     function updateBadge() {
0810         var badger = root.getBadger(launcherUrl);
0811 
0812         if (badger) {
0813             badgeIndicator = parseInt(badger.value);
0814         } else {
0815             badgeIndicator = 0;
0816         }
0817     }
0818 
0819     Connections {
0820         target: pulseAudio.item
0821         ignoreUnknownSignals: true // Plasma-PA might not be available
0822         onStreamsChanged: taskItem.updateAudioStreams()
0823     }
0824 
0825     //fix bug #478, when changing form factor sometimes the tasks are not positioned
0826     //correctly, in such case we make a fast reinitialization for the sizes
0827     Connections {
0828         target: plasmoid
0829         onFormFactorChanged:{
0830             taskItem.inAddRemoveAnimation = false;
0831         }
0832     }
0833 
0834     Connections {
0835         target: root
0836         //trying to fix #440, showing the audio icon indicator to irrelevant tasks
0837         //after dragging an existent task with audio
0838         onDragSourceChanged: taskItem.updateAudioStreams()
0839         onShowAudioBadgeChanged: taskItem.updateAudioStreams()
0840 
0841         onDisableAllWindowsFunctionalityChanged: {
0842             if (!root.inEditMode) {
0843                 return;
0844             }
0845 
0846             taskItem.updateVisibilityBasedOnLaunchers();
0847         }
0848 
0849         onShowWindowsOnlyFromLaunchersChanged: {
0850             if (!root.inEditMode) {
0851                 return;
0852             }
0853 
0854             taskItem.updateVisibilityBasedOnLaunchers();
0855         }
0856 
0857         onInActivityChangeChanged: {
0858             if ((root.showWindowsOnlyFromLaunchers || root.disableAllWindowsFunctionality) && !root.inActivityChange) {
0859                 taskItem.updateVisibilityBasedOnLaunchers();
0860             }
0861         }
0862     }
0863 
0864     Connections {
0865         target: scrollableList
0866         onAnimationsFinishedChanged: {
0867             if (scrollableList.animationsFinished) {
0868                 taskItem.slotPublishGeometries();
0869             }
0870         }
0871     }
0872 
0873     Connections {
0874         target: taskItem.abilities.myView
0875         onIsHiddenChanged: {
0876             if (taskItem.abilities.myView.isHidden) {
0877                 taskItem.slotPublishGeometries();
0878             }
0879         }
0880 
0881         onIsShownFullyChanged: {
0882             if (taskItem.abilities.myView.isShownFully) {
0883                 taskItem.slotPublishGeometries();
0884             }
0885         }
0886     }
0887 
0888     ///// End of Helper functions ////
0889 
0890     Component.onCompleted: {
0891         parabolicItem.opacity = 0;
0892 
0893         root.draggingFinished.connect(handlerDraggingFinished);
0894         root.publishTasksGeometries.connect(slotPublishGeometries);
0895         root.showPreviewForTasks.connect(slotShowPreviewForTasks);
0896 
0897         taskItem.abilities.launchers.launcherChanged.connect(onLauncherChanged);
0898         taskItem.abilities.launchers.launcherRemoved.connect(onLauncherChanged);
0899 
0900         //startup without launcher
0901         var hideStartup =  ((!hasShownLauncher || !taskItem.abilities.launchers.inCurrentActivity(taskItem.launcherUrl))
0902                             && taskItem.isStartup);
0903 
0904         if (!LatteCore.WindowSystem.compositingActive) {
0905             visible = true;
0906         } else if ( (isWindow || isStartup || isLauncher) && tasksExtendedManager.waitingLauncherExists(launcherUrl)) {
0907             tasksExtendedManager.waitingLauncherRemoved.connect(slotWaitingLauncherRemoved);
0908             visible = false;
0909         } else if (hideStartup){
0910             visible = false;
0911         } else {
0912             visible = true;
0913         }
0914 
0915         showWindowAnimation.showWindow();
0916         updateAudioStreams();
0917     }
0918 
0919     Component.onDestruction: {
0920         root.draggingFinished.disconnect(handlerDraggingFinished);
0921         root.publishTasksGeometries.disconnect(slotPublishGeometries);
0922         root.showPreviewForTasks.disconnect(slotShowPreviewForTasks);
0923 
0924         taskItem.abilities.launchers.launcherChanged.disconnect(onLauncherChanged);
0925         taskItem.abilities.launchers.launcherRemoved.disconnect(onLauncherChanged);
0926 
0927         tasksExtendedManager.waitingLauncherRemoved.disconnect(slotWaitingLauncherRemoved);
0928 
0929         taskItem.parabolicItem.sendEndOfNeedBothAxisAnimation();
0930     }
0931 
0932     /////Animations
0933     TaskAnimations.ShowWindowAnimation{ id: _showWindowAnimation }
0934 
0935     // when changing activities and desktops the index of the tasks
0936     // is updated immediately to -1, this timer protects this indexing
0937     // change in order to provide a beautiful removal tasks animation
0938     Timer {
0939         id: lastValidTimer
0940         interval: 100 ///the interval does not follow the animations timing
0941         repeat: false
0942 
0943         onTriggered: {
0944             if (taskItem.itemIndex >= 0){
0945                 taskItem.lastValidIndex = taskItem.itemIndex;
0946             }
0947 
0948             if (taskItem.abilities.debug.timersEnabled) {
0949                 console.log("plasmoid timer: lastValidTimer called...");
0950             }
0951         }
0952     }
0953 
0954     ///Item's Removal Animation
0955     ListView.onRemove: TaskAnimations.RealRemovalAnimation{ id: taskRealRemovalAnimation }
0956 
0957     onIsLauncherAnimationRunningChanged: {
0958         if (!isLauncherAnimationRunning && taskRealRemovalAnimation.paused) {
0959             taskRealRemovalAnimation.resume();
0960         }
0961     }
0962 }// main Item
0963