Commit 6611ff9e authored by Nate Graham's avatar Nate Graham 🔩
Browse files

Filter out currently unused devices

Right now devices that have only a single unplugged port are visible in the applet and the KCM.
For all intents and purposes, these devices are useless as they are inactive and unused.
Therefore, let's filter them out so they're not distracting and confusing to the user. An option
to see them all again is provided in the KCM on the off chance that a person needs to configure
the volume or balance of an unused device *before* it's used.

This patch is principally aimed at people using hardware where PulseAudio represents multiple
input and output sources as separate devices rather than separate ports of the same device.
I asked the PA people about this and they said that for certain hardware, it's intentional,
and the correct approach is to filter out the unused devices over here [1]. So, that's what
this patch does.

Thanks to @nicolasfella for his help with getting the initial prototype working!

BUG: 422612

FIXED-IN: 5.20

[1] https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/913
parent 7f1cf8be
......@@ -531,20 +531,11 @@ Item {
Layout.maximumHeight: contentHeight
spacing: 0
model: PlasmaCore.SortFilterModel {
model: PulseObjectFilterModel {
sortRole: "SortByDefault"
sortOrder: Qt.DescendingOrder
filterOutInactiveDevices: true
sourceModel: paSinkModel
filterCallback: function (source_row, value) {
var idx = sourceModel.index(source_row, 0);
if (sourceModel.data(idx, sourceModel.role("Name")) === dummyOutputName) {
return false;
}
return true;
}
}
boundsBehavior: Flickable.StopAtBounds;
delegate: DeviceListItem {
......@@ -574,6 +565,7 @@ Item {
model: PulseObjectFilterModel {
sortRole: "SortByDefault"
sortOrder: Qt.DescendingOrder
filterOutInactiveDevices: true
sourceModel: paSourceModel
}
boundsBehavior: Flickable.StopAtBounds;
......
......@@ -60,7 +60,7 @@ ScrollView {
sourceModel: StreamRestoreModel {}
}
delegate: StreamListItem {
deviceModel: sinkModel
deviceModel: paSinkModel
isPlayback: true
}
}
......@@ -77,7 +77,7 @@ ScrollView {
sourceModel: SinkInputModel {}
}
delegate: StreamListItem {
deviceModel: sinkModel
deviceModel: paSinkModel
isPlayback: true
}
}
......
......@@ -36,6 +36,8 @@ ColumnLayout {
readonly property var currentPort: Ports[ActivePortIndex]
opacity: (Ports.length === 1 && Ports[0].availability == Port.Unavailable) ? 0.5 : 1
RowLayout {
spacing: Kirigami.Units.smallSpacing
Layout.minimumHeight: portbox.implicitHeight
......
......@@ -25,12 +25,32 @@ import QtQuick.Controls 2.3
import org.kde.kirigami 2.5 as Kirigami
import org.kde.plasma.private.volume 0.1
ScrollView {
id: scrollView
contentHeight: contentItem.height
clip: true
PulseObjectFilterModel {
id: paSinkFilterModel
sortRole: "SortByDefault"
sortOrder: Qt.DescendingOrder
filterOutInactiveDevices: true
sourceModel: paSinkModel
}
PulseObjectFilterModel {
id: paSourceFilterModel
sortRole: "SortByDefault"
sortOrder: Qt.DescendingOrder
filterOutInactiveDevices: true
sourceModel: paSourceModel
}
Item {
id: contentItem
width: scrollView.availableWidth
......@@ -54,7 +74,7 @@ ScrollView {
Layout.margins: Kirigami.Units.gridUnit / 2
interactive: false
spacing: Kirigami.Units.gridUnit
model: sinkModel
model: inactiveDevicesButton.checked ? paSinkModel : paSinkFilterModel
delegate: DeviceListItem {
isPlayback: true
}
......@@ -74,11 +94,26 @@ ScrollView {
Layout.margins: Kirigami.Units.gridUnit / 2
interactive: false
spacing: Kirigami.Units.gridUnit
model: sourceModel
model: inactiveDevicesButton.checked ? paSourceModel : paSourceFilterModel
delegate: DeviceListItem {
isPlayback: false
}
}
Button {
id: inactiveDevicesButton
Layout.alignment: Qt.AlignHCenter
Layout.margins: Kirigami.Units.gridUnit
checkable: true
text: i18nd("kcm_pulseaudio", "Show Inactive Devices")
icon.name: "view-visible"
// Only show if there actually are any inactive devices
visible: (paSourceModel.rowCount != paSourceFilterModel.rowCount) || (paSinkModel.rowCount != paSinkFilterModel.rowCount)
}
}
}
}
......@@ -30,8 +30,8 @@ import org.kde.plasma.private.volume 0.1
Kirigami.Page {
title: kcm.name
property QtObject sinkModel: SinkModel { }
property QtObject sourceModel: SourceModel { }
property QtObject paSinkModel: SinkModel { }
property QtObject paSourceModel: SourceModel { }
property int maxVolumeValue: PulseAudio.NormalVolume // the applet supports changing this value. We will just assume 65536 (100%)
ConfigModule.quickHelp: i18nd("kcm_pulseaudio", "This module allows configuring the Pulseaudio sound subsystem.")
implicitHeight: Kirigami.Units.gridUnit * 28
......
......@@ -37,6 +37,7 @@ public:
enum ItemRole {
PulseObjectRole = Qt::UserRole + 1
};
Q_ENUM(ItemRole)
~AbstractModel() override;
QHash<int, QByteArray> roleNames() const final;
......@@ -86,7 +87,7 @@ public:
enum ItemRole {
SortByDefaultRole = PulseObjectRole + 1
};
Q_ENUMS(ItemRole)
Q_ENUM(ItemRole)
explicit SinkModel(QObject *parent = nullptr);
Sink *defaultSink() const;
......@@ -121,7 +122,7 @@ public:
enum ItemRole {
SortByDefaultRole = PulseObjectRole + 1
};
Q_ENUMS(ItemRole)
Q_ENUM(ItemRole)
explicit SourceModel(QObject *parent = nullptr);
Source *defaultSource() const;
......
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.private.volume 0.1
PlasmaCore.SortFilterModel {
property var filters: []
property bool filterOutInactiveDevices: false
filterCallback: function(source_row, value) {
var idx = sourceModel.index(source_row, 0);
for (var i = 0; i < filters.length; ++i) {
var filter = filters[i];
if (sourceModel.data(idx, sourceModel.role(filter.role)) != filter.value) {
// Don't ever show the dummy output, that's silly
var dummyOutputName = "auto_null"
if (sourceModel.data(idx, sourceModel.role("Name")) === dummyOutputName) {
return false;
}
// Optionally run the role-based filters
if (filters.length > 0) {
for (var i = 0; i < filters.length; ++i) {
var filter = filters[i];
if (sourceModel.data(idx, sourceModel.role(filter.role)) != filter.value) {
return false;
}
}
}
// Optionally exclude inactive devices
if (filterOutInactiveDevices) {
var ports = sourceModel.data(idx, sourceModel.role("PulseObject")).ports;
if (ports.length === 1 && ports[0].availability == Port.Unavailable) {
return false;
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment