diff --git a/applet/contents/config/main.xml b/applet/contents/config/main.xml --- a/applet/contents/config/main.xml +++ b/applet/contents/config/main.xml @@ -16,9 +16,15 @@ true - + true + + false + + + + diff --git a/applet/contents/ui/DeviceListItem.qml b/applet/contents/ui/DeviceListItem.qml --- a/applet/contents/ui/DeviceListItem.qml +++ b/applet/contents/ui/DeviceListItem.qml @@ -24,8 +24,28 @@ ListItemBase { readonly property var currentPort: Ports[ActivePortIndex] + readonly property var currentActivePortIndex: ActivePortIndex + readonly property var currentMuted: Muted property bool onlyOne: false draggable: false label: currentPort ? currentPort.description : Description + + onCurrentActivePortIndexChanged: { + if (globalMute && !Muted) { + Muted = true; + } + } + + onCurrentMutedChanged: { + if (type === "sink") { + if (globalMute) { + if (!Muted) { + plasmoid.configuration.globalMuteDevices = []; + plasmoid.configuration.globalMute = false; + globalMute = false; + } + } + } + } } diff --git a/applet/contents/ui/main.qml b/applet/contents/ui/main.qml --- a/applet/contents/ui/main.qml +++ b/applet/contents/ui/main.qml @@ -35,12 +35,14 @@ id: main property bool volumeFeedback: Plasmoid.configuration.volumeFeedback + property bool globalMute: Plasmoid.configuration.globalMute property int raiseMaxVolumeValue: 150 property int maxVolumeValue: Math.round(raiseMaxVolumeValue * PulseAudio.NormalVolume / 100.0) property int currentMaxVolumeValue: plasmoid.configuration.raiseMaximumVolume ? maxVolumeValue : PulseAudio.NormalVolume property int volumeStep: Math.round(Plasmoid.configuration.volumeStep * PulseAudio.NormalVolume / 100.0) property string displayName: i18n("Audio Volume") property QtObject draggedStream: null + property var globalMuteDevices: Plasmoid.configuration.globalMuteDevices // DEFAULT_SINK_NAME in module-always-sink.c readonly property string dummyOutputName: "auto_null" @@ -121,9 +123,15 @@ return; } var toMute = !paSinkModel.preferredSink.muted; - paSinkModel.preferredSink.muted = toMute; - osd.show(toMute ? 0 : volumePercent(paSinkModel.preferredSink.volume, currentMaxVolumeValue)); - if (!toMute) { + if (toMute) { + enableGlobalMute(); + osd.show(0); + } else { + if (globalMute) { + disableGlobalMute(); + } + paSinkModel.preferredSink.muted = toMute; + osd.show(volumePercent(paSinkModel.preferredSink.volume, currentMaxVolumeValue)); playFeedback(); } } @@ -169,6 +177,60 @@ feedback.play(sinkIndex); } + function enableGlobalMute() { + var role = paSinkModel.role("Muted"); + var rowCount = paSinkModel.rowCount(); + // List for devices that are already muted. Will use to keep muted after disable GlobalMute. + var globalMuteDevices = []; + + for (var i = 0; i < rowCount; i++) { + var idx = paSinkModel.index(i, 0); + var name = paSinkModel.data(idx, paSinkModel.role("Name")); + if (paSinkModel.data(idx, role) === false) { + paSinkModel.setData(idx, true, role); + } else { + globalMuteDevices.push(name + "." + paSinkModel.data(idx, paSinkModel.role("ActivePortIndex"))); + } + } + // If all the devices were muted, will unmute them all with disable GlobalMute. + plasmoid.configuration.globalMuteDevices = globalMuteDevices.length < rowCount ? globalMuteDevices : []; + + if (!globalMute) { + plasmoid.configuration.globalMute = true; + globalMute = true; + } + } + + function forceGlobalMute() { + var role = paSinkModel.role("Muted"); + var rowCount = paSinkModel.rowCount(); + for (var i = 0; i < rowCount; i++) { + var idx = paSinkModel.index(i, 0); + var name = paSinkModel.data(idx, paSinkModel.role("Name")); + if (paSinkModel.data(idx, role) === false) { + paSinkModel.setData(idx, true, role); + } + } + if (!globalMute) { + plasmoid.configuration.globalMute = true; + globalMute = true; + } + } + + function disableGlobalMute() { + var role = paSinkModel.role("Muted"); + for (var i = 0; i < paSinkModel.rowCount(); i++) { + var idx = paSinkModel.index(i, 0); + var name = paSinkModel.data(idx, paSinkModel.role("Name")) + "." + paSinkModel.data(idx, paSinkModel.role("ActivePortIndex")); + if (plasmoid.configuration.globalMuteDevices.indexOf(name) === -1) { + paSinkModel.setData(idx, false, role); + } + } + plasmoid.configuration.globalMuteDevices = []; + plasmoid.configuration.globalMute = false; + globalMute = false; + } + SinkModel { id: paSinkModel @@ -203,6 +265,12 @@ } osd.showText(icon, description); } + + onRowsInserted: { + if (globalMute) { + forceGlobalMute(); + } + } } SourceModel { @@ -563,6 +631,20 @@ Layout.fillWidth: true } + PlasmaComponents.ToolButton { + id: globalMuteCheckbox + iconName: "audio-volume-muted" + onClicked: { + if (!globalMute) { + enableGlobalMute(); + } else { + disableGlobalMute(); + } + } + checked: globalMute + tooltip: i18n("Force mute all playback devices") + } + PlasmaComponents.ToolButton { tooltip: plasmoid.action("configure").text iconName: "configure" @@ -574,7 +656,19 @@ } } + // Wait for paSinkModel init. + Timer { + id: forceGlobalMuteTimer + interval: 200 + onTriggered: { + if (globalMute) { + forceGlobalMute(); + } + } + } + Component.onCompleted: { + forceGlobalMuteTimer.restart(); MicrophoneIndicator.init(); } }