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