diff --git a/app/launcherssignals.cpp b/app/launcherssignals.cpp index 6d9fecb4..a50433ff 100644 --- a/app/launcherssignals.cpp +++ b/app/launcherssignals.cpp @@ -1,275 +1,311 @@ /* * Copyright 2017 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 . */ #include "launcherssignals.h" #include "dockcorona.h" #include "layout.h" #include #include #include namespace Latte { LaunchersSignals::LaunchersSignals(QObject *parent) : QObject(parent) { m_manager = qobject_cast(parent); } LaunchersSignals::~LaunchersSignals() { } QList LaunchersSignals::lattePlasmoids(QString layoutName) { QList applets; Layout *layout = m_manager->activeLayout(layoutName); QList containments; if (layoutName.isEmpty()) { containments = m_manager->corona()->containments(); } else if (layout) { containments = *(layout->containments()); } foreach (auto containment, containments) { for (auto *applet : containment->applets()) { KPluginMetaData meta = applet->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.plasmoid") { applets.append(applet); } } } return applets; } void LaunchersSignals::addLauncher(QString layoutName, int launcherGroup, QString launcher) { Dock::LaunchersGroup group = static_cast(launcherGroup); if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { return; } QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex = metaObject->indexOfMethod("extSignalAddLauncher(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher)); } } } } } void LaunchersSignals::removeLauncher(QString layoutName, int launcherGroup, QString launcher) { Dock::LaunchersGroup group = static_cast(launcherGroup); if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { return; } QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex = metaObject->indexOfMethod("extSignalRemoveLauncher(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher)); } } } } } void LaunchersSignals::addLauncherToActivity(QString layoutName, int launcherGroup, QString launcher, QString activity) { Dock::LaunchersGroup group = static_cast(launcherGroup); if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { return; } QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex = metaObject->indexOfMethod("extSignalAddLauncherToActivity(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher), Q_ARG(QVariant, activity)); } } } } } void LaunchersSignals::removeLauncherFromActivity(QString layoutName, int launcherGroup, QString launcher, QString activity) { Dock::LaunchersGroup group = static_cast(launcherGroup); if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { return; } QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex = metaObject->indexOfMethod("extSignalRemoveLauncherFromActivity(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launcher), Q_ARG(QVariant, activity)); } } } } } void LaunchersSignals::urlsDropped(QString layoutName, int launcherGroup, QStringList urls) { Dock::LaunchersGroup group = static_cast(launcherGroup); if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { return; } QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex = metaObject->indexOfMethod("extSignalUrlsDropped(QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, urls)); } } } } } void LaunchersSignals::moveTask(QString layoutName, int senderId, int launcherGroup, int from, int to) { Dock::LaunchersGroup group = static_cast(launcherGroup); if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { return; } QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; foreach (auto applet, lattePlasmoids(lName)) { if (applet->id() != senderId) { if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { const auto &childItems = appletInterface->childItems(); if (childItems.isEmpty()) { continue; } for (QQuickItem *item : childItems) { if (auto *metaObject = item->metaObject()) { int methodIndex = metaObject->indexOfMethod("extSignalMoveTask(QVariant,QVariant,QVariant)"); if (methodIndex == -1) { continue; } QMetaMethod method = metaObject->method(methodIndex); method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, from), Q_ARG(QVariant, to)); } } } } } } +void LaunchersSignals::validateLaunchersOrder(QString layoutName, int senderId, int launcherGroup, QStringList launchers) +{ + Dock::LaunchersGroup group = static_cast(launcherGroup); + + if ((Dock::LaunchersGroup)group == Dock::UniqueLaunchers) { + return; + } + + QString lName = (group == Dock::LayoutLaunchers) ? layoutName : ""; + + foreach (auto applet, lattePlasmoids(lName)) { + if (applet->id() != senderId) { + if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value()) { + const auto &childItems = appletInterface->childItems(); + + if (childItems.isEmpty()) { + continue; + } + + for (QQuickItem *item : childItems) { + if (auto *metaObject = item->metaObject()) { + int methodIndex = metaObject->indexOfMethod("extSignalValidateLaunchersOrder(QVariant,QVariant)"); + + if (methodIndex == -1) { + continue; + } + + QMetaMethod method = metaObject->method(methodIndex); + method.invoke(item, Q_ARG(QVariant, launcherGroup), Q_ARG(QVariant, launchers)); + } + } + } + } + } +} + } //end of namespace diff --git a/app/launcherssignals.h b/app/launcherssignals.h index 7cf1b9ab..da200e45 100644 --- a/app/launcherssignals.h +++ b/app/launcherssignals.h @@ -1,70 +1,72 @@ /* * Copyright 2017 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 . */ #ifndef LAUNCHERSSIGNALS_H #define LAUNCHERSSIGNALS_H #include "layoutmanager.h" #include "../liblattedock/dock.h" #include namespace Plasma { class Applet; } namespace Latte { class LayoutManager; } namespace Latte { //! in order to support property the launcher groups Layout and Global //! the latte plasmoids must communicate between them with signals when //! there are changes in their models. This way we are trying to avoid //! crashes that occur by setting the launcherList of the tasksModel so //! often. The plasma devs of libtaskmanager have designed the launchers //! model to be initialized only once during startup class LaunchersSignals : public QObject { Q_OBJECT public: LaunchersSignals(QObject *parent); ~LaunchersSignals() override; public slots: Q_INVOKABLE void addLauncher(QString layoutName, int launcherGroup, QString launcher); Q_INVOKABLE void removeLauncher(QString layoutName, int launcherGroup, QString launcher); Q_INVOKABLE void addLauncherToActivity(QString layoutName, int launcherGroup, QString launcher, QString activity); Q_INVOKABLE void removeLauncherFromActivity(QString layoutName, int launcherGroup, QString launcher, QString activity); Q_INVOKABLE void urlsDropped(QString layoutName, int launcherGroup, QStringList urls); + //!Deprecated because it could create crashes, validateLaunchersOrder provides a better approach Q_INVOKABLE void moveTask(QString layoutName, int senderId, int launcherGroup, int from, int to); + Q_INVOKABLE void validateLaunchersOrder(QString layoutName, int senderId, int launcherGroup, QStringList launchers); private: QList lattePlasmoids(QString layoutName); private: LayoutManager *m_manager{nullptr}; }; } #endif diff --git a/plasmoid/package/contents/ui/MouseHandler.qml b/plasmoid/package/contents/ui/MouseHandler.qml index a2dac1aa..9ea76918 100644 --- a/plasmoid/package/contents/ui/MouseHandler.qml +++ b/plasmoid/package/contents/ui/MouseHandler.qml @@ -1,259 +1,260 @@ /* * 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.draganddrop 2.0 import org.kde.taskmanager 0.1 as TaskManager import org.kde.latte 0.1 as Latte import "../code/tools.js" as TaskTools Item { // signal urlDropped(url url) signal urlsDropped(var urls) property Item target property Item ignoredItem property bool moved: false property alias hoveredItem: dropHandler.hoveredItem property alias onlyLaunchers: dropHandler.onlyLaunchers Timer { id: ignoreItemTimer repeat: false interval: 200 onTriggered: { ignoredItem = null; } } Connections { target: root onDragSourceChanged: { if (!dragSource) { ignoredItem = null; ignoreItemTimer.stop(); } } } DropArea { id: dropHandler anchors.fill: parent preventStealing: true; property int droppedPosition: -1; property bool onlyLaunchers: false; property bool droppingSeparator: false; property Item hoveredItem function isDroppingSeparator(event) { return ((event.mimeData.formats.indexOf("text/x-plasmoidservicename") === 0) && (String(event.mimeData.getDataAsByteArray("text/x-plasmoidservicename")) === "audoban.applet.separator")); } onDragEnter:{ if(root.dragSource == null){ onlyLaunchers = false; droppingSeparator = false; root.dropNewLauncher = false; var createLaunchers = false; if (event.mimeData.hasUrls || (event.mimeData.formats.indexOf("text/x-plasmoidservicename") !== 0)) { root.dropNewLauncher = true; if (event.mimeData.hasUrls){ createLaunchers = event.mimeData.urls.every(function (item) { return backend.isApplication(item) }); } } else if (isDroppingSeparator(event)) { droppingSeparator = true; root.dropNewLauncher = true; return; } else { event.ignore(); } if (createLaunchers) { onlyLaunchers = true; } } } onDragMove: { /* if(root.dragSource == null){ root.dropNewLauncher = true; } */ if (target.animating) { return; } var above = target.childAtPos(event.x, event.y); // If we're mixing launcher tasks with other tasks and are moving // a (small) launcher task across a non-launcher task, don't allow // the latter to be the move target twice in a row for a while, as // it will naturally be moved underneath the cursor as result of the // initial move, due to being far larger than the launcher delegate. // TODO: This restriction (minus the timer, which improves things) // has been proven out in the EITM fork, but could be improved later // by tracking the cursor movement vector and allowing the drag if // the movement direction has reversed, etablishing user intent to // move back. if (root.dragSource == null && ignoredItem == above) return; if (root.dragSource != null && root.dragSource.m.IsLauncher === true && above != null && above.m != null && above.m.IsLauncher !== true && above == ignoredItem) { return; } else { //ignoredItem = null; } //at some point it was needed the following && above != ignoredItem //but know not... strange... && above != ignoredItem //I use the ignoredItem in order to reduce the move calls as much //as possible if (tasksModel.sortMode == TaskManager.TasksModel.SortManual && root.dragSource && ignoredItem == null) { var insertAt = TaskTools.insertIndexAt(above, event.x, event.y); if (root.dragSource != above && root.dragSource.itemIndex != insertAt) { // console.log(root.dragSource.itemIndex + " - "+insertAt); root.dragSource.z = 100; ignoredItem = above; var pos = root.dragSource.itemIndex; tasksModel.move(pos, insertAt); - if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { + //! disable syncing for moving launchers action in favor of validatorOrder launchersSignal + /* if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.moveTask(root.managedLayoutName, plasmoid.id, latteDock.launchersGroup, pos, insertAt); - } + }*/ root.separatorsUpdated(); ignoreItemTimer.restart(); } } else if (!root.dragSource && above && hoveredItem != above) { hoveredItem = above; if (!onlyLaunchers) { //! it is needed when dropping a url on a launcher in order to not break parabolic effect root.setHoveredIndex(hoveredItem.itemIndex); } //root.dropNewLauncher = true; activationTimer.restart(); } else if (!above) { //root.dropNewLauncher = true; hoveredItem = null; root.setHoveredIndex(-1); activationTimer.stop(); } if (hoveredItem && windowsPreviewDlg.visible && toolTipDelegate.rootIndex !== hoveredItem.modelIndex() ) { windowsPreviewDlg.hide(6); } } onDragLeave: { hoveredItem = null; root.setHoveredIndex(-1); root.dropNewLauncher = false; onlyLaunchers = false; root.separatorsUpdated(); activationTimer.stop(); } onDrop: { // Reject internal drops. root.dropNewLauncher = false; onlyLaunchers = false; root.separatorsUpdated(); if (event.mimeData.formats.indexOf("application/x-orgkdeplasmataskmanager_taskbuttonitem") >= 0) { return; } if (droppingSeparator) { droppingSeparator = false; if (hoveredItem && hoveredItem.itemIndex >=0){ root.addInternalSeparatorAtPos(hoveredItem.itemIndex); } else { root.addInternalSeparatorAtPos(0); } return; } if (event.mimeData.hasUrls) { parent.urlsDropped(event.mimeData.urls); } } Timer { id: activationTimer interval: 250 repeat: false onTriggered: { if (dropHandler.onlyLaunchers || !root.dropNewLauncher || dropHandler.droppingSeparator) { return; } if (parent.hoveredItem.m.IsGroupParent === true) { root.showPreviewForTasks(parent.hoveredItem); // groupDialog.visualParent = parent.hoveredItem; // groupDialog.visible = true; } else if (parent.hoveredItem.m.IsLauncher !== true) { if(windowsPreviewDlg.visible && toolTipDelegate.currentItem !==parent.hoveredItem.itemIndex ) { windowsPreviewDlg.hide(5); toolTipDelegate.currentItem=-1; } tasksModel.requestActivate(parent.hoveredItem.modelIndex()); } } } } /* MouseArea { id: wheelHandler anchors.fill: parent property int wheelDelta: 0; enabled: plasmoid.configuration.wheelEnabled onWheel: wheelDelta = TaskTools.wheelActivateNextPrevTask(wheelDelta, wheel.angleDelta.y); } */ } diff --git a/plasmoid/package/contents/ui/main.qml b/plasmoid/package/contents/ui/main.qml index 95e0ac32..d99c1947 100644 --- a/plasmoid/package/contents/ui/main.qml +++ b/plasmoid/package/contents/ui/main.qml @@ -1,1943 +1,2141 @@ /* * 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.taskmanager 0.1 as TaskManager import org.kde.plasma.private.taskmanager 0.1 as TaskManagerApplet import org.kde.activities 0.1 as Activities import org.kde.latte 0.1 as Latte import "task" as Task import "../code/tools.js" as TaskTools import "../code/activitiesTools.js" as ActivitiesTools Item { id:root // Layout.fillHeight: userPanelPosition === 0 ? true : false // Layout.fillWidth: userPanelPosition === 0 ? true : false ///IMPORTANT: These values must be tested when the Now Dock Panel support ///also the four new anchors. A small issue is shown between the animation /// of the now dock plasmoid and the neighbour widgets... Layout.minimumWidth: (userPanelPosition !== 0)&&(!latteDock) ? clearWidth : -1 Layout.minimumHeight: (userPanelPosition !== 0)&&(!latteDock) ? clearHeight : -1 Layout.preferredWidth: (userPanelPosition !== 0)&&(!latteDock) ? tasksWidth : -1 Layout.preferredHeight: (userPanelPosition !== 0)&&(!latteDock) ? tasksHeight : -1 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft && !root.vertical LayoutMirroring.childrenInherit: true property bool debugLocation: false //it is used to check both the applet and the containment for direct render property bool globalDirectRender: latteDock ? latteDock.globalDirectRender : icList.directRender property bool editMode: latteDock ? latteDock.editMode : plasmoid.userConfiguring property bool disableRestoreZoom: false //blocks restore animation in rightClick property bool disableAllWindowsFunctionality: root.showWindowsOnlyFromLaunchers && root.activeIndicator === Latte.Dock.NoneIndicator property bool dropNewLauncher: false readonly property bool hasInternalSeparator: parabolicManager.hasInternalSeparator property bool inActivityChange: false property bool inDraggingPhase: false property bool initializationStep: false //true property bool isHovered: false property bool showBarLine: plasmoid.configuration.showBarLine property bool showTasksNumbers: false property int tasksNumbersBase: 0 property bool useThemePanel: plasmoid.configuration.useThemePanel property bool taskInAnimation: noTasksInAnimation > 0 ? true : false property bool transparentPanel: plasmoid.configuration.transparentPanel property bool vertical: ((root.position === PlasmaCore.Types.LeftPositioned) || (root.position === PlasmaCore.Types.RightPositioned)) ? true : false property int clearWidth property int clearHeight property int newLocationDebugUse: PlasmaCore.Types.BottomPositioned property int newDroppedPosition: -1 property int noInitCreatedBuffers: 0 property int noTasksInAnimation: 0 property int themePanelSize: plasmoid.configuration.panelSize property int position : PlasmaCore.Types.BottomPositioned property int tasksStarting: 0 property int realSize: iconSize + iconMargin ///Dont use Math.floor it adds one pixel in animations and creates glitches property int widthMargins: root.vertical ? thickMargin : iconMargin property int heightMargins: !root.vertical ? thickMargin : iconMargin // formula for luminance according to: // https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef property real textColorRs: { var color = theme.textColor.r; if (color <= 0.03928) { return color / 12.92; } else { return Math.pow( ((color + 0.055) / 1.055), 2.4 ); } } property real textColorGs: { var color = theme.textColor.g; if (color <= 0.03928) { return color / 12.92; } else { return Math.pow( ((color + 0.055) / 1.055), 2.4 ); } } property real textColorBs: { var color = theme.textColor.b; if (color <= 0.03928) { return color / 12.92; } else { return Math.pow( ((color + 0.055) / 1.055), 2.4 ); } } property real textColorLuma: 0.2126*textColorRs + 0.7152*textColorGs + 0.0722*textColorBs property color minimizedDotColor: { if (latteDock) { return latteDock.minimizedDotColor; } return textColorLuma > 0.6 ? Qt.darker(theme.textColor, 1.7) : Qt.lighter(theme.textColor, 7) } //a small badgers record (id,value) //in order to track badgers when there are changes //in launcher reference from libtaskmanager property variant badgers:[] property variant launchersOnActivities: [] property variant waitingLaunchers: [] //! launchers that are shown after a window removal and must be shown //! immediately because they are already present! property variant immediateLaunchers: [] //global plasmoid reference to the context menu property QtObject contextMenu: null property QtObject contextMenuComponent: Qt.createComponent("ContextMenu.qml"); property Item dragSource: null property Item parabolicManager: _parabolicManager //separator calculations based on audoban's design property int maxSeparatorLength: { if (root.vertical) return 5 + heightMargins; else return 5 + widthMargins; } property real missingSeparatorLength: { if (!root.isVertical) return ((iconSize + widthMargins) * zoomFactor) - maxSeparatorLength; else return ((iconSize + heightMargins) * zoomFactor) - maxSeparatorLength; } //! it is used to play the animation correct when the user removes a launcher property string launcherForRemoval: "" //BEGIN Latte Dock properties property bool dockIsShownCompletely: latteDock ? latteDock.dockIsShownCompletely : true property bool enableShadows: latteDock ? latteDock.enableShadows > 0 : plasmoid.configuration.showShadows property bool forceHidePanel: false property bool directRenderDelayerIsRunning: latteDock ? latteDock.directRenderDelayerIsRunning : directRenderDelayerForEnteringTimer.running property bool disableLeftSpacer: false property bool disableRightSpacer: false property bool dockIsHidden: latteDock ? latteDock.dockIsHidden : false property bool groupTasksByDefault: latteDock ? latteDock.groupTasksByDefault: true property bool highlightWindows: latteDock ? latteDock.highlightWindows: plasmoid.configuration.highlightWindows property bool indicateAudioStreams: latteDock ? latteDock.indicateAudioStreams : plasmoid.configuration.indicateAudioStreams property bool mouseWheelActions: latteDock ? latteDock.mouseWheelActions : true property bool reverseLinesPosition: latteDock ? latteDock.reverseLinesPosition : plasmoid.configuration.reverseLinesPosition property bool dotsOnActive: latteDock ? latteDock.dotsOnActive : plasmoid.configuration.dotsOnActive property bool showGlow: latteDock ? latteDock.showGlow : plasmoid.configuration.showGlow property bool glow3D: latteDock ? latteDock.glow3D : false property bool showOnlyCurrentScreen: latteDock ? latteDock.showOnlyCurrentScreen : plasmoid.configuration.showOnlyCurrentScreen property bool showOnlyCurrentDesktop: latteDock ? latteDock.showOnlyCurrentDesktop : plasmoid.configuration.showOnlyCurrentDesktop property bool showOnlyCurrentActivity: latteDock ? latteDock.showOnlyCurrentActivity : plasmoid.configuration.showOnlyCurrentActivity property bool showPreviews: latteDock ? latteDock.showToolTips : plasmoid.configuration.showToolTips property bool showWindowActions: latteDock ? latteDock.showWindowActions : plasmoid.configuration.showWindowActions property bool showWindowsOnlyFromLaunchers: latteDock ? latteDock.showWindowsOnlyFromLaunchers : false property bool smartLaunchersEnabled: latteDock ? latteDock.smartLaunchersEnabled : plasmoid.configuration.smartLaunchersEnabled property bool threeColorsWindows: latteDock ? latteDock.threeColorsWindows : plasmoid.configuration.threeColorsWindows property bool titleTooltips: latteDock ? latteDock.titleTooltips : false property alias windowPreviewIsShown: windowsPreviewDlg.visible property int activeIndicator: latteDock ? latteDock.activeIndicator : Latte.Dock.AllIndicator property int activeIndicatorType: latteDock ? latteDock.activeIndicatorType : Latte.Dock.LineIndicator property int animationStep: latteDock ? latteDock.animationStep : 1 property int directRenderAnimationTime: latteDock ? latteDock.directRenderAnimationTime : 0 property int dockHoveredIndex : latteDock ? latteDock.hoveredIndex : -1 property int iconMargin: latteDock ? latteDock.iconMargin : 0.12*iconSize property int iconSize: latteDock ? latteDock.iconSize : Math.max(plasmoid.configuration.iconSize, 16) property int glowOption: latteDock ? latteDock.glowOption : Latte.Dock.GlowAll property real glowOpacity: latteDock ? latteDock.glowOpacity : 0.35 property int middleClickAction: latteDock ? latteDock.middleClickAction : plasmoid.configuration.middleClickAction property int modifier: latteDock ? latteDock.modifier : -1 property int modifierClickAction: latteDock ? latteDock.modifierClickAction : -1 property int modifierClick: latteDock ? latteDock.modifierClick : -1 property int modifierQt:{ if (modifier === Latte.Dock.Shift) return Qt.ShiftModifier; else if (modifier === Latte.Dock.Ctrl) return Qt.ControlModifier; else if (modifier === Latte.Dock.Alt) return Qt.AltModifier; else if (modifier === Latte.Dock.Meta) return Qt.MetaModifier; else return -1; } //decouple iconMargin which now is used only for length calculations with thickMargins //which are used for thickness calculations property int thickMarginBase: latteDock ? latteDock.thickMarginBase : Math.ceil(iconMargin/2) property int thickMarginHigh: latteDock ? latteDock.thickMarginHigh : Math.ceil(iconMargin/2) property int thickMargin: thickMarginBase + thickMarginHigh property int statesLineSize: latteDock ? latteDock.statesLineSize : Math.ceil( root.iconSize/13 ) property int tasksHeight: mouseHandler.height property int tasksWidth: mouseHandler.width property int userPanelPosition: latteDock ? latteDock.panelAlignment : plasmoid.configuration.plasmoidPosition property real durationTime: latteDock ? latteDock.durationTime : plasmoid.configuration.durationTime property real zoomFactor: latteDock ? latteDock.zoomFactor : ( 1 + (plasmoid.configuration.zoomLevel / 20) ) property int appShadowSize: latteDock ? latteDock.appShadowSize : Math.ceil(0.12*iconSize) property string appShadowColor: latteDock ? latteDock.appShadowColor : "#ff080808" property string appShadowColorSolid: latteDock ? latteDock.appShadowColorSolid : "#ff080808" property alias tasksCount: tasksModel.count property alias hoveredIndex: icList.hoveredIndex property QtObject currentLayout : latteDock && latteDock.dockManagedLayout ? latteDock.dockManagedLayout : null property var managedLayoutName: currentLayout ? currentLayout.name : "" property Item latteDock: null //END Now Dock Panel properties Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground signal clearZoomSignal(); signal draggingFinished(); signal hiddenTasksUpdated(); signal launchersUpdatedFor(string launcher); signal presentWindows(variant winIds); signal requestLayout; signal separatorsUpdated(); signal signalActionsBlockHiding(int value); signal signalAnimationsNeedBothAxis(int value); signal signalAnimationsNeedLength(int value); signal signalAnimationsNeedThickness(int value); signal signalPreviewsShown(); //signal signalDraggingState(bool value); signal showPreviewForTasks(QtObject group); //trigger updating scaling of neighbour delegates of zoomed delegate signal updateScale(int delegateIndex, real newScale, real step) signal mimicEnterForParabolic(); signal publishTasksGeometries(); signal waitingLauncherRemoved(string launch); signal windowsHovered(variant winIds, bool hovered) //onAnimationsChanged: console.log(animations); /* Rectangle{ anchors.fill: parent border.width: 1 border.color: "red" color: "white" } */ onLatteDockChanged: { if (latteDock) plasmoid.configuration.isInLatteDock = true; else plasmoid.configuration.isInLatteDock = false; } Connections { target: plasmoid onLocationChanged: { root.updatePosition(); iconGeometryTimer.start(); } } Connections { target: plasmoid.configuration // onLaunchersChanged: tasksModel.launcherList = plasmoid.configuration.launchers onGroupingAppIdBlacklistChanged: tasksModel.groupingAppIdBlacklist = plasmoid.configuration.groupingAppIdBlacklist; onGroupingLauncherUrlBlacklistChanged: tasksModel.groupingLauncherUrlBlacklist = plasmoid.configuration.groupingLauncherUrlBlacklist; } Connections{ target: latteDock onDockIsHiddenChanged:{ if (latteDock.dockIsHidden) { windowsPreviewDlg.hide("3.3"); } } onLaunchersGroupChanged:{ if( latteDock && latteDock.editMode) { tasksModel.updateLaunchersList(); } } } Connections{ target: latteDock && latteDock.universalLayoutManager ? latteDock.universalLayoutManager : null onCurrentLayoutNameChanged: root.publishTasksGeometries(); } Connections{ target: icList onHoveredIndexChanged:{ if (latteDock && icList.hoveredIndex>-1){ latteDock.setHoveredIndex(-1); } } } ///// PlasmaCore.ColorScope{ id: colorScopePalette } ///// function initializeHoveredIndex() { icList.hoveredIndex = -1; icList.currentSpot = -1000; } function launchersDropped(urls){ mouseHandler.urlsDroppedOnArea(urls); } ///UPDATE function launcherExists(url) { return (ActivitiesTools.getIndex(url, tasksModel.launcherList)>=0); } function taskExists(url) { var tasks = icList.contentItem.children; for(var i=0; i -1) { + launch.push(explicitLauncher); + } + } + } + + return launch; + } + + function currentListViewLauncherList() { + var launch = []; + + var tasks = icList.contentItem.children; + for(var i=0; i= Latte.Dock.LayoutLaunchers) { + latteDock.universalLayoutManager.launchersSignals.validateLaunchersOrder(root.managedLayoutName, + plasmoid.id, + latteDock.launchersGroup, + currentLauncherList()); + } + } } else { plasmoid.configuration.launchers59 = launcherList; } } else { plasmoid.configuration.launchers59 = launcherList; } } onGroupingAppIdBlacklistChanged: { plasmoid.configuration.groupingAppIdBlacklist = groupingAppIdBlacklist; } onGroupingLauncherUrlBlacklistChanged: { plasmoid.configuration.groupingLauncherUrlBlacklist = groupingLauncherUrlBlacklist; } onAnyTaskDemandsAttentionChanged: { if (anyTaskDemandsAttention){ plasmoid.status = PlasmaCore.Types.RequiresAttentionStatus; attentionTimerComponent.createObject(root); } } Component.onCompleted: { ActivitiesTools.launchersOnActivities = root.launchersOnActivities ActivitiesTools.currentActivity = String(activityInfo.currentActivity); ActivitiesTools.plasmoid = plasmoid; //var loadedLaunchers = ActivitiesTools.restoreLaunchers(); ActivitiesTools.importLaunchersToNewArchitecture(); if (currentLayout && latteDock.universalSettings && (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers || latteDock.launchersGroup === Latte.Dock.GlobalLaunchers)) { if (latteDock.launchersGroup === Latte.Dock.LayoutLaunchers) { launcherList = latteDock.dockManagedLayout.launchers; } else if (latteDock.launchersGroup === Latte.Dock.GlobalLaunchers) { launcherList = latteDock.universalSettings.launchers; } } else { launcherList = plasmoid.configuration.launchers59; } groupingAppIdBlacklist = plasmoid.configuration.groupingAppIdBlacklist; groupingLauncherUrlBlacklist = plasmoid.configuration.groupingLauncherUrlBlacklist; icList.model = tasksModel; tasksStarting = count; ///Plasma 5.9 enforce grouping at all cases if (Latte.WindowSystem.plasmaDesktopVersion >= Latte.WindowSystem.makeVersion(5,9,0)) { groupingWindowTasksThreshold = -1; } } } //! TaskManagerBackend required a groupDialog setting otherwise it crashes. This patch //! sets one just in order not to crash TaskManagerBackend PlasmaCore.Dialog { //ghost group Dialog to not crash TaskManagerBackend id: groupDialogGhost visible: false type: PlasmaCore.Dialog.PopupMenu flags: Qt.WindowStaysOnTopHint hideOnWindowDeactivate: true location: plasmoid.location } TaskManagerApplet.Backend { id: backend taskManagerItem: root toolTipItem: toolTipDelegate highlightWindows: root.highlightWindows onAddLauncher: { tasksModel.requestAddLauncher(url); } Component.onCompleted: { //! In Plasma 5.9 TaskManagerBackend required a groupDialog setting //! otherwise it crashes. //! frameworks 5.29.0 provide id 335104 //! work only after Plasma 5.9 and frameworks 5.29 //! + added a check for groupDialog also when it is present //! in plasma 5.8 (that was introduced after 5.8.5) if (Latte.WindowSystem.frameworksVersion >= 335104 || (groupDialog !== undefined)) { groupDialog = groupDialogGhost; } } } TaskManagerApplet.DragHelper { id: dragHelper dragIconSize: units.iconSizes.medium } TaskManager.VirtualDesktopInfo { id: virtualDesktopInfo } TaskManager.ActivityInfo { id: activityInfo property string previousActivity: "" onCurrentActivityChanged: { root.inActivityChange = true; activityChangeDelayer.start(); } Component.onCompleted: previousActivity = currentActivity; } PlasmaCore.DataSource { id: mpris2Source engine: "mpris2" connectedSources: sources function sourceNameForLauncherUrl(launcherUrl, pid) { if (!launcherUrl || launcherUrl == "") { return ""; } // MPRIS spec explicitly mentions that "DesktopEntry" is with .desktop extension trimmed // Moreover, remove URL parameters, like wmClass (part after the question mark) var desktopFileName = launcherUrl.toString().split('/').pop().split('?')[0].replace(".desktop", "") if (desktopFileName.indexOf("applications:") === 0) { desktopFileName = desktopFileName.substr(13) } for (var i = 0, length = connectedSources.length; i < length; ++i) { var source = connectedSources[i]; // we intend to connect directly, otherwise the multiplexer steals the connection away if (source === "@multiplex") { continue; } var sourceData = data[source]; if (!sourceData || sourceData.DesktopEntry !== desktopFileName) { continue; } if (pid === undefined || sourceData.InstancePid === pid) { return source; } var metadata = sourceData.Metadata; if (metadata) { var kdePid = metadata["kde:pid"]; if (kdePid && pid === kdePid) { return source; } } } return "" } function startOperation(source, op) { var service = serviceForSource(source) var operation = service.operationDescription(op) return service.startOperationCall(operation) } function goPrevious(source) { startOperation(source, "Previous"); } function goNext(source) { startOperation(source, "Next"); } function playPause(source) { startOperation(source, "PlayPause"); } function stop(source) { startOperation(source, "Stop"); } function raise(source) { startOperation(source, "Raise"); } function quit(source) { startOperation(source, "Quit"); } } Loader { id: pulseAudio source: "PulseAudio.qml" active: root.indicateAudioStreams } ParabolicManager{ id: _parabolicManager } /* IconsModel{ id: iconsmdl }*/ Component{ id: attentionTimerComponent Timer{ id: attentionTimer interval:8500 onTriggered: { plasmoid.status = PlasmaCore.Types.PassiveStatus; destroy(); if (latteDock && latteDock.debugModeTimers) { console.log("plasmoid timer: attentionTimer called..."); } } Component.onCompleted: { start(); } } } //Timer to check if the mouse is still inside the ListView //IMPORTANT ::: This timer should be used only when the Latte plasmoid //is not inside a Latte dock Timer{ id:checkListHovered repeat:false; interval: 120 property int normalInterval: Math.max(120, 2 * (root.durationTime * 1.2 * units.shortDuration) + 50) onTriggered: { if(root.latteDock) console.log("Plasmoid, checkListHoveredTimer was called, even though it shouldnt..."); if (!root.containsMouse()) { icList.directRender = false; root.clearZoom(); } interval = normalInterval; if (latteDock && latteDock.debugModeTimers) { console.log("plasmoid timer: checkListHovered called..."); } } function startNormal(){ interval = normalInterval; start(); } function startDuration( duration){ interval = duration; start(); } } //! Delayer in order to not activate directRendering when the mouse //! enters until the timer has ended. This way we make sure that the //! zoom-in animations will have ended. Timer{ id:directRenderDelayerForEnteringTimer interval: 3.2 * root.durationTime * units.shortDuration } //this timer restores the draggingPhase flag to false //after a dragging has finished... This delay is needed //in order to not animate any tasks are added after a //dragging Timer { id: restoreDraggingPhaseTimer interval: 150 onTriggered: inDraggingPhase = false; } ///Red Liner!!! show the upper needed limit for annimations Rectangle{ anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined width: root.vertical ? 1 : 2 * root.iconSize height: root.vertical ? 2 * root.iconSize : 1 color: "red" x: (root.position === PlasmaCore.Types.LeftPositioned) ? neededSpace : parent.width - neededSpace y: (root.position === PlasmaCore.Types.TopPositioned) ? neededSpace : parent.height - neededSpace visible: plasmoid.configuration.zoomHelper property int neededSpace: zoomFactor*(iconSize+iconMargin) + statesLineSize } Item{ id:barLine /* 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 anchors.horizontalCenter: !parent.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: parent.vertical ? parent.verticalCenter : undefined */ width: ( icList.orientation === Qt.Horizontal ) ? icList.width + spacing : smallSize height: ( icList.orientation === Qt.Vertical ) ? icList.height + spacing : smallSize property int spacing: root.iconSize / 2 property int smallSize: Math.max(3.7*root.statesLineSize, 16) Behavior on opacity{ NumberAnimation { duration: root.durationTime*units.longDuration } } /// plasmoid's default panel BorderImage{ anchors.fill:parent source: "../images/panel-west.png" border { left:8; right:8; top:8; bottom:8 } opacity: (plasmoid.configuration.showBarLine && !plasmoid.configuration.useThemePanel && !root.forceHidePanel) ? 1 : 0 visible: (opacity == 0) ? false : true horizontalTileMode: BorderImage.Stretch verticalTileMode: BorderImage.Stretch Behavior on opacity{ NumberAnimation { duration: root.durationTime*units.longDuration } } } /// item which is used as anchors for the plasma's theme Item{ id:belower width: (root.position === PlasmaCore.Types.LeftPositioned) ? shadowsSvgItem.margins.left : shadowsSvgItem.margins.right height: (root.position === PlasmaCore.Types.BottomPositioned)? shadowsSvgItem.margins.bottom : shadowsSvgItem.margins.top anchors.top: (root.position === PlasmaCore.Types.BottomPositioned) ? parent.bottom : undefined anchors.bottom: (root.position === PlasmaCore.Types.TopPositioned) ? parent.top : undefined anchors.right: (root.position === PlasmaCore.Types.LeftPositioned) ? parent.left : undefined anchors.left: (root.position === PlasmaCore.Types.RightPositioned) ? parent.right : undefined } /// the current theme's panel PlasmaCore.FrameSvgItem{ id: shadowsSvgItem anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? belower.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? belower.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? belower.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? belower.right : undefined anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined width: root.vertical ? panelSize + margins.left + margins.right: parent.width height: root.vertical ? parent.height : panelSize + margins.top + margins.bottom imagePath: "translucent/widgets/panel-background" prefix:"shadow" opacity: (plasmoid.configuration.showBarLine && plasmoid.configuration.useThemePanel && !root.forceHidePanel) ? 1 : 0 visible: (opacity == 0) ? false : true property int panelSize: ((root.position === PlasmaCore.Types.BottomPositioned) || (root.position === PlasmaCore.Types.TopPositioned)) ? plasmoid.configuration.panelSize + belower.height: plasmoid.configuration.panelSize + belower.width Behavior on opacity{ NumberAnimation { duration: root.durationTime*units.longDuration } } PlasmaCore.FrameSvgItem{ anchors.margins: belower.width-1 anchors.fill:parent imagePath: plasmoid.configuration.transparentPanel ? "translucent/widgets/panel-background" : "widgets/panel-background" } } MouseHandler { id: mouseHandler anchors.bottom: (root.position === PlasmaCore.Types.BottomPositioned) ? icList.bottom : undefined anchors.top: (root.position === PlasmaCore.Types.TopPositioned) ? icList.top : undefined anchors.left: (root.position === PlasmaCore.Types.LeftPositioned) ? icList.left : undefined anchors.right: (root.position === PlasmaCore.Types.RightPositioned) ? icList.right : undefined anchors.horizontalCenter: !root.vertical ? icList.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? icList.verticalCenter : undefined width: root.vertical ? maxSize : icList.width height: root.vertical ? icList.height : maxSize target: icList property int maxSize: (((root.hoveredIndex>=0 || dockHoveredIndex>=0 ) || windowPreviewIsShown) && !root.dragSource) ? root.statesLineSize + root.zoomFactor * (root.iconSize + root.thickMargin) : root.statesLineSize + root.iconSize + root.thickMargin function onlyLaunchersInList(list){ return list.every(function (item) { return backend.isApplication(item) }); } function urlsDroppedOnArea(urls){ // If all dropped URLs point to application desktop files, we'll add a launcher for each of them. if (onlyLaunchersInList(urls)) { urls.forEach(function (item) { addLauncher(item); }); return; } if (!hoveredItem) { return; } // DeclarativeMimeData urls is a QJsonArray but requestOpenUrls expects a proper QList. var urlsList = backend.jsonArrayToUrlList(urls); // Otherwise we'll just start a new instance of the application with the URLs as argument, // as you probably don't expect some of your files to open in the app and others to spawn launchers. tasksModel.requestOpenUrls(hoveredItem.modelIndex(), urlsList); } onUrlsDropped: { //! inform synced docks for new dropped launchers if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers && onlyLaunchersInList(urls)) { latteDock.universalLayoutManager.launchersSignals.urlsDropped(root.managedLayoutName, latteDock.launchersGroup, urls); return; } //! if the list does not contain only launchers then just open the corresponding //! urls with the relevant app urlsDroppedOnArea(urls); } } ListView { id:icList boundsBehavior: Flickable.StopAtBounds property int currentSpot : -1000 property int hoveredIndex : -1 property int previousCount : 0 property int tasksCount: tasksModel.count property bool directRender: false // onTasksCountChanged: updateImplicits(); // property int count: children ? children.length : 0 /* 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 anchors.horizontalCenter: !root.vertical ? parent.horizontalCenter : undefined anchors.verticalCenter: root.vertical ? parent.verticalCenter : undefined */ width: !root.vertical ? contentWidth : mouseHandler.maxSize height: root.vertical ? contentHeight : mouseHandler.maxSize orientation: Qt.Horizontal delegate: Task.TaskDelegate{} /* Rectangle{ anchors.fill: parent border.width: 1 border.color: "red" color: "transparent" } */ //the duration of this animation should be as small as possible //it fixes a small issue with the dragging an item to change it's //position, if the duration is too big there is a point in the //list that an item is going back and forth too fast //more of a trouble moveDisplaced: Transition { NumberAnimation { properties: "x,y"; duration: root.durationTime*units.longDuration; easing.type: Easing.Linear } } ///this transition can not be used with dragging !!!! I breaks ///the lists indexes !!!!! /* move: Transition { NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.Linear } } */ function childAtPos(x, y){ var tasks = icList.contentItem.children; for(var i=0; i=choords.x) && (x<=choords.x+task.width) && (y>=choords.y) && (y<=choords.y+task.height)){ return task; } } return null; } function childAtIndex(position) { var tasks = icList.contentItem.children; if (position < 0) return; for(var i=0; i=0; --i) { + if (currentLaunchers[i] !== launchers[i]) { + var p = launcherValidPos(currentLaunchers[i]); + if (p === -1) { + console.log("No pos found for :"+currentLaunchers[i] + " at: "+launchers); + restart(); + return; + } + + console.log(" moving:" +i + " _ " + p ); + tasksModel.move(i, p); + restart(); + return; + } + } + } + + console.log("why we reached ??? "); + console.log("CURRENT ::: " + currentLaunchers); + console.log("VALID ::: " + launchers); + } + } + } + ///////// //// functions function movePanel(obj, newPosition){ var bLine = obj; if (newPosition === PlasmaCore.Types.BottomPositioned){ bLine.anchors.horizontalCenter = bLine.parent.horizontalCenter; bLine.anchors.verticalCenter = undefined; bLine.anchors.bottom = bLine.parent.bottom; bLine.anchors.top = undefined; bLine.anchors.left = undefined; bLine.anchors.right = undefined; } else if (newPosition === PlasmaCore.Types.TopPositioned){ bLine.anchors.horizontalCenter = bLine.parent.horizontalCenter; bLine.anchors.verticalCenter = undefined; bLine.anchors.bottom = undefined; bLine.anchors.top = bLine.parent.top; bLine.anchors.left = undefined; bLine.anchors.right = undefined; } else if (newPosition === PlasmaCore.Types.LeftPositioned){ bLine.anchors.horizontalCenter = undefined; bLine.anchors.verticalCenter = bLine.parent.verticalCenter; bLine.anchors.bottom = undefined; bLine.anchors.top = undefined; bLine.anchors.left = bLine.parent.left; bLine.anchors.right = undefined; } else if (newPosition === PlasmaCore.Types.RightPositioned){ bLine.anchors.horizontalCenter = undefined; bLine.anchors.verticalCenter = bLine.parent.verticalCenter; bLine.anchors.bottom = undefined; bLine.anchors.top = undefined; bLine.anchors.left =undefined; bLine.anchors.right = bLine.parent.right; } } property int ncounter:0 function updateImplicits(){ if(icList.previousCount !== icList.count){ icList.previousCount = icList.count; var zoomedLength = Math.floor( 1.2 * (iconSize+thickMargin) * (root.zoomFactor)); var bigAxis = (tasksModel.count-1) * (iconSize+thickMargin) + zoomedLength; var smallAxis = zoomedLength + statesLineSize; var clearBigAxis = tasksModel.count * (iconSize+thickMargin) + (barLine.spacing/2); var clearSmallAxis = (iconSize+thickMargin)+statesLineSize; // debugging code // ncounter++; // console.log("Implicits______ "+ncounter+". - "+tasksModel.count); if (root.vertical){ root.implicitWidth = smallAxis; root.implicitHeight = bigAxis; root.clearWidth = clearSmallAxis; root.clearHeight = clearBigAxis; } else{ root.implicitWidth = bigAxis; root.implicitHeight = smallAxis; root.clearWidth = clearBigAxis; root.clearHeight = clearSmallAxis; } iconGeometryTimer.restart(); } } PlasmaComponents.Button{ id: orientationBtn text:"Orientation" anchors.centerIn: parent visible: root.debugLocation onClicked:{ switch(root.position){ case PlasmaCore.Types.BottomPositioned: root.newLocationDebugUse = PlasmaCore.Types.LeftEdge; break; case PlasmaCore.Types.LeftPositioned: root.newLocationDebugUse = PlasmaCore.Types.TopEdge; break; case PlasmaCore.Types.TopPositioned: root.newLocationDebugUse = PlasmaCore.Types.RightEdge; break; case PlasmaCore.Types.RightPositioned: root.newLocationDebugUse = PlasmaCore.Types.BottomEdge; break; } updatePosition(); } } function addInternalSeparatorAtPos(pos) { var separatorName = parabolicManager.freeAvailableSeparatorName(); if (separatorName !== "") { parabolicManager.addLauncherToBeMoved(separatorName, Math.max(0,pos)); if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.addLauncher(root.managedLayoutName, latteDock.launchersGroup, separatorName); } else { tasksModel.requestAddLauncher(separatorName); } } } // This is called by dockcorona in response to a Meta+number shortcut. function activateTaskAtIndex(index) { if (typeof index !== "number") { return; } var tasks = icList.contentItem.children; //! this is used to bypass the internal separators if they exist var confirmedIndex = parabolicManager.realTaskIndex(index - 1); for(var i=0; i=0 ? ident1.substring(n + 1) : identifier; for(var i=0; i= 0) { return badgers[i]; } } } function updateBadge(identifier, value) { var tasks = icList.contentItem.children; var identifierF = identifier.concat(".desktop"); for(var i=0; i= 0) { task.badgeIndicator = value === "" ? 0 : Number(value); var badge = getBadger(identifierF); if (badge) { badge.value = value; } else { badgers.push({id: identifierF, value: value}); } } } } function getLauncherList() { return plasmoid.configuration.launchers59; } //! BEGIN ::: external launchers signals in order to update the tasks model function extSignalAddLauncher(group, launcher) { if (group === latteDock.launchersGroup) { tasksModel.requestAddLauncher(launcher); launchersUpdatedFor(launcher); } } function extSignalRemoveLauncher(group, launcher) { if (group === latteDock.launchersGroup) { root.launcherForRemoval = launcher; tasksModel.requestRemoveLauncher(launcher); launchersUpdatedFor(launcher); } } function extSignalAddLauncherToActivity(group, launcher, activity) { if (group === latteDock.launchersGroup) { var launcherActivities = tasksModel.launcherActivities(launcher); if (activity !== tasksModel.activity && (launcherActivities[0] === "00000000-0000-0000-0000-000000000000")) { root.launcherForRemoval = launcher; } tasksModel.requestAddLauncherToActivity(launcher, activity); launchersUpdatedFor(launcher); } } function extSignalRemoveLauncherFromActivity(group, launcher, activity) { if (group === latteDock.launchersGroup) { if (activity === tasksModel.activity) { root.launcherForRemoval = launcher; } tasksModel.requestRemoveLauncherFromActivity(launcher, activity); launchersUpdatedFor(launcher); } } function extSignalUrlsDropped(group, urls) { if (group === latteDock.launchersGroup) { mouseHandler.urlsDroppedOnArea(urls); } } function extSignalMoveTask(group, from, to) { if (group === latteDock.launchersGroup && !root.dragSource) { - tasksModel.move(from, to); + //! disable syncing for moving launchers action in favor of validatorOrder launchersSignal + /* tasksModel.move(from, to); parabolicManager.updateTasksEdgesIndexes(); - root.separatorsUpdated(); + root.separatorsUpdated();*/ + } + } + + function extSignalValidateLaunchersOrder(group, launchers) { + if (group === latteDock.launchersGroup && !root.dragSource) { + launchersOrderValidatorTimer.stop(); + launchersOrderValidatorTimer.launchers = launchers; + launchersOrderValidatorTimer.start(); } } //! END ::: external launchers signals in order to update the tasks model //! it is used to add the fake desktop file which represents //! the separator (fake launcher) function addSeparator(pos){ var separatorName = parabolicManager.freeAvailableSeparatorName(); if (separatorName !== "") { parabolicManager.addLauncherToBeMoved(separatorName, Math.max(0,pos)); if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.addLauncher(latteDock.launchersGroup, separatorName); } else { tasksModel.requestAddLauncher(separatorName); } } } function removeLastSeparator(){ var separatorName = parabolicManager.lastPresentSeparatorName(); if (separatorName !== "") { if (latteDock && latteDock.launchersGroup >= Latte.Dock.LayoutLaunchers) { latteDock.universalLayoutManager.launchersSignals.removeLauncher(root.managedLayoutName, latteDock.launchersGroup, separatorName); } else { root.launcherForRemoval = separatorName; tasksModel.requestRemoveLauncher(separatorName); } } } //! show/hide tasks numbered badges e.g. from global shortcuts function setShowTasksNumbers(showNumbers){ showTasksNumbers = showNumbers; } //! setup the tasks first index based on the fact that this is a plasmoid //! and applets could exist before it function setTasksNumbersBase(base){ tasksNumbersBase = base; } function previewContainsMouse() { if(toolTipDelegate && toolTipDelegate.containsMouse && toolTipDelegate.parentTask) return true; else return false; } function containsMouse(){ //console.log("s1..."); if (disableRestoreZoom && (root.contextMenu || windowsPreviewDlg.visible)) { return; } else { disableRestoreZoom = false; } //if (previewContainsMouse()) // windowsPreviewDlg.hide(4); if (previewContainsMouse()) return true; //console.log("s3..."); var tasks = icList.contentItem.children; for(var i=0; i0) { url = url.substring( 0, url.indexOf("?iconData=" ) ); } tasksModel.requestAddLauncher(url); launchersUpdatedFor(url); } function resetDragSource() { dragSource.z = 0; dragSource = null; } function setGlobalDirectRender(value) { if (waitingLaunchers.length > 0) return; if (latteDock) { latteDock.setGlobalDirectRender(value); } else { if (value === true) { if (root.containsMouse()) { icList.directRender = true; } else { // console.log("direct render true ignored..."); } } else { icList.directRender = false; } } } function startCheckRestoreZoomTimer(duration) { if (latteDock) { latteDock.startCheckRestoreZoomTimer(); } else { if (duration > 0) { checkListHovered.startDuration(duration); } else { checkListHovered.startNormal(); } } } function stopCheckRestoreZoomTimer() { if (latteDock) { latteDock.stopCheckRestoreZoomTimer(); } else { checkListHovered.stop(); } } function startDirectRenderDelayerDuringEntering(){ if (latteDock) { latteDock.startDirectRenderDelayerDuringEntering(); } else { directRenderDelayerForEnteringTimer.start(); } } ///REMOVE /*function createContextMenu(task) { var menu = root.contextMenuComponent.createObject(task); menu.visualParent = task; menu.mpris2Source = mpris2Source; menu.activitiesCount = activityModelInstance.count; return menu; }*/ function createContextMenu(rootTask, modelIndex, args) { var initialArgs = args || {} initialArgs.visualParent = rootTask; initialArgs.modelIndex = modelIndex; initialArgs.mpris2Source = mpris2Source; initialArgs.backend = backend; root.contextMenu = root.contextMenuComponent.createObject(rootTask, initialArgs); return root.contextMenu; } Component.onCompleted: { updatePosition(); root.presentWindows.connect(backend.presentWindows); root.windowsHovered.connect(backend.windowsHovered); dragHelper.dropped.connect(resetDragSource); } Component.onDestruction: { root.presentWindows.disconnect(backend.presentWindows); root.windowsHovered.disconnect(backend.windowsHovered); dragHelper.dropped.disconnect(resetDragSource); } //BEGIN states //user set Panel Positions // 0-Center, 1-Left, 2-Right, 3-Top, 4-Bottom states: [ ///Bottom Edge State { name: "bottomCenter" when: (root.position === PlasmaCore.Types.BottomPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } }, State { name: "bottomLeft" when: (root.position === PlasmaCore.Types.BottomPosition && userPanelPosition===Latte.Dock.Left) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "bottomRight" when: (root.position === PlasmaCore.Types.BottomPosition && userPanelPosition===Latte.Dock.Right) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } }, ///Top Edge State { name: "topCenter" when: (root.position === PlasmaCore.Types.TopPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:undefined; right:undefined; horizontalCenter:parent.horizontalCenter; verticalCenter:undefined} } }, State { name: "topLeft" when: (root.position === PlasmaCore.Types.TopPosition && userPanelPosition===Latte.Dock.Left) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "topRight" when: (root.position === PlasmaCore.Types.TopPosition && userPanelPosition===Latte.Dock.Right) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } }, ////Left Edge State { name: "leftCenter" when: (root.position === PlasmaCore.Types.LeftPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } AnchorChanges { target: icList anchors{ top:undefined; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } }, State { name: "leftTop" when: (root.position === PlasmaCore.Types.LeftPosition && userPanelPosition===Latte.Dock.Top) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "leftBottom" when: (root.position === PlasmaCore.Types.LeftPosition && userPanelPosition===Latte.Dock.Bottom) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:parent.left; right:undefined; horizontalCenter:undefined; verticalCenter:undefined} } }, ///Right Edge State { name: "rightCenter" when: (root.position === PlasmaCore.Types.RightPosition && userPanelPosition===Latte.Dock.Center) AnchorChanges { target: barLine anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } AnchorChanges { target: icList anchors{ top:undefined; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:parent.verticalCenter} } }, State { name: "rightTop" when: (root.position === PlasmaCore.Types.RightPosition && userPanelPosition===Latte.Dock.Top) AnchorChanges { target: barLine anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:parent.top; bottom:undefined; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } }, State { name: "rightBottom" when: (root.position === PlasmaCore.Types.RightPosition && userPanelPosition===Latte.Dock.Bottom) AnchorChanges { target: barLine anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } AnchorChanges { target: icList anchors{ top:undefined; bottom:parent.bottom; left:undefined; right:parent.right; horizontalCenter:undefined; verticalCenter:undefined} } } ] //END states } diff --git a/plasmoid/package/contents/ui/task/TaskDelegate.qml b/plasmoid/package/contents/ui/task/TaskDelegate.qml index 3f004002..e7d5745d 100644 --- a/plasmoid/package/contents/ui/task/TaskDelegate.qml +++ b/plasmoid/package/contents/ui/task/TaskDelegate.qml @@ -1,1569 +1,1558 @@ /* * 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 { //! 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 diff --git a/plasmoid/package/contents/ui/task/TaskWindows.qml b/plasmoid/package/contents/ui/task/TaskWindows.qml index ef9b78f4..060dc192 100644 --- a/plasmoid/package/contents/ui/task/TaskWindows.qml +++ b/plasmoid/package/contents/ui/task/TaskWindows.qml @@ -1,282 +1,302 @@ /* * 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 QtQml.Models 2.2 //trying to do a very simple thing to count how many windows does //a task instace has... //Workaround the mess with launchers, startups, windows etc. Item{ id: windowsContainer property int windowsCount: 0 property bool isLauncher: IsLauncher ? true : false property bool isStartup: IsStartup ? true : false property bool isWindow: IsWindow ? true : false property int lastActiveWinInGroup: -1 onIsLauncherChanged: updateCounter(); // onIsStartupChanged: updateCounter(); // onIsWindowChanged: updateCounter(); //states that exist in windows in a Group of windows property bool hasMinimized: false; property bool hasShown: false; property bool hasActive: false; //FIXME: For some reason the index is not updated correctly in some cases (e.g. window dragging, repositioning launchers) // and this way much beautiful information are lost, an activity change back and return, // it fixes this sometimes... Repeater{ model:DelegateModel { id: windowsLocalModel model: tasksModel //icList.model - rootIndex: tasksModel.makeModelIndex(currentIndex >=0 ? currentIndex : index) + /* rootIndex: { + if (root.inDraggingPhase) { + return tasksModel.makeModelIndex(lastValidIndex); + } + + return tasksModel.makeModelIndex(currentIndex >=0 ? currentIndex : index) + }*/ property int currentIndex: -1 + //! Trying to avoid a crash during dragging tasks/launchers + Binding{ + target: windowsLocalModel + property: "rootIndex" + + value: { + if (root.inDraggingPhase) { + return 0; + } + + return tasksModel.makeModelIndex(currentIndex >=0 ? currentIndex : index) + } + } + delegate: Item{ readonly property string title: display readonly property bool isMinimized: IsMinimized === true ? true : false onIsMinimizedChanged: windowsContainer.initializeStates(); } } onCountChanged:{ windowsContainer.updateCounter(); } } function initializeStates(){ hasMinimized = false; hasShown = false; hasActive = false; if(IsGroupParent){ checkInternalStates(); } else{ if(mainItemContainer.isActive) hasActive = true; if(mainItemContainer.isMinimized){ hasMinimized = true; } else { hasShown = true; } } } function checkInternalStates(){ windowsLocalModel.currentIndex = index; var childs = windowsLocalModel.items; for(var i=0; i 0) { title = title.substring(0, lst); }*/ result.push(title); } return result; } //! function which is used to cycle activation into //! a group of windows function activateNextTask() { if (!mainItemContainer.isGroupParent) { return; } windowsLocalModel.currentIndex = index; var childs = windowsLocalModel.items; var nextAvailableWindow = -1; for(var i=0; i= childs.count) { nextAvailableWindow = 0; } if (nextAvailableWindow === -1 && lastActiveWinInGroup !==-1){ for(var i=0; i=0; --i){ var kid = childs.get(i); if (kid.model.IsActive === true) { prevAvailableWindow = i - 1; break; } } //the active window is 0 if (prevAvailableWindow == -1) { prevAvailableWindow = childs.count-1; } if (prevAvailableWindow === -2 && lastActiveWinInGroup !==-1){ for(var i=childs.count-1; i>=0; --i){ var kid = childs.get(i); if (kid.model.LegacyWinIdList[0] === lastActiveWinInGroup) { prevAvailableWindow = i; break; } } } //no window was found if (prevAvailableWindow === -2) prevAvailableWindow = 0; tasksModel.requestActivate(tasksModel.makeModelIndex(index,prevAvailableWindow)); } // keep a record of the last active window in a group Connections{ target:tasksModel onActiveTaskChanged:{ if (!mainItemContainer.isGroupParent) { return; } windowsLocalModel.currentIndex = index; var childs = windowsLocalModel.items; for(var i=0; i=0){ if(IsGroupParent){ windowsLocalModel.currentIndex = index; var tempC = windowsLocalModel.count; if (tempC == 0){ if(isLauncher){ windowsCount = 0; } else if(isWindow || isStartup){ windowsCount = 1; } } else{ windowsCount = tempC; } } else{ if(isLauncher){ windowsCount = 0; } else if(isWindow || isStartup){ windowsCount = 1; } } initializeStates(); } } } diff --git a/plasmoid/package/contents/ui/task/animations/TaskRealRemovalAnimation.qml b/plasmoid/package/contents/ui/task/animations/TaskRealRemovalAnimation.qml index 62257ecf..c0b06d23 100644 --- a/plasmoid/package/contents/ui/task/animations/TaskRealRemovalAnimation.qml +++ b/plasmoid/package/contents/ui/task/animations/TaskRealRemovalAnimation.qml @@ -1,200 +1,200 @@ /* * 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.latte 0.1 as Latte SequentialAnimation { id: taskRealRemovalAnimation PropertyAction { target: mainItemContainer; property: "ListView.delayRemove"; value: true } PropertyAction { target: mainItemContainer; property: "inAnimation"; value: true } PropertyAction { target: mainItemContainer; property: "inAddRemoveAnimation"; value: true } PropertyAction { target: mainItemContainer; property: "inRemoveStage"; value: true } //Animation Add/Remove (1) - when is window with no launcher, animations enabled //Animation Add/Remove (4) - the user removes a launcher, animation enabled property bool animation1: ((((tasksModel.launcherPosition(mainItemContainer.launcherUrl) === -1) && (tasksModel.launcherPosition(mainItemContainer.launcherUrlWithIcon) === -1) ) - || !launcherIsPresent(mainItemContainer.launcherUrl)) + || !tasksModel.launcherInCurrentActivity(mainItemContainer.launcherUrl)) && !mainItemContainer.isStartup && Latte.WindowSystem.compositingActive) property bool animation4: ((mainItemContainer.launcherUrl===root.launcherForRemoval || mainItemContainer.launcherUrlWithIcon===root.launcherForRemoval ) && !mainItemContainer.isStartup && Latte.WindowSystem.compositingActive) property bool enabledAnimation: (animation1 || animation4) && (root.durationTime !== 0) && !mainItemContainer.inBouncingAnimation && !mainItemContainer.isSeparator && mainItemContainer.visible; ScriptAction{ script:{ //! When a window is removed and afterwards its launcher must be shown immediately! if (!enabledAnimation && mainItemContainer.isWindow && !mainItemContainer.isSeparator && tasksModel.launcherPosition(mainItemContainer.launcherUrl) !== -1 && !root.immediateLauncherExists(mainItemContainer.launcherUrl)){ root.addImmediateLauncher(mainItemContainer.launcherUrl); } //trying to fix the ListView nasty behavior //during the removal the anchoring for ListView children changes a lot var previousTask = icList.childAtIndex(mainItemContainer.lastValidIndex-1); if (previousTask !== undefined && !previousTask.isStartup && !previousTask.inBouncingAnimation){ //! When removing a task and there are surrounding separators then the hidden spacers //! are updated immediately for the neighbour tasks. In such case in order to not break //! the removal animation a small margin must applied var nextTaskIsSeparator = (lastValidIndex !== -1) && enabledAnimation && ((mainItemContainer.hasNeighbourSeparator(lastValidIndex+1,true) && !mainItemContainer.isSeparator && lastValidIndexparabolicManager.lastRealTaskIndex)); var previousTaskIsSeparator = (lastValidIndex !== -1) && enabledAnimation && ((mainItemContainer.hasNeighbourSeparator(lastValidIndex-1,false) && !mainItemContainer.isSeparator && lastValidIndex>parabolicManager.firstRealTaskIndex) || (latteDock && latteDock.parabolicManager.isSeparator(latteDock.latteAppletPos-1) && lastValidIndex<=parabolicManager.firstRealTaskIndex)); var spacer = nextTaskIsSeparator ? -(2+root.iconMargin/2) : ( previousTaskIsSeparator ? (2+root.iconMargin/2)/2 : 0); //console.log("EDGES ::: " + parabolicManager.firstRealTaskIndex + " _ " + parabolicManager.lastRealTaskIndex); //console.log("Removing ::: " + lastValidIndex + " _ " + launcherUrl + " _ " + previousTaskIsSeparator + " _ " + nextTaskIsSeparator); if (root.vertical) { mainItemContainer.anchors.top = previousTask.bottom; mainItemContainer.anchors.topMargin = spacer; } else { mainItemContainer.anchors.left = previousTask.right; mainItemContainer.anchors.leftMargin = spacer; } } // console.log("1." + mainItemContainer.launcherUrl + " - " + taskRealRemovalAnimation.enabledAnimation); // console.log("2." + root.launcherForRemoval + " - " + mainItemContainer.isLauncher); root.signalAnimationsNeedLength(1); if (wrapper.mScale > 1 && !taskRealRemovalAnimation.enabledAnimation && !mainItemContainer.inBouncingAnimation && Latte.WindowSystem.compositingActive) { parabolicManager.setFrozenTask(mainItemContainer.launcherUrl, wrapper.mScale); } } } //Ghost animation that acts as a delayer in case there is a bouncing animation //taking place PropertyAnimation { target: wrapper property: "opacity" to: 1 //this duration must be a bit less than the bouncing animation. Otherwise the //smooth trasition between removals is breaking duration: mainItemContainer.inBouncingAnimation && !mainItemContainer.isSeparator? 4*launcherSpeedStep + 50 : 0 easing.type: Easing.InQuad property int launcherSpeedStep: root.durationTime * 0.8 * units.longDuration } //end of ghost animation PropertyAnimation { target: wrapper property: "mScale" to: 1 duration: taskRealRemovalAnimation.enabledAnimation ? showWindowAnimation.speed : 0 easing.type: Easing.InQuad } //PropertyAction { target: wrapper; property: "opacity"; value: isWindow ? 0 : 1 } //animation mainly for launchers removal and startups ParallelAnimation{ id: removalAnimation // property int speed: (IsStartup && !mainItemContainer.visible)? 0 : 400 //property int speed: 400 NumberAnimation { target: wrapper; property: "opacity"; to: 0; duration: taskRealRemovalAnimation.enabledAnimation ? 1.35*showWindowAnimation.speed : 0 easing.type: Easing.InQuad } PropertyAnimation { target: wrapper property: (icList.orientation === Qt.Vertical) ? "tempScaleWidth" : "tempScaleHeight" to: 0 duration: taskRealRemovalAnimation.enabledAnimation ? 1.35*showWindowAnimation.speed : 0 easing.type: Easing.InQuad } } //smooth move into place the surrounding tasks PropertyAnimation { target: wrapper property: (icList.orientation === Qt.Vertical) ? "tempScaleHeight" : "tempScaleWidth" to: 0 duration: taskRealRemovalAnimation.enabledAnimation ? 1.35*showWindowAnimation.speed : 0 easing.type: Easing.InQuad } ScriptAction{ script:{ if (showWindowAnimation.animationSent){ //console.log("SAFETY REMOVAL 1: animation removing ended"); showWindowAnimation.animationSent = false; root.signalAnimationsNeedLength(-1); } root.signalAnimationsNeedLength(-1); if(mainItemContainer.launcherUrl===root.launcherForRemoval && mainItemContainer.isLauncher) root.launcherForRemoval=""; if (windowsPreviewDlg.visible && windowsPreviewDlg.mainItem.parentTask === mainItemContainer && isWindow && !isGroupParent){ hidePreview(); } if (root.showWindowsOnlyFromLaunchers) { if (root.vertical) { mainItemContainer.anchors.top = undefined; mainItemContainer.anchors.topMargin = 0; } else { mainItemContainer.anchors.left = undefined; mainItemContainer.anchors.leftMargin = 0; } } mainItemContainer.visible = false; //send signal that the launcher is really removing if (mainItemContainer.inBouncingAnimation) { root.removeWaitingLauncher(mainItemContainer.launcherUrl); root.setGlobalDirectRender(false); } } } PropertyAction { target: mainItemContainer; property: "inAnimation"; value: false } PropertyAction { target: mainItemContainer; property: "inAddRemoveAnimation"; value: false } PropertyAction { target: mainItemContainer; property: "inRemoveStage"; value: false } PropertyAction { target: mainItemContainer; property: "ListView.delayRemove"; value: false } } diff --git a/plasmoid/package/contents/ui/task/animations/TaskShowWindowAnimation.qml b/plasmoid/package/contents/ui/task/animations/TaskShowWindowAnimation.qml index 3c6b01ec..000aea1a 100644 --- a/plasmoid/package/contents/ui/task/animations/TaskShowWindowAnimation.qml +++ b/plasmoid/package/contents/ui/task/animations/TaskShowWindowAnimation.qml @@ -1,200 +1,200 @@ /* * 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.latte 0.1 as Latte ///item's added Animation SequentialAnimation{ id:showWindowAnimation property int speed: Latte.WindowSystem.compositingActive ? root.durationTime* (1.2*units.longDuration) : 0 property bool animationSent: false //Ghost animation that acts as a delayer, in order to fix #342 PropertyAnimation { target: wrapper property: "opacity" to: 0 //it is not depend to durationTime when animations are active duration: root.durationTime > 0 ? 750 : 0 easing.type: Easing.InQuad } //end of ghost animation ScriptAction{ script:{ if (!showWindowAnimation.animationSent) { showWindowAnimation.animationSent = true; root.signalAnimationsNeedLength(1); } } } PropertyAnimation { target: wrapper property: (icList.orientation == Qt.Vertical) ? "tempScaleHeight" : "tempScaleWidth" to: 1 duration: showWindowAnimation.speed easing.type: Easing.OutQuad } ParallelAnimation{ PropertyAnimation { target: wrapper property: (icList.orientation == Qt.Vertical) ? "tempScaleWidth" : "tempScaleHeight" to: 1 duration: showWindowAnimation.speed easing.type: Easing.OutQuad } PropertyAnimation { target: wrapper property: "opacity" from: 0 to: 1 duration: showWindowAnimation.speed easing.type: Easing.OutQuad } } onStopped: { mainItemContainer.inAddRemoveAnimation = false; if(mainItemContainer.isWindow || mainItemContainer.isStartup){ taskInitComponent.createObject(wrapper); if (mainItemContainer.isDemandingAttention){ mainItemContainer.groupWindowAdded(); } } mainItemContainer.inAnimation = false; if (showWindowAnimation.animationSent) { root.signalAnimationsNeedLength(-1); showWindowAnimation.animationSent = false; } } function execute(){ //trying to fix the ListView nasty behavior //during the removal the anchoring for ListView children changes a lot if (isWindow){ var previousTask = icList.childAtIndex(index-1); var nextTask = icList.childAtIndex(index+1); if (previousTask !== undefined && nextTask !== undefined && nextTask.inBouncingAnimation){ if (root.vertical) { mainItemContainer.anchors.top = previousTask.bottom; } else { mainItemContainer.anchors.left = previousTask.right; } } } var hasShownLauncher = ((tasksModel.launcherPosition(mainItemContainer.launcherUrl) !== -1) || (tasksModel.launcherPosition(mainItemContainer.launcherUrlWithIcon) !== -1) ); var launcherIsAlreadyShown = hasShownLauncher && isLauncher && !root.inActivityChange; //Animation Add/Remove (2) - when is window with no launcher, animations enabled //Animation Add/Remove (3) - when is launcher with no window, animations enabled - var animation2 = ((!hasShownLauncher || !launcherIsPresent(mainItemContainer.launcherUrl)) + var animation2 = ((!hasShownLauncher || !tasksModel.launcherInCurrentActivity(mainItemContainer.launcherUrl)) && mainItemContainer.isWindow && Latte.WindowSystem.compositingActive); var animation3 = (!root.immediateLauncherExists(mainItemContainer.launcherUrl) && mainItemContainer.isLauncher && Latte.WindowSystem.compositingActive); var activities = tasksModel.launcherActivities(mainItemContainer.launcherUrl); var animation6 = (root.inActivityChange && mainItemContainer.isWindow && activities.indexOf(activityInfo.currentActivity)>=0 && activities.indexOf(activityInfo.previousActivity) === -1 && Latte.WindowSystem.compositingActive); //startup without launcher, animation should be blocked - var launcherExists = !(!hasShownLauncher || !launcherIsPresent(mainItemContainer.launcherUrl)); + var launcherExists = !(!hasShownLauncher || !tasksModel.launcherInCurrentActivity(mainItemContainer.launcherUrl)); //var hideStartup = launcherExists && mainItemContainer.isStartup; //! fix #976 var hideWindow = root.showWindowsOnlyFromLaunchers && !launcherExists && mainItemContainer.isWindow; if (root.immediateLauncherExists(mainItemContainer.launcherUrl) && mainItemContainer.isLauncher) { root.removeImmediateLauncher(mainItemContainer.launcherUrl); } //if (hideStartup || hideWindow) { //fix #976 if (hideWindow) { isForcedHidden = true; mainItemContainer.visible = false; wrapper.tempScaleWidth = 0; wrapper.tempScaleHeight = 0; wrapper.opacity = 0; mainItemContainer.inAnimation = false; } else if (!Latte.WindowSystem.compositingActive || root.inDraggingPhase || mainItemContainer.isSeparator) { isForcedHidden = false; mainItemContainer.visible = true; wrapper.tempScaleWidth = 1; wrapper.tempScaleHeight = 1; wrapper.mScale = 1; wrapper.opacity = 1; mainItemContainer.inAnimation = false; } else if (( animation2 || animation3 || animation6 || isForcedHidden) && (root.durationTime !== 0) && !launcherIsAlreadyShown){ isForcedHidden = false; mainItemContainer.visible = true; wrapper.tempScaleWidth = 0; wrapper.tempScaleHeight = 0; start(); } else { isForcedHidden = false; var frozenTask = parabolicManager.getFrozenTask(mainItemContainer.launcherUrl); if (frozenTask && frozenTask.mScale>1) { wrapper.mScale = frozenTask.mScale; parabolicManager.removeFrozenTask(mainItemContainer.launcherUrl); } else { wrapper.tempScaleWidth = 1; wrapper.tempScaleHeight = 1; } //! by enabling it we break the bouncing animation //mainItemContainer.visible = true; wrapper.opacity = 1; mainItemContainer.inAnimation = false; } } function showWindow(){ execute(); } Component.onDestruction: { if (animationSent){ //console.log("SAFETY REMOVAL 2: animation removing ended"); animationSent = false; root.signalAnimationsNeedLength(-1); } } }