summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/icons/checkmark.svg20
-rw-r--r--src/main.cpp25
-rw-r--r--src/mainwindow.cpp12
-rw-r--r--src/mainwindow.ui86
-rw-r--r--src/setdefault.cpp151
-rw-r--r--src/setdefault.h8
-rw-r--r--src/slxoutput.cpp4
8 files changed, 276 insertions, 33 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 709a77e..78b49b4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -12,12 +12,14 @@ find_package(Qt5Core ${QT_MINIMUM_VERSION} REQUIRED)
set(pavucontrol-qt_HDRS
main.h
mainwindow.h
+ setdefault.h
slxoutput.h
)
set(pavucontrol-qt_SRCS
main.cpp
mainwindow.cpp
+ setdefault.cpp
slxoutput.cpp
)
@@ -31,6 +33,7 @@ qt5_add_resources(pavucontrol-qt_RCS resources.qrc)
add_executable(pavucontrol-qt
${pavucontrol-qt_SRCS}
+ ${pavucontrol-qt_HDRS}
${pavucontrol-qt_RCS}
${pavucontrol-qt_UI_HEADERS}
)
diff --git a/src/icons/checkmark.svg b/src/icons/checkmark.svg
index 214db50..fad3bec 100644
--- a/src/icons/checkmark.svg
+++ b/src/icons/checkmark.svg
@@ -1,21 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
<svg
- width="200mm"
- height="200mm"
- viewBox="0 0 200 200"
+ viewBox="0 0 24 24"
version="1.1"
id="svg5"
+ width="24"
+ height="24"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
- <defs
- id="defs2" />
<g
- id="layer1">
+ id="surface1"
+ transform="matrix(0.83191502,0,0,0.83175649,-1.3106403,-1.587701)"
+ style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.999583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<path
- style="fill:none;fill-rule:evenodd;stroke:#800000;stroke-width:13;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="M 11.632616,103.25917 C 62.406956,156.18139 50.284158,255.87375 124.78438,132.14843 199.28477,8.4228577 183.63194,8.1400739 183.63194,8.1400739"
- id="path42" />
+ d="M 28.28125,6.28125 11,23.5625 3.71875,16.28125 l -1.4375,1.4375 8,8 0.71875,0.6875 0.71875,-0.6875 18,-18 z"
+ id="path2"
+ style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.999583;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>
diff --git a/src/main.cpp b/src/main.cpp
index cc149a4..b1736cc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,7 @@
#include "main.h"
#include "mainwindow.h"
#include "slxoutput.h"
+#include "setdefault.h"
#include <cstdio>
#include <cstring>
@@ -19,6 +20,7 @@
#include <QList>
#include <QSet>
#include <QTimer>
+#include <QCommandLineParser>
// libkf5pulseaudioqt-dev
// Public
@@ -76,6 +78,7 @@ static void addDevicePortToWindow(PulseAudioQt::Card *card, PulseAudioQt::Device
volume = 65535;
device->setVolume(volume);
}
+ device->setMuted(false);
}
//knownCardPortCombos.insert(card->name() + ":" + port->name());
_mainWindow->getDevice(card, device, port, isOutput)->updateDeviceAndPort(defaultSinkAndPort, device->isMuted(),
@@ -430,10 +433,26 @@ void enableSource(const QString &source, const QString &port)
int main(int argc, char **argv)
{
QApplication a(argc, argv);
- printf("Muh\n");
auto *i = PulseAudioQt::Context::instance();
- printf("Pa is %p = %d\n", i, (int)i->isValid());
- printf("Cards: %d\n", (int)i->cards().size());
+
+ a.setOrganizationName(QStringLiteral("slxmix"));
+ a.setApplicationVersion(QLatin1String("1.0.0.0.0"));
+ QCommandLineParser parser;
+ parser.setApplicationDescription(QObject::tr("SLXmix Volume Control"));
+ parser.addHelpOption();
+ QCommandLineOption selectOption(QStringList() << QStringLiteral("output") << QStringLiteral("o"),
+ QObject::tr("Select a specific output configuration and quit. Will select the Profile/Sink/Port combo that best matches the list of given keywords, e.g. 'HDMI 1 5.1'"),
+ QStringLiteral("keywords"));
+ parser.addOption(selectOption);
+ parser.process(a);
+ // Select default output and exit
+ if (parser.isSet(selectOption)) {
+ QString what = parser.value(selectOption);
+ QTimer::singleShot(100, [what]() {
+ setDefaultOutput(what);
+ });
+ return a.exec();
+ }
// There's no signal, or no way to check if we're connected to PA, so
// just wait a bit and hope for the best.
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 0fc6341..83b999e 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -10,8 +10,12 @@ MainWindow::MainWindow() : QDialog()
{
setupUi(this);
setWindowFlags(Qt::WindowStaysOnTopHint | windowFlags());
- outputTab->setLayout(new QVBoxLayout(outputTab));
- inputTab->setLayout(new QVBoxLayout(inputTab));
+ // Make heading 20% larger than system default
+ QFont f = inputLabel->font();
+ f.setPointSize(f.pointSize() * 6 / 5);
+ inputLabel->setFont(f);
+ outputLabel->setFont(f);
+ cardLabel->setFont(f);
}
MainWindow::~MainWindow()
@@ -86,9 +90,9 @@ void MainWindow::insertItemWidget(SlxOutput* w, bool isDevice)
if (w->type() == SlxOutput::CardProfileItem) {
container = cards;
} else if (w->type() == SlxOutput::SinkPortItem) {
- container = qobject_cast<QBoxLayout*>(outputTab->layout());
+ container = outputListLayout;
} else {
- container = qobject_cast<QBoxLayout*>(inputTab->layout());
+ container = inputListLayout;
}
for (idx = 0; idx < container->count(); ++idx) {
auto *l = container->itemAt(idx);
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index af88c18..03e1aae 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -15,20 +15,80 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
- <widget class="QTabWidget" name="inOutTab">
- <property name="currentIndex">
- <number>0</number>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QLabel" name="outputLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Output</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="outputListLayout"/>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="inputLabel">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Input</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="inputListLayout"/>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="cardLabel">
+ <property name="text">
+ <string>Card/Profile</string>
</property>
- <widget class="QWidget" name="outputTab">
- <attribute name="title">
- <string>Output</string>
- </attribute>
- </widget>
- <widget class="QWidget" name="inputTab">
- <attribute name="title">
- <string>Input</string>
- </attribute>
- </widget>
</widget>
</item>
<item>
diff --git a/src/setdefault.cpp b/src/setdefault.cpp
new file mode 100644
index 0000000..21b368e
--- /dev/null
+++ b/src/setdefault.cpp
@@ -0,0 +1,151 @@
+#include "setdefault.h"
+
+#include <PulseAudioQt/Context>
+#include <PulseAudioQt/Server>
+#include <PulseAudioQt/Profile>
+#include <PulseAudioQt/PulseObject>
+#include <PulseAudioQt/SinkInput>
+#include <PulseAudioQt/Sink>
+#include <PulseAudioQt/Card>
+#include <PulseAudioQt/Port>
+
+#include <QRegularExpression>
+#include <QDebug>
+#include <QCoreApplication>
+#include <QTimer>
+
+static const QRegularExpression _splitter("[() \t-]");
+
+static int countMatches(const QStringList &find, const QString &haystack);
+
+static void setDefaultSink(const QString &bestCardId, const QStringList &words);
+
+void setDefaultOutput(const QString &name)
+{
+ auto *ctx = PulseAudioQt::Context::instance();
+ const QStringList words = name.toLower().split(_splitter, QString::SkipEmptyParts);
+ int bestNum = -1000;
+ int bestProfileIdx = -1;
+ PulseAudioQt::Card *bestCard = nullptr;
+ for (auto *card : ctx->cards()) {
+ int i = -1;
+ for (auto *profile : card->profiles()) {
+ ++i;
+ if (profile->sinks() == 0)
+ continue;
+ int matches = countMatches(words, profile->description());
+ // Prefer Duplex
+ if (profile->description().contains(QLatin1String("Duplex"))) {
+ matches += 2;
+ }
+ // Penaltize unavailable profiles
+ if (profile->availability() != PulseAudioQt::Profile::Available) {
+ matches -= 11;
+ }
+ qDebug() << matches << "Profile" << profile->description();
+ if (matches > bestNum) {
+ bestNum = matches;
+ bestCard = card;
+ bestProfileIdx = i;
+ }
+ }
+ }
+ if (bestCard == nullptr) {
+ qDebug() << "No match found";
+ qApp->quit();
+ return;
+ }
+ QString bestCardId = bestCard->name();
+ if (bestCard->activeProfileIndex() == bestProfileIdx) {
+ setDefaultSink(bestCardId, words);
+ return;
+ }
+ QObject::connect(bestCard, &PulseAudioQt::Card::activeProfileIndexChanged, [bestCardId, words]() {
+ QTimer::singleShot(10, [bestCardId, words]() {
+ setDefaultSink(bestCardId, words);
+ });
+ });
+ qDebug() << "Switching card's profile...";
+ bestCard->setActiveProfileIndex(bestProfileIdx);
+ // Wait for switch - add safety timeout
+ QTimer::singleShot(1000, []() {
+ qDebug() << "WARNING - timeout reached, exiting...";
+ qApp->exit(1);
+ });
+}
+
+static void setDefaultSink(const QString &bestCardId, const QStringList &words)
+{
+ auto *ctx = PulseAudioQt::Context::instance();
+ int idx = -1;
+ int bestCardIdx = -1;
+ for (auto *card : ctx->cards()) {
+ idx++;
+ if (card->name() == bestCardId) {
+ bestCardIdx = idx;
+ break;
+ }
+ }
+ int bestNum = -1000;
+ int bestPortIdx = -1;
+ PulseAudioQt::Sink *bestSink = nullptr;
+ for (auto *sink : ctx->sinks()) {
+ if (bestCardIdx != -1 && sink->cardIndex() != bestCardIdx)
+ continue; // Not sink of card
+ int sinkMatchVal = countMatches(words, sink->description());
+ int pi = -1;
+ for (auto *port : sink->ports()) {
+ pi++;
+ int portMatchVal = sinkMatchVal + countMatches(words, port->description());
+ qDebug() << portMatchVal << "SinkPort" << sink->description() << port->description();
+ if (portMatchVal > bestNum) {
+ bestNum = portMatchVal;
+ bestSink = sink;
+ bestPortIdx = pi;
+ }
+
+ }
+ }
+ if (bestSink == nullptr) {
+ qDebug() << "No match found";
+ qApp->exit(1);
+ }
+ if (bestPortIdx != -1 && bestSink->activePortIndex() != bestPortIdx) {
+ qDebug() << "Selecting port";
+ bestSink->setActivePortIndex(bestPortIdx);
+ }
+ QTimer::singleShot(10, [bestSink]() {
+ qDebug() << "Unmuting sink and selecting as default:" << bestSink->description();
+ bestSink->setDefault(true);
+ bestSink->setMuted(false);
+ bestSink->setVolume(65535);
+ });
+ QTimer::singleShot(20, []() {
+ qDebug() << "Done";
+ qApp->quit();
+ });
+}
+
+static int countMatches(const QStringList &find, const QString &haystack)
+{
+ int ret = 0;
+ QStringList hayList = haystack.toLower().split(_splitter, QString::SkipEmptyParts);
+ qDebug() << "Comparing" << hayList;
+ // Look for all the words we want to find
+ for (const QString &word : find) {
+ if (hayList.contains(word)) {
+ ret += 10;
+ }
+ }
+ if (ret == 0) {
+ // If not a single word matched, bail out
+ return -1000;
+ }
+ // Penaltize additonal words in haystack that we don't want to find
+ for (const QString &word : hayList) {
+ if (!find.contains(word)) {
+ ret -= 1;
+ }
+ }
+ return ret;
+}
diff --git a/src/setdefault.h b/src/setdefault.h
new file mode 100644
index 0000000..123ad20
--- /dev/null
+++ b/src/setdefault.h
@@ -0,0 +1,8 @@
+#ifndef _SET_DEFAULT_H_
+#define _SET_DEFAULT_H_
+
+#include <QString>
+
+void setDefaultOutput(const QString &name);
+
+#endif
diff --git a/src/slxoutput.cpp b/src/slxoutput.cpp
index b1da26f..637ffc3 100644
--- a/src/slxoutput.cpp
+++ b/src/slxoutput.cpp
@@ -15,9 +15,9 @@ SlxOutput::SlxOutput(ItemType type, const QString &id,
QWidget(nullptr)
{
setupUi(this);
- // Make heading 25% larger than system default
+ // Make heading 20% larger than system default
QFont f = headingLabel->font();
- f.setPointSize(f.pointSize() * 5 / 4);
+ f.setPointSize(f.pointSize() * 6 / 5);
f.setBold(_type == SinkPortItem || _type == SourcePortItem);
headingLabel->setFont(f);
//