From ae278b8643cf1089f66df18713c8154208d9a505 Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Fri, 6 Sep 2019 11:32:12 +0300 Subject: [PATCH] streamwidget: Use a drop-down list instead of a button and a popup for selecting the device This looks better, requires less code and probably fixes https://gitlab.freedesktop.org/pulseaudio/pavucontrol/issues/63 --- src/mainwindow.cc | 18 +++++++-- src/pavucontrol.glade | 6 +-- src/rolewidget.cc | 2 +- src/sinkinputwidget.cc | 79 +++++++++++++++------------------------ src/sinkinputwidget.h | 26 +------------ src/sourceoutputwidget.cc | 77 ++++++++++++++------------------------ src/sourceoutputwidget.h | 26 +------------ src/streamwidget.cc | 11 +++--- src/streamwidget.h | 7 +++- 9 files changed, 90 insertions(+), 162 deletions(-) diff --git a/src/mainwindow.cc b/src/mainwindow.cc index 459ebbb..a402945 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -1084,12 +1084,15 @@ void MainWindow::reallyUpdateDeviceVisibility() { for (std::map::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) { SinkInputWidget* w = i->second; + w->updating = true; + w->updateDeviceComboBox(); + if (sinkWidgets.size() > 1) { w->directionLabel->show(); - w->deviceButton->show(); + w->deviceComboBox->show(); } else { w->directionLabel->hide(); - w->deviceButton->hide(); + w->deviceComboBox->hide(); } if (showSinkInputType == SINK_INPUT_ALL || w->type == showSinkInputType) { @@ -1097,6 +1100,8 @@ void MainWindow::reallyUpdateDeviceVisibility() { is_empty = false; } else w->hide(); + + w->updating = false; } if (eventRoleWidget) @@ -1112,12 +1117,15 @@ void MainWindow::reallyUpdateDeviceVisibility() { for (std::map::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) { SourceOutputWidget* w = i->second; + w->updating = true; + w->updateDeviceComboBox(); + if (sourceWidgets.size() > 1) { w->directionLabel->show(); - w->deviceButton->show(); + w->deviceComboBox->show(); } else { w->directionLabel->hide(); - w->deviceButton->hide(); + w->deviceComboBox->hide(); } if (showSourceOutputType == SOURCE_OUTPUT_ALL || w->type == showSourceOutputType) { @@ -1125,6 +1133,8 @@ void MainWindow::reallyUpdateDeviceVisibility() { is_empty = false; } else w->hide(); + + w->updating = false; } if (is_empty) diff --git a/src/pavucontrol.glade b/src/pavucontrol.glade index a66e193..fe6c635 100644 --- a/src/pavucontrol.glade +++ b/src/pavucontrol.glade @@ -1496,13 +1496,9 @@ - - Device + True True - True - half - 0 False diff --git a/src/rolewidget.cc b/src/rolewidget.cc index db07f92..7f755aa 100644 --- a/src/rolewidget.cc +++ b/src/rolewidget.cc @@ -33,7 +33,7 @@ RoleWidget::RoleWidget(BaseObjectType* cobject, const Glib::RefPtr lockToggleButton->hide(); directionLabel->hide(); - deviceButton->hide(); + deviceComboBox->hide(); } RoleWidget* RoleWidget::create() { diff --git a/src/sinkinputwidget.cc b/src/sinkinputwidget.cc index 5a0ba39..ff086d6 100644 --- a/src/sinkinputwidget.cc +++ b/src/sinkinputwidget.cc @@ -44,28 +44,42 @@ SinkInputWidget* SinkInputWidget::create(MainWindow* mainWindow) { x->get_widget_derived("streamWidget", w); w->init(mainWindow); w->reference(); + return w; } SinkInputWidget::~SinkInputWidget(void) { - clearMenu(); } void SinkInputWidget::setSinkIndex(uint32_t idx) { mSinkIndex = idx; - - if (mpMainWindow->sinkWidgets.count(idx)) { - SinkWidget *w = mpMainWindow->sinkWidgets[idx]; - deviceButton->set_label(w->description.c_str()); - } - else - deviceButton->set_label(_("Unknown output")); + updateDeviceComboBox(); } uint32_t SinkInputWidget::sinkIndex() { return mSinkIndex; } +void SinkInputWidget::updateDeviceComboBox() { + Glib::ustring currentSinkName = UNKNOWN_DEVICE_NAME; + + deviceComboBox->remove_all(); + + for (auto i = mpMainWindow->sinkWidgets.begin(); i != mpMainWindow->sinkWidgets.end(); i++) { + SinkWidget *sink = i->second; + + deviceComboBox->append(sink->name, sink->description); + + if (sink->index == mSinkIndex) + currentSinkName = sink->name; + } + + if (currentSinkName == UNKNOWN_DEVICE_NAME) + deviceComboBox->append(UNKNOWN_DEVICE_NAME, _("Unknown output")); + + deviceComboBox->set_active_id(currentSinkName); +} + void SinkInputWidget::executeVolumeUpdate() { pa_operation* o; @@ -102,44 +116,13 @@ void SinkInputWidget::onKill() { pa_operation_unref(o); } -void SinkInputWidget::clearMenu() { - while (!sinkMenuItems.empty()) { - std::map::iterator i = sinkMenuItems.begin(); - delete i->second; - sinkMenuItems.erase(i); - } -} - -void SinkInputWidget::buildMenu() { - for (std::map::iterator i = mpMainWindow->sinkWidgets.begin(); i != mpMainWindow->sinkWidgets.end(); ++i) { - SinkMenuItem *m; - sinkMenuItems[i->second->index] = m = new SinkMenuItem(this, i->second->description.c_str(), i->second->index, i->second->index == mSinkIndex); - menu.append(m->menuItem); - } - menu.show_all(); -} - -void SinkInputWidget::SinkMenuItem::onToggle() { - if (widget->updating) - return; - - if (!menuItem.get_active()) - return; - - /*if (!mpMainWindow->sinkWidgets.count(widget->index)) - return;*/ - - pa_operation* o; - if (!(o = pa_context_move_sink_input_by_index(get_context(), widget->index, index, NULL, NULL))) { - show_error(_("pa_context_move_sink_input_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -void SinkInputWidget::onDeviceChangePopup() { - clearMenu(); - buildMenu(); - menu.popup(1, 0); +void SinkInputWidget::onDeviceComboBoxChanged() { + if (updating) + return; + + Glib::ustring sinkName = deviceComboBox->get_active_id(); + + pa_operation *o = pa_context_move_sink_input_by_name(get_context(), index, sinkName.c_str(), NULL, NULL); + if (o) + pa_operation_unref(o); } diff --git a/src/sinkinputwidget.h b/src/sinkinputwidget.h index 368dde0..af40d03 100644 --- a/src/sinkinputwidget.h +++ b/src/sinkinputwidget.h @@ -38,36 +38,14 @@ public: uint32_t index, clientIndex; void setSinkIndex(uint32_t idx); uint32_t sinkIndex(); + void updateDeviceComboBox(); virtual void executeVolumeUpdate(); virtual void onMuteToggleButton(); - virtual void onDeviceChangePopup(); virtual void onKill(); + virtual void onDeviceComboBoxChanged(); private: uint32_t mSinkIndex; - - void clearMenu(); - void buildMenu(); - - Gtk::Menu menu; - - struct SinkMenuItem { - SinkMenuItem(SinkInputWidget *w, const char *label, uint32_t i, bool active) : - widget(w), - menuItem(label), - index(i) { - menuItem.set_active(active); - menuItem.set_draw_as_radio(true); - menuItem.signal_toggled().connect(sigc::mem_fun(*this, &SinkMenuItem::onToggle)); - } - - SinkInputWidget *widget; - Gtk::CheckMenuItem menuItem; - uint32_t index; - void onToggle(); - }; - - std::map sinkMenuItems; }; #endif diff --git a/src/sourceoutputwidget.cc b/src/sourceoutputwidget.cc index 4d915b0..1c2e762 100644 --- a/src/sourceoutputwidget.cc +++ b/src/sourceoutputwidget.cc @@ -54,24 +54,37 @@ SourceOutputWidget* SourceOutputWidget::create(MainWindow* mainWindow) { } SourceOutputWidget::~SourceOutputWidget(void) { - clearMenu(); } void SourceOutputWidget::setSourceIndex(uint32_t idx) { mSourceIndex = idx; - - if (mpMainWindow->sourceWidgets.count(idx)) { - SourceWidget *w = mpMainWindow->sourceWidgets[idx]; - deviceButton->set_label(w->description.c_str()); - } - else - deviceButton->set_label(_("Unknown input")); + updateDeviceComboBox(); } uint32_t SourceOutputWidget::sourceIndex() { return mSourceIndex; } +void SourceOutputWidget::updateDeviceComboBox() { + Glib::ustring currentSourceName = UNKNOWN_DEVICE_NAME; + + deviceComboBox->remove_all(); + + for (auto i = mpMainWindow->sourceWidgets.begin(); i != mpMainWindow->sourceWidgets.end(); i++) { + SourceWidget *source = i->second; + + deviceComboBox->append(source->name, source->description); + + if (source->index == mSourceIndex) + currentSourceName = source->name; + } + + if (currentSourceName == UNKNOWN_DEVICE_NAME) + deviceComboBox->append(UNKNOWN_DEVICE_NAME, _("Unknown input")); + + deviceComboBox->set_active_id(currentSourceName); +} + #if HAVE_SOURCE_OUTPUT_VOLUMES void SourceOutputWidget::executeVolumeUpdate() { pa_operation* o; @@ -110,45 +123,13 @@ void SourceOutputWidget::onKill() { pa_operation_unref(o); } +void SourceOutputWidget::onDeviceComboBoxChanged() { + if (updating) + return; -void SourceOutputWidget::clearMenu() { - while (!sourceMenuItems.empty()) { - std::map::iterator i = sourceMenuItems.begin(); - delete i->second; - sourceMenuItems.erase(i); - } -} - -void SourceOutputWidget::buildMenu() { - for (std::map::iterator i = mpMainWindow->sourceWidgets.begin(); i != mpMainWindow->sourceWidgets.end(); ++i) { - SourceMenuItem *m; - sourceMenuItems[i->second->index] = m = new SourceMenuItem(this, i->second->description.c_str(), i->second->index, i->second->index == mSourceIndex); - menu.append(m->menuItem); - } - menu.show_all(); -} - -void SourceOutputWidget::SourceMenuItem::onToggle() { - if (widget->updating) - return; - - if (!menuItem.get_active()) - return; - - /*if (!mpMainWindow->sourceWidgets.count(widget->index)) - return;*/ - - pa_operation* o; - if (!(o = pa_context_move_source_output_by_index(get_context(), widget->index, index, NULL, NULL))) { - show_error(_("pa_context_move_source_output_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -void SourceOutputWidget::onDeviceChangePopup() { - clearMenu(); - buildMenu(); - menu.popup(1, 0); + Glib::ustring sourceName = deviceComboBox->get_active_id(); + + pa_operation *o = pa_context_move_source_output_by_name(get_context(), index, sourceName.c_str(), NULL, NULL); + if (o) + pa_operation_unref(o); } diff --git a/src/sourceoutputwidget.h b/src/sourceoutputwidget.h index 1b9ab0f..5edd438 100644 --- a/src/sourceoutputwidget.h +++ b/src/sourceoutputwidget.h @@ -38,38 +38,16 @@ public: uint32_t index, clientIndex; void setSourceIndex(uint32_t idx); uint32_t sourceIndex(); + void updateDeviceComboBox(); #if HAVE_SOURCE_OUTPUT_VOLUMES virtual void executeVolumeUpdate(); virtual void onMuteToggleButton(); #endif - virtual void onDeviceChangePopup(); virtual void onKill(); + virtual void onDeviceComboBoxChanged(); private: uint32_t mSourceIndex; - - void clearMenu(); - void buildMenu(); - - Gtk::Menu menu; - - struct SourceMenuItem { - SourceMenuItem(SourceOutputWidget *w, const char *label, uint32_t i, bool active) : - widget(w), - menuItem(label), - index(i) { - menuItem.set_active(active); - menuItem.set_draw_as_radio(true); - menuItem.signal_toggled().connect(sigc::mem_fun(*this, &SourceMenuItem::onToggle)); - } - - SourceOutputWidget *widget; - Gtk::CheckMenuItem menuItem; - uint32_t index; - void onToggle(); - }; - - std::map sourceMenuItems; }; #endif diff --git a/src/streamwidget.cc b/src/streamwidget.cc index 00b7796..00df09f 100644 --- a/src/streamwidget.cc +++ b/src/streamwidget.cc @@ -42,12 +42,12 @@ StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtrget_widget("streamLockToggleButton", lockToggleButton); x->get_widget("streamMuteToggleButton", muteToggleButton); x->get_widget("directionLabel", directionLabel); - x->get_widget("deviceButton", deviceButton); + x->get_widget("deviceComboBox", deviceComboBox); this->signal_button_press_event().connect(sigc::mem_fun(*this, &StreamWidget::onContextTriggerEvent)); muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onMuteToggleButton)); lockToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onLockToggleButton)); - deviceButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onDeviceChangePopup)); + deviceComboBox->signal_changed().connect(sigc::mem_fun(*this, &StreamWidget::onDeviceComboBoxChanged)); terminate.set_label(_("Terminate")); terminate.signal_activate().connect(sigc::mem_fun(*this, &StreamWidget::onKill)); @@ -58,7 +58,6 @@ StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtr& x); @@ -41,7 +44,7 @@ public: Gtk::ToggleButton *lockToggleButton, *muteToggleButton; Gtk::Label *directionLabel; - Gtk::Button *deviceButton; + Gtk::ComboBoxText *deviceComboBox; pa_channel_map channelMap; pa_cvolume volume; @@ -50,7 +53,6 @@ public: virtual void onMuteToggleButton(); virtual void onLockToggleButton(); - virtual void onDeviceChangePopup(); virtual bool onContextTriggerEvent(GdkEventButton*); sigc::connection timeoutConnection; @@ -59,6 +61,7 @@ public: virtual void executeVolumeUpdate(); virtual void onKill(); + virtual void onDeviceComboBoxChanged(); protected: MainWindow* mpMainWindow;