From 159609135f34c2791eee7f2d6576e50fff80fa6a Mon Sep 17 00:00:00 2001 From: Colin Guthrie Date: Sat, 27 Jun 2009 18:14:05 +0100 Subject: Add support for changing ports. This commit adds a combo box for selecting ports. Overall this implementation could have taken two paths: * Implement port selection as combo box. * Implement port selection as a button. I went for the first option as is done in selecting card profiles over the second method used for selecting devices for streams. This seems more like how a config option should be presented as opposed to a runtime type thing. --- src/devicewidget.cc | 32 ++++++++++++++++++++++++ src/devicewidget.h | 26 ++++++++++++++++++++ src/mainwindow.cc | 67 ++++++++++++++++++++++++++++++++++++++++++--------- src/pavucontrol.glade | 31 +++++++++++++++++++++++- src/sinkwidget.cc | 25 +++++++++++++++++++ src/sinkwidget.h | 3 +++ src/sourcewidget.cc | 25 +++++++++++++++++++ src/sourcewidget.h | 3 +++ 8 files changed, 200 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/devicewidget.cc b/src/devicewidget.cc index e419849..2b30b83 100644 --- a/src/devicewidget.cc +++ b/src/devicewidget.cc @@ -32,10 +32,18 @@ DeviceWidget::DeviceWidget(BaseObjectType* cobject, const Glib::RefPtrget_widget("lockToggleButton", lockToggleButton); x->get_widget("muteToggleButton", muteToggleButton); x->get_widget("defaultToggleButton", defaultToggleButton); + x->get_widget("portSelect", portSelect); + x->get_widget("portList", portList); muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &DeviceWidget::onMuteToggleButton)); defaultToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &DeviceWidget::onDefaultToggleButton)); + treeModel = Gtk::ListStore::create(portModel); + portList->set_model(treeModel); + portList->pack_start(portModel.desc); + + portList->signal_changed().connect( sigc::mem_fun(*this, &DeviceWidget::onPortChange)); + for (unsigned i = 0; i < PA_CHANNELS_MAX; i++) channelWidgets[i] = NULL; } @@ -121,3 +129,27 @@ void DeviceWidget::setSteps(unsigned n) { for (int i = 0; i < channelMap.channels; i++) channelWidgets[channelMap.channels-1]->setSteps(n); } + +void DeviceWidget::prepareMenu() { + int idx = 0; + int active_idx = -1; + + treeModel->clear(); + /* Fill the ComboBox's Tree Model */ + for (uint32_t i = 0; i < ports.size(); ++i) { + Gtk::TreeModel::Row row = *(treeModel->append()); + row[portModel.name] = ports[i].first; + row[portModel.desc] = ports[i].second; + if (ports[i].first == activePort) + active_idx = idx; + idx++; + } + + if (active_idx >= 0) + portList->set_active(active_idx); + + if (ports.size() > 0) + portSelect->show(); + else + portSelect->hide(); +} diff --git a/src/devicewidget.h b/src/devicewidget.h index d092a49..e4ba4af 100644 --- a/src/devicewidget.h +++ b/src/devicewidget.h @@ -53,6 +53,32 @@ public: virtual void executeVolumeUpdate(); virtual void setBaseVolume(pa_volume_t v); virtual void setSteps(unsigned n); + + std::vector< std::pair > ports; + Glib::ustring activePort; + + void prepareMenu(); + +protected: + virtual void onPortChange() = 0; + + /* Tree model columns */ + class ModelColumns : public Gtk::TreeModel::ColumnRecord + { + public: + + ModelColumns() + { add(name); add(desc); } + + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn desc; + }; + + ModelColumns portModel; + + Gtk::HBox *portSelect; + Gtk::ComboBox *portList; + Glib::RefPtr treeModel; }; #endif diff --git a/src/mainwindow.cc b/src/mainwindow.cc index 5e86a41..b1f33df 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -37,13 +37,31 @@ /* Used for profile sorting */ struct profile_prio_compare { - bool operator() (const pa_card_profile_info& lhs, const pa_card_profile_info& rhs) const { - - if (lhs.priority == rhs.priority) - return strcmp(lhs.name, rhs.name) > 0; - - return lhs.priority > rhs.priority; - } + bool operator() (const pa_card_profile_info& lhs, const pa_card_profile_info& rhs) const { + + if (lhs.priority == rhs.priority) + return strcmp(lhs.name, rhs.name) > 0; + + return lhs.priority > rhs.priority; + } +}; +struct sink_port_prio_compare { + bool operator() (const pa_sink_port_info& lhs, const pa_sink_port_info& rhs) const { + + if (lhs.priority == rhs.priority) + return strcmp(lhs.name, rhs.name) > 0; + + return lhs.priority > rhs.priority; + } +}; +struct source_port_prio_compare { + bool operator() (const pa_source_port_info& lhs, const pa_source_port_info& rhs) const { + + if (lhs.priority == rhs.priority) + return strcmp(lhs.name, rhs.name) > 0; + + return lhs.priority > rhs.priority; + } }; @@ -162,12 +180,11 @@ void MainWindow::updateCard(const pa_card_info &info) { } w->profiles.clear(); - for (std::set::iterator i = profile_priorities.begin(); i != profile_priorities.end(); ++i) w->profiles.push_back(std::pair(i->name, i->description)); - w->activeProfile = info.active_profile->name; - + w->activeProfile = info.active_profile ? info.active_profile->name : ""; + w->updating = false; w->prepareMenu(); @@ -180,6 +197,7 @@ void MainWindow::updateSink(const pa_sink_info &info) { SinkWidget *w; bool is_new = false; const char *icon; + std::set port_priorities; if (sinkWidgets.count(info.index)) w = sinkWidgets[info.index]; @@ -216,8 +234,21 @@ void MainWindow::updateSink(const pa_sink_info &info) { w->setDefault(w->name == defaultSinkName); + port_priorities.clear(); + for (uint32_t i=0; iports.clear(); + for (std::set::iterator i = port_priorities.begin(); i != port_priorities.end(); ++i) + w->ports.push_back(std::pair(i->name, i->description)); + + w->activePort = info.active_port ? info.active_port->name : ""; + w->updating = false; + w->prepareMenu(); + if (is_new) updateDeviceVisibility(); } @@ -327,7 +358,8 @@ void MainWindow::updateSource(const pa_source_info &info) { SourceWidget *w; bool is_new = false; const char *icon; - + std::set port_priorities; + if (sourceWidgets.count(info.index)) w = sourceWidgets[info.index]; else { @@ -364,8 +396,21 @@ void MainWindow::updateSource(const pa_source_info &info) { w->setDefault(w->name == defaultSourceName); + port_priorities.clear(); + for (uint32_t i=0; iports.clear(); + for (std::set::iterator i = port_priorities.begin(); i != port_priorities.end(); ++i) + w->ports.push_back(std::pair(i->name, i->description)); + + w->activePort = info.active_port ? info.active_port->name : ""; + w->updating = false; + w->prepareMenu(); + if (is_new) updateDeviceVisibility(); } diff --git a/src/pavucontrol.glade b/src/pavucontrol.glade index 892b281..7a13004 100644 --- a/src/pavucontrol.glade +++ b/src/pavucontrol.glade @@ -797,6 +797,35 @@ Monitors 0 + + + True + 6 + + + True + 0 + <b>Port:</b> + True + + + False + 0 + + + + + True + + + 1 + + + + + 1 + + True @@ -811,7 +840,7 @@ Monitors False False - 1 + 2 diff --git a/src/sinkwidget.cc b/src/sinkwidget.cc index 56159e8..7a7aad9 100644 --- a/src/sinkwidget.cc +++ b/src/sinkwidget.cc @@ -75,3 +75,28 @@ void SinkWidget::onDefaultToggleButton() { } pa_operation_unref(o); } + +void SinkWidget::onPortChange() { + Gtk::TreeModel::iterator iter; + + if (updating) + return; + + iter = portList->get_active(); + if (iter) + { + Gtk::TreeModel::Row row = *iter; + if (row) + { + pa_operation* o; + Glib::ustring port = row[portModel.name]; + + if (!(o = pa_context_set_sink_port_by_index(get_context(), index, port.c_str(), NULL, NULL))) { + show_error(_("pa_context_set_sink_port_by_index() failed")); + return; + } + + pa_operation_unref(o); + } + } +} diff --git a/src/sinkwidget.h b/src/sinkwidget.h index 6c6186b..efabc7c 100644 --- a/src/sinkwidget.h +++ b/src/sinkwidget.h @@ -39,6 +39,9 @@ public: virtual void onMuteToggleButton(); virtual void executeVolumeUpdate(); virtual void onDefaultToggleButton(); + +protected: + virtual void onPortChange(); }; #endif diff --git a/src/sourcewidget.cc b/src/sourcewidget.cc index 94e78b1..2779df4 100644 --- a/src/sourcewidget.cc +++ b/src/sourcewidget.cc @@ -75,3 +75,28 @@ void SourceWidget::onDefaultToggleButton() { } pa_operation_unref(o); } + +void SourceWidget::onPortChange() { + Gtk::TreeModel::iterator iter; + + if (updating) + return; + + iter = portList->get_active(); + if (iter) + { + Gtk::TreeModel::Row row = *iter; + if (row) + { + pa_operation* o; + Glib::ustring port = row[portModel.name]; + + if (!(o = pa_context_set_source_port_by_index(get_context(), index, port.c_str(), NULL, NULL))) { + show_error(_("pa_context_set_source_port_by_index() failed")); + return; + } + + pa_operation_unref(o); + } + } +} \ No newline at end of file diff --git a/src/sourcewidget.h b/src/sourcewidget.h index 81bd44c..f0088b4 100644 --- a/src/sourcewidget.h +++ b/src/sourcewidget.h @@ -39,6 +39,9 @@ public: virtual void onMuteToggleButton(); virtual void executeVolumeUpdate(); virtual void onDefaultToggleButton(); + +protected: + virtual void onPortChange(); }; #endif -- cgit