1 #include "MixerGUI.h"
2 #include "ui_MixerGUI.h"
3
MixerGUI(QSettings * set)4 MixerGUI::MixerGUI(QSettings *set) : QMainWindow(), ui(new Ui::MixerGUI){
5 ui->setupUi(this); //load the designer file
6 settings = set; //save this settings access for later
7 closing = false;
8 loadPulseDisabled();
9
10 //connect the signals/slots
11 connect(ui->actionClose_Mixer, SIGNAL(triggered()), this, SLOT(hideGUI()) );
12 connect(ui->actionClose_Mixer_and_Tray, SIGNAL(triggered()), this, SLOT(closeApplication()) );
13 connect(ui->menuConfiguration, SIGNAL(triggered(QAction*)), this, SLOT(startExternalApp(QAction*)) );
14 connect(ui->tool_test, SIGNAL(clicked()), this, SLOT(TestSound()) );
15 connect(ui->actionRestart_PulseAudio, SIGNAL(triggered()), this, SLOT(RestartPulseAudio()) );
16 connect(ui->check_disablepulse, SIGNAL(toggled(bool)), this, SLOT(setPulseDisabled(bool)) );
17 connect(ui->tool_set_default, SIGNAL(clicked()), this, SLOT(saveOutputDevice()) );
18 }
19
~MixerGUI()20 MixerGUI::~MixerGUI(){
21
22 }
23
updateGUI()24 void MixerGUI::updateGUI(){
25 //Load the list of available devices
26 QStringList devList = Mixer::getDevices();
27 //devList.sort();
28 //Clear the UI
29 ui->combo_default->disconnect();
30 ui->combo_default->clear();
31 ui->combo_record->disconnect();
32 ui->combo_record->clear();
33 ui->combo_outdevice->disconnect();
34 ui->combo_outdevice->clear();
35 delete ui->scrollArea->widget(); //delete the widget and all children
36 ui->scrollArea->setWidget( new QWidget() ); //create a new widget in the scroll area
37 ui->scrollArea->widget()->setContentsMargins(0,0,0,0);
38 QHBoxLayout *layout = new QHBoxLayout;
39 //Now Fill the UI with the devices
40 QString cdefault ="none";
41 QString rdefault = Mixer::getRecDevice();
42 if(settings!=0){
43 cdefault = settings->value("tray-device", "vol").toString();
44 }
45 for(int i=0; i<devList.length(); i++){
46 //Get the individual pieces
47 QString dev = devList[i].section(":",0,0);
48 int Lval = devList[i].section(":",1,1).toInt();
49 int Rval = devList[i].section(":",2,2).toInt();
50 //Now create the device widget
51 DeviceWidget *device = new DeviceWidget(this);
52 device->setupDevice(dev, Lval, Rval);
53 layout->addWidget(device);
54 connect(device, SIGNAL(deviceChanged(QString)), this, SLOT(itemChanged(QString)) );
55 //Now add the device to the default/record lists
56 ui->combo_default->addItem(dev);
57 ui->combo_record->addItem(dev);
58 if(dev == cdefault){
59 ui->combo_default->setCurrentIndex(i);
60 }
61 if(dev == rdefault){
62 ui->combo_record->setCurrentIndex(i);
63 }
64 }
65 layout->addStretch(); //add spacer to the end
66 layout->setContentsMargins(2,2,2,2);
67 layout->setSpacing(4);
68 ui->scrollArea->widget()->setLayout(layout);
69 ui->scrollArea->setMinimumHeight(ui->scrollArea->widget()->minimumSizeHint().height()+ui->scrollArea->horizontalScrollBar()->height());
70 //Now rebuild the output device list
71 QStringList outdevs =runShellCommand("cat /dev/sndstat");
72 qDebug() << "Output Devices Found:" << outdevs;
73 for(int i=0; i<outdevs.length(); i++){
74 if(outdevs[i].startsWith("pcm")){
75 ui->combo_outdevice->addItem(outdevs[i].section(" default",0,0), outdevs[i].section(":",0,0) );
76 if(outdevs[i].contains(" default")){ ui->combo_outdevice->setCurrentIndex( ui->combo_outdevice->count()-1); }
77 }
78 }
79 ui->combo_outdevice->setEnabled(ui->combo_outdevice->count() > 0);
80 //re-connect combobox signal
81 connect(ui->combo_default, SIGNAL(currentIndexChanged(QString)), this, SLOT(changeDefaultTrayDevice(QString)) );
82 connect(ui->combo_record, SIGNAL(currentIndexChanged(QString)), this, SLOT(changeRecordingDevice(QString)) );
83 connect(ui->combo_outdevice, SIGNAL(currentIndexChanged(QString)), this, SLOT(changeOutputDevice()) );
84 //Hide the tray icon controls if necessary
85 ui->combo_default->setVisible(settings!=0);
86 ui->label_tray->setVisible(settings!=0);
87 ui->actionClose_Mixer_and_Tray->setVisible(settings!=0);
88 //Enable/Disable the pulseaudio shortcuts if they are not installed
89 ui->actionRestart_PulseAudio->setEnabled( QFile::exists("/usr/local/bin/pulseaudio") );
90 ui->action_PulseAudio_Mixer->setEnabled( QFile::exists("/usr/local/bin/pavucontrol") );
91 ui->actionPulseAudio_Settings->setEnabled( QFile::exists("/usr/local/bin/paprefs") );
92 }
93
loadPulseDisabled()94 void MixerGUI::loadPulseDisabled(){
95 bool disabled = false;
96 //Find the current config directory
97 QString confdir = getenv("XDG_CONFIG_HOME");
98 if(confdir.isEmpty()){confdir = QDir::homePath()+"/.config"; }
99 //Find the client config file
100 QString client_conf = confdir+"/pulse/client.conf";
101 if(QFile::exists(client_conf) ){
102 QStringList lines = runShellCommand("grep autospawn \""+client_conf+"\"");
103 for(int i=0; i<lines.length(); i++){
104 lines[i] = lines[i].simplified();
105 if(lines[i].startsWith(";") || lines[i].startsWith("#")){ continue; } //commented out
106 if(lines[i].contains("=")){
107 disabled = lines[i].section("=",1,1).simplified().toLower()=="no";
108 }
109 }
110 }
111 //Now check the status of the auto-start on login (both must be disabled as a unit)
112 if(disabled){
113 QString auto_conf = confdir+"/autostart/pulseaudio.desktop";
114 if(QFile::exists(auto_conf)){
115 QStringList lines = runShellCommand("grep Hidden \""+auto_conf+"\"");
116 for(int i=0; i<lines.length(); i++){
117 lines[i] = lines[i].simplified();
118 if(lines[i].contains("=")){
119 disabled = lines[i].section("=",1,1).simplified().toLower()=="true";
120 break;
121 }
122 }
123 }else{
124 disabled = false; //not disabled from auto-start on login for this user
125 }
126 }
127 ui->menuConfiguration->setEnabled(!disabled);
128 ui->check_disablepulse->setChecked(disabled);
129 }
130
setPulseDisabled(bool disable)131 void MixerGUI::setPulseDisabled(bool disable){
132 //Find the current config directory
133 QString confdir = getenv("XDG_CONFIG_HOME");
134 if(confdir.isEmpty()){confdir = QDir::homePath()+"/.config"; }
135 //Adjust the client config file
136 QString client_conf = confdir+"/pulse/client.conf";
137 QStringList contents;
138 if(QFile::exists(client_conf) ){
139 QStringList lines = readFile(client_conf);
140 for(int i=0; i<lines.length(); i++){
141 if(lines[i].simplified().startsWith(";") || lines[i].simplified().startsWith("#")){ continue; } //commented out
142 if(lines[i].contains("=") && lines[i].contains("autospawn") ){
143 lines[i] = QString("autospawn = ")+(disable ? "no" : "yes");
144 }
145 }
146 contents = lines;
147 }else{
148 contents << "#PulseAudio client configuration overrides";
149 contents << "# - automatically generated by pc-mixer";
150 contents << "# For all options please look at /usr/local/etc/pulse/client.conf";
151 contents << QString("autospawn = ")+(disable ? "no" : "yes");
152 }
153 if( !writeFile(client_conf, contents) ){
154 //Could not save client settings
155 QMessageBox::warning(this, tr("ERROR"), tr("Could not save PulseAudio client configuration file"));
156 ui->check_disablepulse->setChecked(!disable); //reset the check state back to the previous value
157 return;
158 }
159 //Now adjust the autolaunch registration
160 QString auto_conf = confdir+"/autostart/pulseaudio.desktop";
161 contents.clear(); //re-use this string list for the next file
162 if(QFile::exists(auto_conf)){
163 contents = readFile(auto_conf);
164 bool found = false;
165 for(int i=0; i<contents.length() && !found; i++){
166 if(contents[i].contains("Hidden=")){
167 contents[i]=QString("Hidden=")+(disable ? "true" : "false");
168 found = true;
169 }
170 }
171 if(!found){ contents << QString("Hidden=")+(disable ? "true" : "false"); }
172 }else{
173 contents << "[Desktop Entry]";
174 contents << "Type=Application";
175 contents << "Hidden="+QString(disable ? "true" : "false");
176 }
177 if( !writeFile(auto_conf, contents) ){
178 //Could not save client settings
179 QMessageBox::warning(this, tr("ERROR"), tr("Could not save PulseAudio auto-start file\nYou may need to adjust the autostart registration through your DE itself"));
180 }
181 ui->menuConfiguration->setEnabled(!disable);
182 }
183
changeDefaultTrayDevice(QString device)184 void MixerGUI::changeDefaultTrayDevice(QString device){
185 if(settings!=0){ settings->setValue("tray-device", device); }
186 emit updateTray();
187 }
188
changeRecordingDevice(QString device)189 void MixerGUI::changeRecordingDevice(QString device){
190 Mixer::setRecDevice(device);
191 }
192
changeOutputDevice()193 void MixerGUI::changeOutputDevice(){
194 QString dev = ui->combo_outdevice->currentData().toString().section("pcm",1,-1); //should be just a number
195 if(dev.isEmpty()){ return; }
196 QProcess::execute("sysctl hw.snd.default_unit="+dev);
197 updateGUI();
198 emit outChanged();
199 }
200
saveOutputDevice()201 void MixerGUI::saveOutputDevice(){
202 QString dev = ui->combo_outdevice->currentData().toString().section("pcm",1,-1); //should be just a number
203 if(dev.isEmpty()){ return; }
204 QProcess::execute("qsudo sysrc -f /etc/sysctl.conf hw.snd.default_unit="+dev);
205 }
206
itemChanged(QString device)207 void MixerGUI::itemChanged(QString device){
208 if(device == ui->combo_default->currentText()){
209 emit updateTray();
210 }
211 }
212
TestSound()213 void MixerGUI::TestSound(){
214 static QMediaPlayer *mediaobj = 0;
215 //ui->tool_test->setEnabled(false);
216 if(mediaobj==0){
217 mediaobj = new QMediaPlayer();
218 connect(mediaobj, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(TestStateChanged(QMediaPlayer::State)) );
219 }else{
220 mediaobj->stop();
221 QApplication::processEvents();
222 }
223 mediaobj->setMedia( QUrl("qrc:/testsound.ogg"));
224 mediaobj->setVolume(100);
225 QApplication::processEvents();
226 mediaobj->play();
227 }
228
TestStateChanged(QMediaPlayer::State state)229 void MixerGUI::TestStateChanged(QMediaPlayer::State state){
230 ui->tool_test->setEnabled(state == QMediaPlayer::StoppedState);
231 }
232
RestartPulseAudio()233 void MixerGUI::RestartPulseAudio(){
234 if(!QFile::exists("/usr/local/bin/pulseaudio")){ return; }
235 QProcess::execute("pulseaudio --kill");
236 QProcess::startDetached("start-pulseaudio-x11");
237 }
238