diff --git a/applets/kickoff/package/contents/config/main.xml b/applets/kickoff/package/contents/config/main.xml
index 541915912..3ca76f041 100644
--- a/applets/kickoff/package/contents/config/main.xml
+++ b/applets/kickoff/package/contents/config/main.xml
@@ -1,47 +1,47 @@
true
false
start-here-kde
- preferred://browser,kontact.desktop,systemsettings.desktop,org.kde.dolphin.desktop,ktp-contactlist.desktop,org.kde.kate.desktop,org.kde.discover
+ preferred://browser,kontact.desktop,systemsettings.desktop,org.kde.dolphin.desktop,ktp-contactlist.desktop,org.kde.kate.desktop,org.kde.discover.desktop
systemsettings.desktop,org.kde.kinfocenter.desktop
true
shell,bookmarks,recentdocuments,locations,baloosearch
bookmark:t,application:t,computer:t,used:t,leave:t
false
diff --git a/applets/taskmanager/package/contents/ui/ContextMenu.qml b/applets/taskmanager/package/contents/ui/ContextMenu.qml
index 435261610..7d220f6e9 100644
--- a/applets/taskmanager/package/contents/ui/ContextMenu.qml
+++ b/applets/taskmanager/package/contents/ui/ContextMenu.qml
@@ -1,659 +1,659 @@
/***************************************************************************
* Copyright (C) 2012-2016 by Eike Hein *
* Copyright (C) 2016 by Kai Uwe Broulik *
* *
* This program 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. *
* *
* This program 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, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
import QtQuick 2.0
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.taskmanager 0.1 as TaskManager
PlasmaComponents.ContextMenu {
id: menu
property QtObject mpris2Source
property var modelIndex
readonly property var atm: TaskManager.AbstractTasksModel
placement: {
if (plasmoid.location == PlasmaCore.Types.LeftEdge) {
return PlasmaCore.Types.RightPosedTopAlignedPopup;
} else if (plasmoid.location == PlasmaCore.Types.TopEdge) {
return PlasmaCore.Types.BottomPosedLeftAlignedPopup;
} else {
return PlasmaCore.Types.TopPosedLeftAlignedPopup;
}
}
minimumWidth: visualParent.width
onStatusChanged: {
if (visualParent && get(atm.LauncherUrlWithoutIcon) != null && status == PlasmaComponents.DialogStatus.Open) {
launcherToggleAction.checked = (tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) != -1);
activitiesDesktopsMenu.refresh();
} else if (status == PlasmaComponents.DialogStatus.Closed) {
menu.destroy();
+ backend.ungrabMouse(visualParent);
}
}
function get(modelProp) {
return tasksModel.data(modelIndex, modelProp)
}
function show() {
loadDynamicLaunchActions(get(atm.LauncherUrlWithoutIcon));
- backend.ungrabMouse(visualParent);
openRelative();
}
function newMenuItem(parent) {
return Qt.createQmlObject(
"import org.kde.plasma.components 2.0 as PlasmaComponents;" +
"PlasmaComponents.MenuItem {}",
parent);
}
function newSeparator(parent) {
return Qt.createQmlObject(
"import org.kde.plasma.components 2.0 as PlasmaComponents;" +
"PlasmaComponents.MenuItem { separator: true }",
parent);
}
function loadDynamicLaunchActions(launcherUrl) {
var actionList = backend.jumpListActions(launcherUrl, menu);
for (var i = 0; i < actionList.length; ++i) {
var item = newMenuItem(menu);
item.action = actionList[i];
menu.addMenuItem(item, virtualDesktopsMenuItem);
}
if (actionList.length > 0) {
menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem);
}
var actionList = backend.recentDocumentActions(launcherUrl, menu);
for (var i = 0; i < actionList.length; ++i) {
var item = newMenuItem(menu);
item.action = actionList[i];
menu.addMenuItem(item, virtualDesktopsMenuItem);
}
if (actionList.length > 0) {
menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem);
}
// Add Media Player control actions
var sourceName = mpris2Source.sourceNameForLauncherUrl(launcherUrl, get(atm.AppPid));
if (sourceName && !(get(atm.LegacyWinIdList) != undefined && get(atm.LegacyWinIdList).length > 1)) {
var playerData = mpris2Source.data[sourceName]
if (playerData.CanControl) {
var menuItem = menu.newMenuItem(menu);
menuItem.text = i18nc("Play previous track", "Previous Track");
menuItem.icon = "media-skip-backward";
menuItem.enabled = Qt.binding(function() {
return playerData.CanGoPrevious;
});
menuItem.clicked.connect(function() {
mpris2Source.goPrevious(sourceName);
});
menu.addMenuItem(menuItem, virtualDesktopsMenuItem);
menuItem = menu.newMenuItem(menu);
// PlasmaCore Menu doesn't actually handle icons or labels changing at runtime...
menuItem.text = Qt.binding(function() {
return playerData.PlaybackStatus === "Playing" ? i18nc("Pause playback", "Pause") : i18nc("Start playback", "Play");
});
menuItem.icon = Qt.binding(function() {
return playerData.PlaybackStatus === "Playing" ? "media-playback-pause" : "media-playback-start";
});
menuItem.clicked.connect(function() {
mpris2Source.playPause(sourceName);
});
menu.addMenuItem(menuItem, virtualDesktopsMenuItem);
menuItem = menu.newMenuItem(menu);
menuItem.text = i18nc("Stop playback", "Stop");
menuItem.icon = "media-playback-stop";
menuItem.clicked.connect(function() {
mpris2Source.stop(sourceName);
});
menu.addMenuItem(menuItem, virtualDesktopsMenuItem);
menuItem = menu.newMenuItem(menu);
menuItem.text = i18nc("Play next track", "Next Track");
menuItem.icon = "media-skip-forward";
menuItem.enabled = Qt.binding(function() {
return playerData.CanGoNext;
});
menuItem.clicked.connect(function() {
mpris2Source.goNext(sourceName);
});
menu.addMenuItem(menuItem, virtualDesktopsMenuItem);
// Technically media controls and audio streams are separate but for the user they're
// semantically related, don't add a separator inbetween.
if (!menu.visualParent.hasAudioStream) {
menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem);
}
// If we don't have a window associated with the player but we can quit
// it through MPRIS we'll offer a "Quit" option instead of "Close"
if (!closeWindowItem.visible && playerData.CanQuit) {
menuItem = menu.newMenuItem(menu);
menuItem.text = i18nc("Quit media player app", "Quit");
menuItem.icon = "application-exit";
menuItem.visible = Qt.binding(function() {
return !closeWindowItem.visible;
});
menuItem.clicked.connect(function() {
mpris2Source.quit(sourceName);
});
menu.addMenuItem(menuItem);
}
// If we don't have a window associated with the player but we can raise
// it through MPRIS we'll offer a "Restore" option
if (!startNewInstanceItem.visible && playerData.CanRaise) {
menuItem = menu.newMenuItem(menu);
menuItem.text = i18nc("Open or bring to the front window of media player app", "Restore");
menuItem.icon = playerData["Desktop Icon Name"];
menuItem.visible = Qt.binding(function() {
return !startNewInstanceItem.visible;
});
menuItem.clicked.connect(function() {
mpris2Source.raise(sourceName);
});
menu.addMenuItem(menuItem, startNewInstanceItem);
}
}
}
// We allow mute/unmute whenever an application has a stream, regardless of whether it
// is actually playing sound.
// This way you can unmute, e.g. a telephony app, even after the conversation has ended,
// so you still have it ringing later on.
if (menu.visualParent.hasAudioStream) {
var muteItem = menu.newMenuItem(menu);
muteItem.checkable = true;
muteItem.checked = Qt.binding(function() {
return menu.visualParent && menu.visualParent.muted;
});
muteItem.clicked.connect(function() {
menu.visualParent.toggleMuted();
});
muteItem.text = i18n("Mute");
muteItem.icon = "audio-volume-muted";
menu.addMenuItem(muteItem, virtualDesktopsMenuItem);
menu.addMenuItem(newSeparator(menu), virtualDesktopsMenuItem);
}
}
PlasmaComponents.MenuItem {
id: virtualDesktopsMenuItem
visible: virtualDesktopInfo.numberOfDesktops > 1
&& (visualParent && get(atm.IsLauncher) !== true
&& get(atm.IsStartup) !== true
&& get(atm.IsVirtualDesktopChangeable) === true)
enabled: visible
text: i18n("Move To &Desktop")
Connections {
target: virtualDesktopInfo
onNumberOfDesktopsChanged: virtualDesktopsMenu.refresh()
onDesktopNamesChanged: virtualDesktopsMenu.refresh()
}
PlasmaComponents.ContextMenu {
id: virtualDesktopsMenu
visualParent: virtualDesktopsMenuItem.action
function refresh() {
clearMenuItems();
if (virtualDesktopInfo.numberOfDesktops <= 1) {
return;
}
var menuItem = menu.newMenuItem(virtualDesktopsMenu);
menuItem.text = i18n("Move &To Current Desktop");
menuItem.enabled = Qt.binding(function() {
return menu.visualParent && menu.get(atm.VirtualDesktop) != virtualDesktopInfo.currentDesktop;
});
menuItem.clicked.connect(function() {
tasksModel.requestVirtualDesktop(menu.modelIndex, virtualDesktopInfo.currentDesktop);
});
menuItem = menu.newMenuItem(virtualDesktopsMenu);
menuItem.text = i18n("&All Desktops");
menuItem.checkable = true;
menuItem.checked = Qt.binding(function() {
return menu.visualParent && menu.get(atm.IsOnAllVirtualDesktops) === true;
});
menuItem.clicked.connect(function() {
tasksModel.requestVirtualDesktop(menu.modelIndex, 0);
});
backend.setActionGroup(menuItem.action);
menu.newSeparator(virtualDesktopsMenu);
for (var i = 0; i < virtualDesktopInfo.desktopNames.length; ++i) {
menuItem = menu.newMenuItem(virtualDesktopsMenu);
menuItem.text = i18nc("1 = number of desktop, 2 = desktop name", "&%1 Desktop %2", i + 1, virtualDesktopInfo.desktopNames[i]);
menuItem.checkable = true;
menuItem.checked = Qt.binding((function(i) {
return function() { return menu.visualParent && menu.get(atm.VirtualDesktop) == (i + 1) };
})(i));
menuItem.clicked.connect((function(i) {
return function() { return tasksModel.requestVirtualDesktop(menu.modelIndex, i + 1); };
})(i));
backend.setActionGroup(menuItem.action);
}
menu.newSeparator(virtualDesktopsMenu);
menuItem = menu.newMenuItem(virtualDesktopsMenu);
menuItem.text = i18n("&New Desktop");
menuItem.clicked.connect(function() {
tasksModel.requestVirtualDesktop(menu.modelIndex, virtualDesktopInfo.numberOfDesktops + 1)
});
}
Component.onCompleted: refresh()
}
}
PlasmaComponents.MenuItem {
id: activitiesDesktopsMenuItem
visible: activityInfo.numberOfRunningActivities > 1
&& (visualParent && !get(atm.IsLauncher)
&& !get(atm.IsStartup))
enabled: visible
text: i18n("Move To &Activity")
Connections {
target: activityInfo
onNumberOfRunningActivitiesChanged: activitiesDesktopsMenu.refresh()
}
PlasmaComponents.ContextMenu {
id: activitiesDesktopsMenu
visualParent: activitiesDesktopsMenuItem.action
function refresh() {
clearMenuItems();
if (activityInfo.numberOfRunningActivities <= 1) {
return;
}
var menuItem = menu.newMenuItem(activitiesDesktopsMenu);
menuItem.text = i18n("Add To Current Activity");
menuItem.enabled = Qt.binding(function() {
return menu.visualParent && menu.get(atm.Activities).length > 0 &&
menu.get(atm.Activities).indexOf(activityInfo.currentActivity) < 0;
});
menuItem.clicked.connect(function() {
tasksModel.requestActivities(menu.modelIndex, menu.get(atm.Activities).concat(activityInfo.currentActivity));
});
menuItem = menu.newMenuItem(activitiesDesktopsMenu);
menuItem.text = i18n("All Activities");
menuItem.checkable = true;
menuItem.checked = Qt.binding(function() {
return menu.visualParent && menu.get(atm.Activities).length === 0;
});
menuItem.clicked.connect(function() {
var checked = menuItem.checked;
var newActivities = undefined; // will cast to an empty QStringList i.e all activities
if (!checked) {
newActivities = new Array(activityInfo.currentActivity);
}
tasksModel.requestActivities(menu.modelIndex, newActivities);
});
menu.newSeparator(activitiesDesktopsMenu);
var runningActivities = activityInfo.runningActivities();
for (var i = 0; i < runningActivities.length; ++i) {
var activityId = runningActivities[i];
menuItem = menu.newMenuItem(activitiesDesktopsMenu);
menuItem.text = activityInfo.activityName(runningActivities[i]);
menuItem.checkable = true;
menuItem.checked = Qt.binding( (function(activityId) {
return function() {
return menu.visualParent && menu.get(atm.Activities).indexOf(activityId) >= 0;
};
})(activityId));
menuItem.clicked.connect((function(activityId) {
return function () {
var checked = menuItem.checked;
var newActivities = menu.get(atm.Activities);
if (checked) {
newActivities = newActivities.concat(activityId);
} else {
var index = newActivities.indexOf(activityId)
if (index < 0) {
return;
}
newActivities = newActivities.splice(index, 1);
}
return tasksModel.requestActivities(menu.modelIndex, newActivities);
};
})(activityId));
}
menu.newSeparator(activitiesDesktopsMenu);
}
Component.onCompleted: refresh()
}
}
PlasmaComponents.MenuItem {
visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
enabled: visualParent && get(atm.IsMinimizable) === true
checkable: true
checked: visualParent && get(atm.IsMinimized) === true
text: i18n("Mi&nimize")
onClicked: tasksModel.requestToggleMinimized(modelIndex)
}
PlasmaComponents.MenuItem {
visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
enabled: visualParent && get(atm.IsMaximizable) === true
checkable: true
checked: visualParent && get(atm.IsMaximized) === true
text: i18n("Ma&ximize")
onClicked: tasksModel.requestToggleMaximized(modelIndex)
}
PlasmaComponents.MenuItem {
id: startNewInstanceItem
visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
enabled: visualParent && get(atm.LauncherUrlWithoutIcon) != null
text: i18n("Start New Instance")
icon: "system-run"
onClicked: tasksModel.requestNewInstance(modelIndex)
}
PlasmaComponents.MenuItem {
id: launcherToggleAction
visible: visualParent
&& get(atm.IsLauncher) !== true
&& get(atm.IsStartup) !== true
&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
&& (activityInfo.numberOfRunningActivities < 2)
enabled: visualParent && get(atm.LauncherUrlWithoutIcon) != ""
checkable: true
text: i18nc("Toggle action for showing a launcher button while the application is not running", "&Pin")
onClicked: {
if (tasksModel.launcherPosition(get(atm.LauncherUrlWithoutIcon)) != -1) {
tasksModel.requestRemoveLauncher(get(atm.LauncherUrlWithoutIcon));
} else {
tasksModel.requestAddLauncher(get(atm.LauncherUrl));
}
}
}
PlasmaComponents.MenuItem {
id: showLauncherInActivitiesItem
text: i18n("&Pin")
visible: visualParent
&& get(atm.IsLauncher) !== true
&& get(atm.IsStartup) !== true
&& plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
&& (activityInfo.numberOfRunningActivities >= 2)
Connections {
target: activityInfo
onNumberOfRunningActivitiesChanged: activitiesDesktopsMenu.refresh()
}
PlasmaComponents.ContextMenu {
id: activitiesLaunchersMenu
visualParent: showLauncherInActivitiesItem.action
function refresh() {
clearMenuItems();
if (menu.visualParent === null) return;
var createNewItem = function(id, title, url, activities) {
var result = menu.newMenuItem(activitiesLaunchersMenu);
result.text = title;
result.visible = true;
result.checkable = true;
result.checked = activities.some(function(activity) { return activity === id });
result.clicked.connect(
function() {
if (result.checked) {
tasksModel.requestAddLauncherToActivity(url, id);
} else {
tasksModel.requestRemoveLauncherFromActivity(url, id);
}
}
);
return result;
}
if (menu.visualParent === null) return;
var url = menu.get(atm.LauncherUrlWithoutIcon);
var activities = tasksModel.launcherActivities(url);
var NULL_UUID = "00000000-0000-0000-0000-000000000000";
createNewItem(NULL_UUID, i18n("On All Activities"), url, activities);
if (activityInfo.numberOfRunningActivities <= 1) {
return;
}
createNewItem(activityInfo.currentActivity, i18n("On The Current Activity"), url, activities);
menu.newSeparator(activitiesLaunchersMenu);
var runningActivities = activityInfo.runningActivities();
runningActivities.forEach(function(id) {
createNewItem(id, activityInfo.activityName(id), url, activities);
});
}
Component.onCompleted: {
menu.onVisualParentChanged.connect(refresh);
refresh();
}
}
}
PlasmaComponents.MenuItem {
visible: (visualParent && get(atm.IsLauncher) === true) && plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
text: i18nc("Remove launcher button for application shown while it is not running", "Unpin")
onClicked: {
tasksModel.requestRemoveLauncher(get(atm.LauncherUrlWithoutIcon));
}
}
PlasmaComponents.MenuItem {
id: moreActionsMenuItem
visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
enabled: visible
text: i18n("More Actions")
PlasmaComponents.ContextMenu {
visualParent: moreActionsMenuItem.action
PlasmaComponents.MenuItem {
enabled: menu.visualParent && menu.get(atm.IsMovable) === true
text: i18n("&Move")
icon: "transform-move"
onClicked: tasksModel.requestMove(menu.modelIndex)
}
PlasmaComponents.MenuItem {
enabled: menu.visualParent && menu.get(atm.IsResizable) === true
text: i18n("Re&size")
onClicked: tasksModel.requestResize(menu.modelIndex)
}
PlasmaComponents.MenuItem {
checkable: true
checked: menu.visualParent && menu.get(atm.IsKeepAbove) === true
text: i18n("Keep &Above Others")
icon: "go-up"
onClicked: tasksModel.requestToggleKeepAbove(menu.modelIndex)
}
PlasmaComponents.MenuItem {
checkable: true
checked: menu.visualParent && menu.get(atm.IsKeepBelow) === true
text: i18n("Keep &Below Others")
icon: "go-down"
onClicked: tasksModel.requestToggleKeepBelow(menu.modelIndex)
}
PlasmaComponents.MenuItem {
enabled: menu.visualParent && menu.get(atm.IsFullScreenable) === true
checkable: true
checked: menu.visualParent && menu.get(atm.IsFullScreen) === true
text: i18n("&Fullscreen")
icon: "view-fullscreen"
onClicked: tasksModel.requestToggleFullScreen(menu.modelIndex)
}
PlasmaComponents.MenuItem {
enabled: menu.visualParent && menu.get(atm.IsShadeable) === true
checkable: true
checked: menu.visualParent && menu.get(atm.IsShaded) === true
text: i18n("&Shade")
onClicked: tasksModel.requestToggleShaded(menu.modelIndex)
}
PlasmaComponents.MenuItem {
separator: true
}
PlasmaComponents.MenuItem {
visible: (plasmoid.configuration.groupingStrategy != 0) && menu.get(atm.IsWindow) === true
checkable: true
checked: menu.visualParent && menu.get(atm.IsGroupable) === true
text: i18n("Allow this program to be grouped")
onClicked: tasksModel.requestToggleGrouping(menu.modelIndex)
}
}
}
PlasmaComponents.MenuItem {
property QtObject configureAction: null
enabled: configureAction && configureAction.enabled
text: configureAction ? configureAction.text : ""
icon: configureAction ? configureAction.icon : ""
onClicked: configureAction.trigger()
Component.onCompleted: configureAction = plasmoid.action("configure")
}
PlasmaComponents.MenuItem {
separator: true
}
PlasmaComponents.MenuItem {
id: closeWindowItem
visible: (visualParent && get(atm.IsLauncher) !== true && get(atm.IsStartup) !== true)
enabled: visualParent && get(atm.IsClosable) === true
text: i18n("&Close")
icon: "window-close"
onClicked: tasksModel.requestClose(modelIndex)
}
}
diff --git a/applets/taskmanager/package/contents/ui/ToolTipInstance.qml b/applets/taskmanager/package/contents/ui/ToolTipInstance.qml
index 2d120f7c4..45b24b5c5 100644
--- a/applets/taskmanager/package/contents/ui/ToolTipInstance.qml
+++ b/applets/taskmanager/package/contents/ui/ToolTipInstance.qml
@@ -1,466 +1,463 @@
/*
* Copyright 2013 by Sebastian Kügler
* Copyright 2014 by Martin Gräßlin
* Copyright 2016 by Kai Uwe Broulik
* Copyright 2017 by Roman Gilg
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* This program 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 Library General Public License for more details
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.6
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.0
import QtQml.Models 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
import org.kde.taskmanager 0.1 as TaskManager
Column {
property var submodelIndex: tasksModel.makeModelIndex(parentIndex, isGroup ? index : -1)
property int flatIndex: isGroup && index != undefined ? index : 0
spacing: units.smallSpacing
property string mprisSourceName: mpris2Source.sourceNameForLauncherUrl(toolTipDelegate.launcherUrl, isGroup ? AppPid : pidParent)
property var playerData: mprisSourceName != "" ? mpris2Source.data[mprisSourceName] : 0
property bool hasPlayer: !!mprisSourceName && !!playerData
property bool playing: hasPlayer && playerData.PlaybackStatus === "Playing"
property bool canControl: hasPlayer && playerData.CanControl
property bool canGoBack: hasPlayer && playerData.CanGoPrevious
property bool canGoNext: hasPlayer && playerData.CanGoNext
property bool canRaise: hasPlayer && playerData.CanRaise
property var currentMetadata: hasPlayer ? playerData.Metadata : ({})
readonly property string track: {
var xesamTitle = currentMetadata["xesam:title"]
if (xesamTitle) {
return xesamTitle;
}
// if no track title is given, print out the file name
var xesamUrl = currentMetadata["xesam:url"] ? currentMetadata["xesam:url"].toString() : ""
if (!xesamUrl) {
return "";
}
var lastSlashPos = xesamUrl.lastIndexOf('/')
if (lastSlashPos < 0) {
return "";
}
var lastUrlPart = xesamUrl.substring(lastSlashPos + 1)
return decodeURIComponent(lastUrlPart);
}
readonly property string artist: currentMetadata["xesam:artist"] || ""
readonly property string albumArt: currentMetadata["mpris:artUrl"] || ""
//
// launcher icon + text labels + close button
RowLayout {
id: header
Layout.minimumWidth: childrenRect.width
Layout.maximumWidth: Layout.minimumWidth
Layout.minimumHeight: childrenRect.height
Layout.maximumHeight: Layout.minimumHeight
anchors.horizontalCenter: parent.horizontalCenter
// launcher icon
PlasmaCore.IconItem {
source: icon
animated: false
usesPlasmaTheme: false
visible: !isWin
}
// all textlabels
Column {
- spacing: 0.75 * units.smallSpacing
- PlasmaComponents.Label {
+ PlasmaExtras.Heading {
+ level: 3
width: isWin ? textWidth : undefined
- height: theme.mSize(theme.defaultFont).height
- font.pointSize: -1
- font.pixelSize: height
+ height: undefined
elide: Text.ElideRight
text: appName
opacity: flatIndex == 0
textFormat: Text.PlainText
+ visible: text !== ""
}
// window title
- PlasmaComponents.Label {
+ PlasmaExtras.Heading {
+ level: 5
width: isWin ? textWidth : undefined
- height: 0.75 * theme.mSize(theme.defaultFont).height
- font.pointSize: -1
- font.pixelSize: height
+ height: undefined
elide: Text.ElideRight
text: generateTitle()
textFormat: Text.PlainText
opacity: 0.75
}
// subtext
- PlasmaComponents.Label {
+ PlasmaExtras.Heading {
+ level: 6
width: isWin ? textWidth : undefined
- height: 0.6 * theme.mSize(theme.defaultFont).height
- font.pointSize: -1
- font.pixelSize: height
+ height: undefined
elide: Text.ElideRight
text: isWin ? generateSubText() : ""
textFormat: Text.PlainText
opacity: 0.6
visible: text !== ""
}
}
// close button
MouseArea {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
height: units.iconSizes.smallMedium
width: height
visible: isWin
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: {
backend.cancelHighlightWindows();
tasksModel.requestClose(submodelIndex);
}
PlasmaCore.IconItem {
anchors.fill: parent
active: parent.containsMouse
source: "window-close"
animated: false
}
}
}
// thumbnail container
Item {
id: thumbnail
width: header.width
// similar to 0.5625 = 1 / (16:9) as most screens are
// round necessary, otherwise shadow mask for players has gap!
height: Math.round(0.5 * width)
anchors.horizontalCenter: parent.horizontalCenter
visible: isWin
Item {
id: thumbnailSourceItem
anchors.fill: parent
readonly property bool isMinimized: isGroup ? IsMinimized == true : isMinimizedParent
// TODO: this causes XCB error message when being visible the first time
property int winId: isWin && windows[flatIndex] != undefined ? windows[flatIndex] : 0
PlasmaCore.WindowThumbnail {
anchors.fill: parent
visible: !albumArtImage.visible && !thumbnailSourceItem.isMinimized
winId: thumbnailSourceItem.winId
ToolTipWindowMouseArea {
anchors.fill: parent
rootTask: parentTask
modelIndex: submodelIndex
winId: thumbnailSourceItem.winId
}
}
Image {
id: albumArtImage
// also Image.Loading to prevent loading thumbnails just because the album art takes a split second to load
readonly property bool available: status === Image.Ready || status === Image.Loading
anchors.fill: parent
sourceSize: Qt.size(parent.width, parent.height)
asynchronous: true
source: albumArt
fillMode: Image.PreserveAspectCrop
visible: available
ToolTipWindowMouseArea {
anchors.fill: parent
rootTask: parentTask
modelIndex: submodelIndex
winId: thumbnailSourceItem.winId
}
}
// when minimized, we don't have a preview, so show the icon
PlasmaCore.IconItem {
anchors.fill: parent
source: icon
animated: false
usesPlasmaTheme: false
visible: thumbnailSourceItem.isMinimized && !albumArtImage.visible
ToolTipWindowMouseArea {
anchors.fill: parent
rootTask: parentTask
modelIndex: submodelIndex
winId: thumbnailSourceItem.winId
}
}
}
Loader {
anchors.fill: thumbnail
sourceComponent: hasPlayer ? playerControlsComp : undefined
}
Component {
id: playerControlsComp
Item {
anchors.fill: parent
// TODO: When could this really be the case? A not-launcher-task always has a window!?
// if there's no window associated with this task, we might still be able to raise the player
// MouseArea {
// id: raisePlayerArea
// anchors.fill: parent
// visible: !isWin || !windows[0] && canRaise
// onClicked: mpris2Source.raise(mprisSourceName)
// }
Item {
id: playerControlsFrostedGlass
anchors.fill: parent
visible: false // OpacityMask would render it
Rectangle {
width: parent.width
height: parent.height - playerControlsRow.height
opacity: 0
}
Rectangle {
anchors.bottom: parent.bottom
width: parent.width
height: playerControlsRow.height
color: theme.backgroundColor
opacity: 0.8
}
}
OpacityMask {
id: playerControlsOpacityMask
anchors.fill: parent
source: playerControlsFrostedGlass
maskSource: thumbnailSourceItem
}
// prevent accidental click-through when a control is disabled
MouseArea {
anchors.fill: playerControlsRow
}
RowLayout {
id: playerControlsRow
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
}
width: parent.width
spacing: 0
enabled: canControl
ColumnLayout {
Layout.fillWidth: true
spacing: 0
PlasmaExtras.Heading {
Layout.fillWidth: true
level: 4
wrapMode: Text.NoWrap
elide: Text.ElideRight
text: track || ""
}
PlasmaExtras.Heading {
Layout.fillWidth: true
level: 5
wrapMode: Text.NoWrap
elide: Text.ElideRight
text: artist || ""
}
}
MouseArea {
height: units.iconSizes.smallMedium
width: height
enabled: canGoBack
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: mpris2Source.goPrevious(mprisSourceName)
PlasmaCore.IconItem {
anchors.fill: parent
enabled: canGoBack
active: parent.containsMouse
source: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward"
animated: false
}
}
MouseArea {
height: units.iconSizes.medium
width: height
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: mpris2Source.playPause(mprisSourceName)
PlasmaCore.IconItem {
anchors.fill: parent
active: parent.containsMouse
source: playing ? "media-playback-pause" : "media-playback-start"
animated: false
}
}
MouseArea {
height: units.iconSizes.smallMedium
width: height
enabled: canGoNext
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: mpris2Source.goNext(mprisSourceName)
PlasmaCore.IconItem {
anchors.fill: parent
enabled: canGoNext
active: parent.containsMouse
source: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward"
animated: false
}
}
}
}
}
}
function generateTitle() {
if (!isWin) {
return genericName != undefined ? genericName : "";
}
var text;
if (isGroup) {
if (model.display == undefined) {
return "";
}
text = model.display.toString();
} else {
text = displayParent;
}
// KWin appends increasing integers in between pointy brackets to otherwise equal window titles.
// In this case save <#number> as counter and delete it at the end of text.
var counter = text.match(/<\d+>\W*$/);
text = text.replace(/\s*<\d+>\W*$/, "");
// Remove appName from the end of text.
var appNameRegex = new RegExp(appName + "$", "i");
text = text.replace(appNameRegex, "");
text = text.replace(/\s*(?:-|—)*\s*$/, "");
// Add counter back at the end.
if (counter != null) {
if (text == "") {
text = counter;
} else {
text = text + " " + counter;
}
}
// In case the window title had only redundant informations (i.e. appName), text is now empty.
// Add a hyphen to indicate that and avoid empty space.
if (text == "") {
text = "—";
}
return text.toString();
}
function generateSubText() {
if (activitiesParent == undefined) {
return "";
}
var subTextEntries = [];
var vd = isGroup ? VirtualDesktop : virtualDesktopParent;
if (!plasmoid.configuration.showOnlyCurrentDesktop
&& virtualDesktopInfo.numberOfDesktops > 1
&& (isGroup ? IsOnAllVirtualDesktops : isOnAllVirtualDesktopsParent) !== true
&& vd != -1
&& vd != undefined
&& virtualDesktopInfo.desktopNames[vd - 1] != undefined) {
subTextEntries.push(i18n("On %1", virtualDesktopInfo.desktopNames[vd - 1]));
}
var act = isGroup ? Activities : activitiesParent;
if (act == undefined) {
return subTextEntries.join("\n");
}
if (act.length == 0 && activityInfo.numberOfRunningActivities > 1) {
subTextEntries.push(i18nc("Which virtual desktop a window is currently on",
"Available on all activities"));
} else if (act.length > 0) {
var activityNames = [];
for (var i = 0; i < act.length; i++) {
var activity = act[i];
var activityName = activityInfo.activityName(act[i]);
if (activityName == "") {
continue;
}
if (plasmoid.configuration.showOnlyCurrentActivity) {
if (activity != activityInfo.currentActivity) {
activityNames.push(activityName);
}
} else if (activity != activityInfo.currentActivity) {
activityNames.push(activityName);
}
}
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");
}
}