Warning, /plasma/plasma-desktop/applets/taskmanager/package/contents/ui/PulseAudio.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2017 Kai Uwe Broulik <kde@privat.broulik.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 import QtQuick 2.15 0008 0009 import org.kde.plasma.private.volume 0.1 0010 0011 QtObject { 0012 id: pulseAudio 0013 0014 signal streamsChanged 0015 0016 // It's a JS object so we can do key lookup and don't need to take care of filtering duplicates. 0017 property var pidMatches: ({}) 0018 0019 // TODO Evict cache at some point, preferably if all instances of an application closed. 0020 function registerPidMatch(appName) { 0021 if (!hasPidMatch(appName)) { 0022 pidMatches[appName] = true; 0023 0024 // In case this match is new, notify that streams might have changed. 0025 // This way we also catch the case when the non-playing instance 0026 // shows up first. 0027 // Only notify if we changed to avoid infinite recursion. 0028 streamsChanged(); 0029 } 0030 } 0031 0032 function hasPidMatch(appName) { 0033 return pidMatches[appName] === true; 0034 } 0035 0036 function findStreams(key, value) { 0037 return findStreamsFn(stream => stream[key] === value); 0038 } 0039 0040 function findStreamsFn(fn) { 0041 var streams = [] 0042 for (var i = 0, length = instantiator.count; i < length; ++i) { 0043 var stream = instantiator.objectAt(i); 0044 if (fn(stream)) { 0045 streams.push(stream); 0046 } 0047 } 0048 return streams; 0049 } 0050 0051 function streamsForAppId(appId) { 0052 return findStreams("portalAppId", appId); 0053 } 0054 0055 function streamsForAppName(appName) { 0056 return findStreams("appName", appName); 0057 } 0058 0059 function streamsForPid(pid) { 0060 // skip stream that has portalAppId 0061 // app using portal may have a sandbox pid 0062 var streams = findStreamsFn(stream => stream.pid === pid && !stream.portalAppId); 0063 0064 if (streams.length === 0) { 0065 for (var i = 0, length = instantiator.count; i < length; ++i) { 0066 var stream = instantiator.objectAt(i); 0067 0068 if (stream.parentPid === -1) { 0069 stream.parentPid = backend.parentPid(stream.pid); 0070 } 0071 0072 if (stream.parentPid === pid) { 0073 streams.push(stream); 0074 } 0075 } 0076 } 0077 0078 return streams; 0079 } 0080 0081 // QtObject has no default property, hence adding the Instantiator to one explicitly. 0082 property var instantiator: Instantiator { 0083 model: PulseObjectFilterModel { 0084 filters: [ { role: "VirtualStream", value: false } ] 0085 sourceModel: SinkInputModel {} 0086 } 0087 0088 delegate: QtObject { 0089 id: delegate 0090 required property var model 0091 readonly property int pid: model.Client ? model.Client.properties["application.process.id"] : 0 0092 // Determined on demand. 0093 property int parentPid: -1 0094 readonly property string appName: model.Client && model.Client.properties["application.name"] || "" 0095 readonly property string portalAppId: model.Client && model.Client.properties["pipewire.access.portal.app_id"] || "" 0096 readonly property bool muted: model.Muted 0097 // whether there is nothing actually going on on that stream 0098 readonly property bool corked: model.Corked 0099 readonly property int volume: model.Volume 0100 0101 function mute() { 0102 model.Muted = true 0103 } 0104 function unmute() { 0105 model.Muted = false 0106 } 0107 } 0108 0109 onObjectAdded: pulseAudio.streamsChanged() 0110 onObjectRemoved: pulseAudio.streamsChanged() 0111 } 0112 0113 readonly property int minimalVolume: PulseAudio.MinimalVolume 0114 readonly property int normalVolume: PulseAudio.NormalVolume 0115 }