diff options
Diffstat (limited to 'src/pavucontrol.cc')
-rw-r--r-- | src/pavucontrol.cc | 1835 |
1 files changed, 20 insertions, 1815 deletions
diff --git a/src/pavucontrol.cc b/src/pavucontrol.cc index 7fef582..423c44b 100644 --- a/src/pavucontrol.cc +++ b/src/pavucontrol.cc @@ -22,366 +22,25 @@ #include <config.h> #endif -#include <signal.h> -#include <string.h> +#include "pavucontrol.h" -#include <gtkmm.h> -#include <libglademm.h> -#include <libintl.h> - -#include <canberra-gtk.h> - -#include <pulse/pulseaudio.h> #include <pulse/glib-mainloop.h> #include <pulse/ext-stream-restore.h> #include "i18n.h" - -#ifndef GLADE_FILE -#define GLADE_FILE "pavucontrol.glade" -#endif +#include "minimalstreamwidget.h" +#include "channelwidget.h" +#include "streamwidget.h" +#include "cardwidget.h" +#include "sinkwidget.h" +#include "sourcewidget.h" +#include "sinkinputwidget.h" +#include "sourceoutputwidget.h" +#include "rolewidget.h" +#include "mainwindow.h" static pa_context *context = NULL; static int n_outstanding = 0; -static bool show_decibel = true; - -enum SinkInputType { - SINK_INPUT_ALL, - SINK_INPUT_CLIENT, - SINK_INPUT_VIRTUAL -}; - -enum SinkType { - SINK_ALL, - SINK_HARDWARE, - SINK_VIRTUAL, -}; - -enum SourceOutputType { - SOURCE_OUTPUT_ALL, - SOURCE_OUTPUT_CLIENT, - SOURCE_OUTPUT_VIRTUAL -}; - -enum SourceType{ - SOURCE_ALL, - SOURCE_NO_MONITOR, - SOURCE_HARDWARE, - SOURCE_VIRTUAL, - SOURCE_MONITOR, -}; - -class StreamWidget; -class MainWindow; - -class ChannelWidget : public Gtk::EventBox { -public: - ChannelWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static ChannelWidget* create(); - - void setVolume(pa_volume_t volume); - - Gtk::Label *channelLabel; - Gtk::Label *volumeLabel; - Gtk::HScale *volumeScale; - - int channel; - StreamWidget *streamWidget; - - void onVolumeScaleValueChanged(); - - bool can_decibel; - bool volumeScaleEnabled; - - Glib::ustring beepDevice; - - virtual void set_sensitive(bool enabled); -}; - -class MinimalStreamWidget : public Gtk::VBox { -public: - MinimalStreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - - Gtk::VBox *channelsVBox; - Gtk::Label *nameLabel, *boldNameLabel; - Gtk::ToggleButton *streamToggleButton; - Gtk::Menu menu; - Gtk::Image *iconImage; - Gtk::ProgressBar peakProgressBar; - double lastPeak; - - bool updating; - - void onStreamToggleButton(); - void onMenuDeactivated(); - void popupMenuPosition(int& x, int& y, bool& push_in); - - virtual void prepareMenu(void); - - bool volumeMeterEnabled; - void enableVolumeMeter(); - void updatePeak(double v); - - Glib::ustring beepDevice; - -protected: - virtual bool on_button_press_event(GdkEventButton* event); -}; - -class StreamWidget : public MinimalStreamWidget { -public: - StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - - void setChannelMap(const pa_channel_map &m, bool can_decibel); - void setVolume(const pa_cvolume &volume, bool force); - virtual void updateChannelVolume(int channel, pa_volume_t v); - - Gtk::ToggleButton *lockToggleButton, *muteToggleButton; - - pa_channel_map channelMap; - pa_cvolume volume; - - ChannelWidget *channelWidgets[PA_CHANNELS_MAX]; - - virtual void onMuteToggleButton(); - - sigc::connection timeoutConnection; - - bool timeoutEvent(); - - virtual void executeVolumeUpdate(); -}; - -class CardWidget : public Gtk::VBox { -public: - CardWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static CardWidget* create(); - - Gtk::Label *nameLabel; - Gtk::ToggleButton *streamToggleButton; - Gtk::Menu menu; - Gtk::Image *iconImage; - Glib::ustring name; - uint32_t index; - bool updating; - - std::map<Glib::ustring,Glib::ustring> profiles; - Glib::ustring activeProfile; - bool hasSinks; - bool hasSources; - - void prepareMenu(); - -protected: - virtual void onProfileChange(); - - //Tree model columns: - class ModelColumns : public Gtk::TreeModel::ColumnRecord - { - public: - - ModelColumns() - { add(name); add(desc); } - - Gtk::TreeModelColumn<Glib::ustring> name; - Gtk::TreeModelColumn<Glib::ustring> desc; - }; - - ModelColumns profileModel; - - //Child widgets: - Gtk::ComboBox *profileList; - Glib::RefPtr<Gtk::ListStore> treeModel; -}; - -class SinkWidget : public StreamWidget { -public: - SinkWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static SinkWidget* create(); - - SinkType type; - Glib::ustring description; - Glib::ustring name; - uint32_t index, monitor_index, card_index; - bool can_decibel; - - Gtk::CheckMenuItem defaultMenuItem; - - virtual void onMuteToggleButton(); - virtual void executeVolumeUpdate(); - virtual void onDefaultToggle(); -}; - -class SourceWidget : public StreamWidget { -public: - SourceWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static SourceWidget* create(); - - SourceType type; - Glib::ustring name; - Glib::ustring description; - uint32_t index, card_index; - bool can_decibel; - - Gtk::CheckMenuItem defaultMenuItem; - - virtual void onMuteToggleButton(); - virtual void executeVolumeUpdate(); - virtual void onDefaultToggle(); -}; - -class SinkInputWidget : public StreamWidget { -public: - SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static SinkInputWidget* create(); - virtual ~SinkInputWidget(); - - SinkInputType type; - - uint32_t index, clientIndex, sinkIndex; - virtual void executeVolumeUpdate(); - virtual void onMuteToggleButton(); - virtual void onKill(); - virtual void prepareMenu(); - - MainWindow *mainWindow; - Gtk::Menu submenu; - Gtk::MenuItem titleMenuItem, killMenuItem; - - 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<uint32_t, SinkMenuItem*> sinkMenuItems; - - void clearMenu(); - void buildMenu(); -}; - -class SourceOutputWidget : public MinimalStreamWidget { -public: - SourceOutputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static SourceOutputWidget* create(); - virtual ~SourceOutputWidget(); - - SourceOutputType type; - - uint32_t index, clientIndex, sourceIndex; - virtual void onKill(); - - MainWindow *mainWindow; - Gtk::Menu submenu; - Gtk::MenuItem titleMenuItem, killMenuItem; - - 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<uint32_t, SourceMenuItem*> sourceMenuItems; - - void clearMenu(); - void buildMenu(); - virtual void prepareMenu(); -}; - -class RoleWidget : public StreamWidget { -public: - RoleWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static RoleWidget* create(); - - Glib::ustring role; - Glib::ustring device; - - virtual void onMuteToggleButton(); - virtual void executeVolumeUpdate(); -}; - -class MainWindow : public Gtk::Window { -public: - MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x); - static MainWindow* create(); - virtual ~MainWindow(); - - void updateCard(const pa_card_info &info); - void updateSink(const pa_sink_info &info); - void updateSource(const pa_source_info &info); - void updateSinkInput(const pa_sink_input_info &info); - void updateSourceOutput(const pa_source_output_info &info); - void updateClient(const pa_client_info &info); - void updateServer(const pa_server_info &info); - void updateVolumeMeter(uint32_t source_index, uint32_t sink_input_index, double v); - void updateRole(const pa_ext_stream_restore_info &info); - - void removeCard(uint32_t index); - void removeSink(uint32_t index); - void removeSource(uint32_t index); - void removeSinkInput(uint32_t index); - void removeSourceOutput(uint32_t index); - void removeClient(uint32_t index); - - Gtk::Notebook *notebook; - Gtk::VBox *streamsVBox, *recsVBox, *sinksVBox, *sourcesVBox, *cardsVBox; - Gtk::Label *noStreamsLabel, *noRecsLabel, *noSinksLabel, *noSourcesLabel, *noCardsLabel; - Gtk::ComboBox *sinkInputTypeComboBox, *sourceOutputTypeComboBox, *sinkTypeComboBox, *sourceTypeComboBox; - - std::map<uint32_t, CardWidget*> cardWidgets; - std::map<uint32_t, SinkWidget*> sinkWidgets; - std::map<uint32_t, SourceWidget*> sourceWidgets; - std::map<uint32_t, SinkInputWidget*> sinkInputWidgets; - std::map<uint32_t, SourceOutputWidget*> sourceOutputWidgets; - std::map<uint32_t, char*> clientNames; - - SinkInputType showSinkInputType; - SinkType showSinkType; - SourceOutputType showSourceOutputType; - SourceType showSourceType; - - virtual void onSinkInputTypeComboBoxChanged(); - virtual void onSourceOutputTypeComboBoxChanged(); - virtual void onSinkTypeComboBoxChanged(); - virtual void onSourceTypeComboBoxChanged(); - - void updateDeviceVisibility(); - void reallyUpdateDeviceVisibility(); - void createMonitorStreamForSource(uint32_t source_idx); - void createMonitorStreamForSinkInput(uint32_t sink_input_idx, uint32_t sink_idx); - - void setIconFromProplist(Gtk::Image *icon, pa_proplist *l, const char *name); - - RoleWidget *eventRoleWidget; - - bool createEventRoleWidget(); - void deleteEventRoleWidget(); - - Glib::ustring defaultSinkName, defaultSourceName; - -protected: - virtual void on_realize(); -}; void show_error(const char *txt) { char buf[256]; @@ -394,1466 +53,6 @@ void show_error(const char *txt) { Gtk::Main::quit(); } -/*** ChannelWidget ***/ - -ChannelWidget::ChannelWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - Gtk::EventBox(cobject), - volumeScaleEnabled(true) { - - x->get_widget("channelLabel", channelLabel); - x->get_widget("volumeLabel", volumeLabel); - x->get_widget("volumeScale", volumeScale); - - volumeScale->set_value(100); - - volumeScale->signal_value_changed().connect(sigc::mem_fun(*this, &ChannelWidget::onVolumeScaleValueChanged)); -} - -ChannelWidget* ChannelWidget::create() { - ChannelWidget* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "channelWidget"); - x->get_widget_derived("channelWidget", w); - return w; -} - -void ChannelWidget::setVolume(pa_volume_t volume) { - double v; - char txt[64]; - - v = ((gdouble) volume * 100) / PA_VOLUME_NORM; - - if (can_decibel && show_decibel) { - double dB = pa_sw_volume_to_dB(volume); - - if (dB > PA_DECIBEL_MININFTY) { - snprintf(txt, sizeof(txt), "%0.2f dB", dB); - volumeLabel->set_tooltip_text(txt); - } else - volumeLabel->set_tooltip_markup("-∞dB"); - volumeLabel->set_has_tooltip(TRUE); - } else - volumeLabel->set_has_tooltip(FALSE); - - snprintf(txt, sizeof(txt), "%0.0f%%", v); - volumeLabel->set_text(txt); - - volumeScaleEnabled = false; - volumeScale->set_value(v > 100 ? 100 : v); - volumeScaleEnabled = true; -} - -void ChannelWidget::onVolumeScaleValueChanged() { - - if (!volumeScaleEnabled) - return; - - if (streamWidget->updating) - return; - - pa_volume_t volume = (pa_volume_t) ((volumeScale->get_value() * PA_VOLUME_NORM) / 100); - streamWidget->updateChannelVolume(channel, volume); - - if (beepDevice != "") { - ca_context_change_device(ca_gtk_context_get(), beepDevice.c_str()); - - ca_context_cancel(ca_gtk_context_get(), 2); - - ca_gtk_play_for_widget(GTK_WIDGET(volumeScale->gobj()), - 2, - CA_PROP_EVENT_DESCRIPTION, _("Volume Control Feedback Sound"), - CA_PROP_EVENT_ID, "audio-volume-change", - CA_PROP_CANBERRA_CACHE_CONTROL, "permanent", - CA_PROP_CANBERRA_VOLUME, "0", - CA_PROP_CANBERRA_ENABLE, "1", - NULL); - - ca_context_change_device(ca_gtk_context_get(), NULL); - } -} - -void ChannelWidget::set_sensitive(bool enabled) { - Gtk::EventBox::set_sensitive(enabled); - - channelLabel->set_sensitive(enabled); - volumeLabel->set_sensitive(enabled); - volumeScale->set_sensitive(enabled); -} - - - -/*** CardWidget ***/ -CardWidget::CardWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - Gtk::VBox(cobject) { - - x->get_widget("nameLabel", nameLabel); - x->get_widget("profileList", profileList); - x->get_widget("iconImage", iconImage); - - treeModel = Gtk::ListStore::create(profileModel); - profileList->set_model(treeModel); - profileList->pack_start(profileModel.desc); - - profileList->signal_changed().connect( sigc::mem_fun(*this, &CardWidget::onProfileChange)); -} - -CardWidget* CardWidget::create() { - CardWidget* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "cardWidget"); - x->get_widget_derived("cardWidget", w); - return w; -} - - -void CardWidget::prepareMenu() { - int idx = 0; - int active_idx = -1; - - treeModel->clear(); - //Fill the ComboBox's Tree Model: - for (std::map<Glib::ustring, Glib::ustring>::iterator i = profiles.begin(); i != profiles.end(); ++i) { - Gtk::TreeModel::Row row = *(treeModel->append()); - row[profileModel.name] = i->first; - row[profileModel.desc] = i->second; - if (i->first == activeProfile) - active_idx = idx; - idx++; - } - - if (active_idx >= 0) - profileList->set_active(active_idx); -} - -void CardWidget::onProfileChange() { - Gtk::TreeModel::iterator iter; - - if (updating) - return; - - iter = profileList->get_active(); - if (iter) - { - Gtk::TreeModel::Row row = *iter; - if (row) - { - pa_operation* o; - Glib::ustring profile = row[profileModel.name]; - - if (!(o = pa_context_set_card_profile_by_index(context, index, profile.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_card_profile_by_index() failed")); - return; - } - - pa_operation_unref(o); - } - } -} - - -/*** MinimalStreamWidget ***/ -MinimalStreamWidget::MinimalStreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - Gtk::VBox(cobject), - peakProgressBar(), - lastPeak(0), - updating(false), - volumeMeterEnabled(false) { - - x->get_widget("channelsVBox", channelsVBox); - x->get_widget("nameLabel", nameLabel); - x->get_widget("boldNameLabel", boldNameLabel); - x->get_widget("streamToggle", streamToggleButton); - x->get_widget("iconImage", iconImage); - - peakProgressBar.set_size_request(-1, 10); - channelsVBox->pack_end(peakProgressBar, false, false); - - streamToggleButton->set_active(false); - streamToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onStreamToggleButton)); - menu.signal_deactivate().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onMenuDeactivated)); - - peakProgressBar.hide(); -} - -void MinimalStreamWidget::prepareMenu(void) { -} - -void MinimalStreamWidget::onMenuDeactivated(void) { - streamToggleButton->set_active(false); -} - -void MinimalStreamWidget::popupMenuPosition(int& x, int& y, bool& push_in G_GNUC_UNUSED) { - Gtk::Requisition r; - - streamToggleButton->get_window()->get_origin(x, y); - r = menu.size_request(); - - /* Align the right side of the menu with the right side of the togglebutton */ - x += streamToggleButton->get_allocation().get_x(); - x += streamToggleButton->get_allocation().get_width(); - x -= r.width; - - /* Align the top of the menu with the buttom of the togglebutton */ - y += streamToggleButton->get_allocation().get_y(); - y += streamToggleButton->get_allocation().get_height(); -} - -void MinimalStreamWidget::onStreamToggleButton(void) { - if (streamToggleButton->get_active()) { - prepareMenu(); - menu.popup(sigc::mem_fun(*this, &MinimalStreamWidget::popupMenuPosition), 0, gtk_get_current_event_time()); - } -} - -bool MinimalStreamWidget::on_button_press_event (GdkEventButton* event) { - if (Gtk::VBox::on_button_press_event(event)) - return TRUE; - - if (event->type == GDK_BUTTON_PRESS && event->button == 3) { - prepareMenu(); - menu.popup(0, event->time); - return TRUE; - } - - return FALSE; -} - -#define DECAY_STEP .04 - -void MinimalStreamWidget::updatePeak(double v) { - - if (lastPeak >= DECAY_STEP) - if (v < lastPeak - DECAY_STEP) - v = lastPeak - DECAY_STEP; - - lastPeak = v; - - if (v >= 0) { - peakProgressBar.set_sensitive(TRUE); - peakProgressBar.set_fraction(v); - } else { - peakProgressBar.set_sensitive(FALSE); - peakProgressBar.set_fraction(0); - } - - enableVolumeMeter(); -} - -void MinimalStreamWidget::enableVolumeMeter() { - if (volumeMeterEnabled) - return; - - volumeMeterEnabled = true; - peakProgressBar.show(); -} - -/*** StreamWidget ***/ - -StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - MinimalStreamWidget(cobject, x) { - - x->get_widget("lockToggleButton", lockToggleButton); - x->get_widget("muteToggleButton", muteToggleButton); - - muteToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &StreamWidget::onMuteToggleButton)); - - for (unsigned i = 0; i < PA_CHANNELS_MAX; i++) - channelWidgets[i] = NULL; -} - -void StreamWidget::setChannelMap(const pa_channel_map &m, bool can_decibel) { - channelMap = m; - - for (int i = 0; i < m.channels; i++) { - ChannelWidget *cw = channelWidgets[i] = ChannelWidget::create(); - cw->beepDevice = beepDevice; - cw->channel = i; - cw->can_decibel = can_decibel; - cw->streamWidget = this; - char text[64]; - snprintf(text, sizeof(text), "<b>%s</b>", pa_channel_position_to_pretty_string(m.map[i])); - cw->channelLabel->set_markup(text); - channelsVBox->pack_start(*cw, false, false, 0); - } - - lockToggleButton->set_sensitive(m.channels > 1); -} - -void StreamWidget::setVolume(const pa_cvolume &v, bool force = false) { - g_assert(v.channels == channelMap.channels); - - volume = v; - - if (timeoutConnection.empty() || force) { /* do not update the volume when a volume change is still in flux */ - for (int i = 0; i < volume.channels; i++) - channelWidgets[i]->setVolume(volume.values[i]); - } -} - -void StreamWidget::updateChannelVolume(int channel, pa_volume_t v) { - pa_cvolume n; - g_assert(channel < volume.channels); - - n = volume; - if (lockToggleButton->get_active()) { - for (int i = 0; i < n.channels; i++) - n.values[i] = v; - } else - n.values[channel] = v; - - setVolume(n, true); - - if (timeoutConnection.empty()) - timeoutConnection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &StreamWidget::timeoutEvent), 100); -} - -void StreamWidget::onMuteToggleButton() { - - lockToggleButton->set_sensitive(!muteToggleButton->get_active()); - - for (int i = 0; i < channelMap.channels; i++) - channelWidgets[i]->set_sensitive(!muteToggleButton->get_active()); -} - -bool StreamWidget::timeoutEvent() { - executeVolumeUpdate(); - return false; -} - -void StreamWidget::executeVolumeUpdate() { -} - -SinkWidget::SinkWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - StreamWidget(cobject, x), - defaultMenuItem("_Default", true){ - - add_events(Gdk::BUTTON_PRESS_MASK); - - defaultMenuItem.set_active(false); - defaultMenuItem.signal_toggled().connect(sigc::mem_fun(*this, &SinkWidget::onDefaultToggle)); - menu.append(defaultMenuItem); - menu.show_all(); -} - -SinkWidget* SinkWidget::create() { - SinkWidget* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); - return w; -} - -void SinkWidget::executeVolumeUpdate() { - pa_operation* o; - - if (!(o = pa_context_set_sink_volume_by_index(context, index, &volume, NULL, NULL))) { - show_error(_("pa_context_set_sink_volume_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -void SinkWidget::onMuteToggleButton() { - StreamWidget::onMuteToggleButton(); - - if (updating) - return; - - pa_operation* o; - if (!(o = pa_context_set_sink_mute_by_index(context, index, muteToggleButton->get_active(), NULL, NULL))) { - show_error(_("pa_context_set_sink_mute_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -void SinkWidget::onDefaultToggle() { - pa_operation* o; - - if (updating) - return; - - if (!(o = pa_context_set_default_sink(context, name.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_default_sink() failed")); - return; - } - pa_operation_unref(o); -} - -SourceWidget::SourceWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - StreamWidget(cobject, x), - defaultMenuItem(_("_Default"), true){ - - add_events(Gdk::BUTTON_PRESS_MASK); - - defaultMenuItem.set_active(false); - defaultMenuItem.signal_toggled().connect(sigc::mem_fun(*this, &SourceWidget::onDefaultToggle)); - menu.append(defaultMenuItem); - menu.show_all(); -} - -SourceWidget* SourceWidget::create() { - SourceWidget* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); - return w; -} - -void SourceWidget::executeVolumeUpdate() { - pa_operation* o; - - if (!(o = pa_context_set_source_volume_by_index(context, index, &volume, NULL, NULL))) { - show_error(_("pa_context_set_source_volume_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -void SourceWidget::onMuteToggleButton() { - StreamWidget::onMuteToggleButton(); - - if (updating) - return; - - pa_operation* o; - if (!(o = pa_context_set_source_mute_by_index(context, index, muteToggleButton->get_active(), NULL, NULL))) { - show_error(_("pa_context_set_source_mute_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -void SourceWidget::onDefaultToggle() { - pa_operation* o; - - if (updating) - return; - - if (!(o = pa_context_set_default_source(context, name.c_str(), NULL, NULL))) { - show_error(_("pa_context_set_default_source() failed")); - return; - } - pa_operation_unref(o); -} - -SinkInputWidget::SinkInputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - StreamWidget(cobject, x), - mainWindow(NULL), - titleMenuItem(_("_Move Stream..."), true), - killMenuItem(_("_Terminate Stream"), true) { - - add_events(Gdk::BUTTON_PRESS_MASK); - - menu.append(titleMenuItem); - titleMenuItem.set_submenu(submenu); - - menu.append(killMenuItem); - killMenuItem.signal_activate().connect(sigc::mem_fun(*this, &SinkInputWidget::onKill)); -} - -SinkInputWidget::~SinkInputWidget() { - clearMenu(); -} - -SinkInputWidget* SinkInputWidget::create() { - SinkInputWidget* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); - return w; -} - -void SinkInputWidget::executeVolumeUpdate() { - pa_operation* o; - - if (!(o = pa_context_set_sink_input_volume(context, index, &volume, NULL, NULL))) { - show_error(_("pa_context_set_sink_input_volume() failed")); - return; - } - - pa_operation_unref(o); -} - -void SinkInputWidget::onMuteToggleButton() { - StreamWidget::onMuteToggleButton(); - - if (updating) - return; - - pa_operation* o; - if (!(o = pa_context_set_sink_input_mute(context, index, muteToggleButton->get_active(), NULL, NULL))) { - show_error(_("pa_context_set_sink_input_mute() failed")); - return; - } - - pa_operation_unref(o); -} - -void SinkInputWidget::prepareMenu() { - clearMenu(); - buildMenu(); -} - -void SinkInputWidget::clearMenu() { - - while (!sinkMenuItems.empty()) { - std::map<uint32_t, SinkMenuItem*>::iterator i = sinkMenuItems.begin(); - delete i->second; - sinkMenuItems.erase(i); - } -} - -void SinkInputWidget::buildMenu() { - for (std::map<uint32_t, SinkWidget*>::iterator i = mainWindow->sinkWidgets.begin(); i != mainWindow->sinkWidgets.end(); ++i) { - SinkMenuItem *m; - sinkMenuItems[i->second->index] = m = new SinkMenuItem(this, i->second->description.c_str(), i->second->index, i->second->index == sinkIndex); - submenu.append(m->menuItem); - } - - menu.show_all(); -} - -void SinkInputWidget::onKill() { - pa_operation* o; - if (!(o = pa_context_kill_sink_input(context, index, NULL, NULL))) { - show_error(_("pa_context_kill_sink_input() failed")); - return; - } - - pa_operation_unref(o); -} - -void SinkInputWidget::SinkMenuItem::onToggle() { - - if (widget->updating) - return; - - if (!menuItem.get_active()) - return; - - pa_operation* o; - if (!(o = pa_context_move_sink_input_by_index(context, widget->index, index, NULL, NULL))) { - show_error(_("pa_context_move_sink_input_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -SourceOutputWidget::SourceOutputWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - MinimalStreamWidget(cobject, x), - mainWindow(NULL), - titleMenuItem(_("_Move Stream..."), true), - killMenuItem(_("_Terminate Stream"), true) { - - add_events(Gdk::BUTTON_PRESS_MASK); - - menu.append(titleMenuItem); - titleMenuItem.set_submenu(submenu); - - menu.append(killMenuItem); - killMenuItem.signal_activate().connect(sigc::mem_fun(*this, &SourceOutputWidget::onKill)); -} - -SourceOutputWidget::~SourceOutputWidget() { - clearMenu(); -} - -SourceOutputWidget* SourceOutputWidget::create() { - SourceOutputWidget* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); - return w; -} - -void SourceOutputWidget::onKill() { - pa_operation* o; - if (!(o = pa_context_kill_source_output(context, index, NULL, NULL))) { - show_error(_("pa_context_kill_source_output() failed")); - return; - } - - pa_operation_unref(o); -} - -void SourceOutputWidget::clearMenu() { - - while (!sourceMenuItems.empty()) { - std::map<uint32_t, SourceMenuItem*>::iterator i = sourceMenuItems.begin(); - delete i->second; - sourceMenuItems.erase(i); - } -} - -void SourceOutputWidget::buildMenu() { - for (std::map<uint32_t, SourceWidget*>::iterator i = mainWindow->sourceWidgets.begin(); i != mainWindow->sourceWidgets.end(); ++i) { - SourceMenuItem *m; - sourceMenuItems[i->second->index] = m = new SourceMenuItem(this, i->second->description.c_str(), i->second->index, i->second->index == sourceIndex); - submenu.append(m->menuItem); - } - - menu.show_all(); -} - -void SourceOutputWidget::prepareMenu(void) { - clearMenu(); - buildMenu(); -} - -void SourceOutputWidget::SourceMenuItem::onToggle() { - - if (widget->updating) - return; - - if (!menuItem.get_active()) - return; - - pa_operation* o; - if (!(o = pa_context_move_source_output_by_index(context, widget->index, index, NULL, NULL))) { - show_error(_("pa_context_move_source_output_by_index() failed")); - return; - } - - pa_operation_unref(o); -} - -RoleWidget::RoleWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - StreamWidget(cobject, x) { - - lockToggleButton->hide(); - streamToggleButton->hide(); -} - -RoleWidget* RoleWidget::create() { - RoleWidget* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "streamWidget"); - x->get_widget_derived("streamWidget", w); - return w; -} - -void RoleWidget::onMuteToggleButton() { - StreamWidget::onMuteToggleButton(); - - executeVolumeUpdate(); -} - -void RoleWidget::executeVolumeUpdate() { - pa_ext_stream_restore_info info; - - if (updating) - return; - - info.name = role.c_str(); - info.channel_map.channels = 1; - info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO; - info.volume = volume; - info.device = device == "" ? NULL : device.c_str(); - info.mute = muteToggleButton->get_active(); - - pa_operation* o; - if (!(o = pa_ext_stream_restore_write(context, PA_UPDATE_REPLACE, &info, 1, TRUE, NULL, NULL))) { - show_error(_("pa_ext_stream_restore_write() failed")); - return; - } - - pa_operation_unref(o); -} - -/*** MainWindow ***/ - -MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) : - Gtk::Window(cobject), - showSinkInputType(SINK_INPUT_CLIENT), - showSinkType(SINK_ALL), - showSourceOutputType(SOURCE_OUTPUT_CLIENT), - showSourceType(SOURCE_NO_MONITOR), - eventRoleWidget(NULL){ - - x->get_widget("cardsVBox", cardsVBox); - x->get_widget("streamsVBox", streamsVBox); - x->get_widget("recsVBox", recsVBox); - x->get_widget("sinksVBox", sinksVBox); - x->get_widget("sourcesVBox", sourcesVBox); - x->get_widget("noCardsLabel", noCardsLabel); - x->get_widget("noStreamsLabel", noStreamsLabel); - x->get_widget("noRecsLabel", noRecsLabel); - x->get_widget("noSinksLabel", noSinksLabel); - x->get_widget("noSourcesLabel", noSourcesLabel); - x->get_widget("sinkInputTypeComboBox", sinkInputTypeComboBox); - x->get_widget("sourceOutputTypeComboBox", sourceOutputTypeComboBox); - x->get_widget("sinkTypeComboBox", sinkTypeComboBox); - x->get_widget("sourceTypeComboBox", sourceTypeComboBox); - x->get_widget("notebook", notebook); - - cardsVBox->set_reallocate_redraws(true); - sourcesVBox->set_reallocate_redraws(true); - streamsVBox->set_reallocate_redraws(true); - recsVBox->set_reallocate_redraws(true); - sinksVBox->set_reallocate_redraws(true); - - sinkInputTypeComboBox->set_active((int) showSinkInputType); - sourceOutputTypeComboBox->set_active((int) showSourceOutputType); - sinkTypeComboBox->set_active((int) showSinkType); - sourceTypeComboBox->set_active((int) showSourceType); - - sinkInputTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSinkInputTypeComboBoxChanged)); - sourceOutputTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceOutputTypeComboBoxChanged)); - sinkTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSinkTypeComboBoxChanged)); - sourceTypeComboBox->signal_changed().connect(sigc::mem_fun(*this, &MainWindow::onSourceTypeComboBoxChanged)); -} - -MainWindow* MainWindow::create() { - MainWindow* w; - Glib::RefPtr<Gnome::Glade::Xml> x = Gnome::Glade::Xml::create(GLADE_FILE, "mainWindow"); - x->get_widget_derived("mainWindow", w); - return w; -} - -void MainWindow::on_realize() { - Gtk::Window::on_realize(); - - get_window()->set_cursor(Gdk::Cursor(Gdk::WATCH)); -} - -MainWindow::~MainWindow() { - while (!clientNames.empty()) { - std::map<uint32_t, char*>::iterator i = clientNames.begin(); - g_free(i->second); - clientNames.erase(i); - } -} - -static void set_icon_name_fallback(Gtk::Image *i, const char *name, Gtk::IconSize size) { - Glib::RefPtr<Gtk::IconTheme> theme; - Glib::RefPtr<Gdk::Pixbuf> pixbuf; - gint width = 24, height = 24; - - Gtk::IconSize::lookup(size, width, height); - theme = Gtk::IconTheme::get_default(); - pixbuf = theme->load_icon(name, width, Gtk::ICON_LOOKUP_GENERIC_FALLBACK); - - if (pixbuf) - i->set(pixbuf); - else - i->set(name); -} - -void MainWindow::updateCard(const pa_card_info &info) { - CardWidget *w; - bool is_new = false; - const char *description, *icon; - - if (cardWidgets.count(info.index)) - w = cardWidgets[info.index]; - else { - cardWidgets[info.index] = w = CardWidget::create(); - cardsVBox->pack_start(*w, false, false, 0); - w->index = info.index; - is_new = true; - } - - w->updating = true; - - description = pa_proplist_gets(info.proplist, PA_PROP_DEVICE_DESCRIPTION); - w->name = description ? description : info.name; - w->nameLabel->set_markup(w->name.c_str()); - - icon = pa_proplist_gets(info.proplist, PA_PROP_DEVICE_ICON_NAME); - set_icon_name_fallback(w->iconImage, icon ? icon : "audio-card", Gtk::ICON_SIZE_SMALL_TOOLBAR); - - w->hasSinks = w->hasSources = false; - w->profiles.clear(); - for (uint32_t i=0; i<info.n_profiles; ++i) { - w->hasSinks = w->hasSinks || (info.profiles[i].n_sinks > 0); - w->hasSources = w->hasSources || (info.profiles[i].n_sources > 0); - w->profiles.insert(std::pair<Glib::ustring,Glib::ustring>(info.profiles[i].name, info.profiles[i].description)); - } - w->activeProfile = info.active_profile->name; - //w->defaultMenuItem.set_active(w->name == defaultSinkName); - - w->updating = false; - - w->prepareMenu(); - - if (is_new) - updateDeviceVisibility(); -} - -void MainWindow::updateSink(const pa_sink_info &info) { - SinkWidget *w; - bool is_new = false; - const char *icon; - - if (sinkWidgets.count(info.index)) - w = sinkWidgets[info.index]; - else { - sinkWidgets[info.index] = w = SinkWidget::create(); - w->beepDevice = info.name; - w->setChannelMap(info.channel_map, !!(info.flags & PA_SINK_DECIBEL_VOLUME)); - sinksVBox->pack_start(*w, false, false, 0); - w->index = info.index; - w->monitor_index = info.monitor_source; - is_new = true; - } - - w->updating = true; - - w->card_index = info.card; - w->name = info.name; - w->description = info.description; - w->type = info.flags & PA_SINK_HARDWARE ? SINK_HARDWARE : SINK_VIRTUAL; - - w->boldNameLabel->set_text(""); - gchar *txt; - w->nameLabel->set_markup(txt = g_markup_printf_escaped("%s", info.description)); - g_free(txt); - - icon = pa_proplist_gets(info.proplist, PA_PROP_DEVICE_ICON_NAME); - set_icon_name_fallback(w->iconImage, icon ? icon : "audio-card", Gtk::ICON_SIZE_SMALL_TOOLBAR); - - w->setVolume(info.volume); - w->muteToggleButton->set_active(info.mute); - - w->defaultMenuItem.set_active(w->name == defaultSinkName); - - w->updating = false; - - if (is_new) - updateDeviceVisibility(); -} - -static void suspended_callback(pa_stream *s, void *userdata) { - MainWindow *w = static_cast<MainWindow*>(userdata); - - if (pa_stream_is_suspended(s)) - w->updateVolumeMeter(pa_stream_get_device_index(s), PA_INVALID_INDEX, -1); -} - -static void read_callback(pa_stream *s, size_t length, void *userdata) { - MainWindow *w = static_cast<MainWindow*>(userdata); - const void *data; - double v; - - if (pa_stream_peek(s, &data, &length) < 0) { - show_error(_("Failed to read data from stream")); - return; - } - - assert(length > 0); - assert(length % sizeof(float) == 0); - - v = ((const float*) data)[length / sizeof(float) -1]; - - pa_stream_drop(s); - - if (v < 0) - v = 0; - if (v > 1) - v = 1; - - w->updateVolumeMeter(pa_stream_get_device_index(s), pa_stream_get_monitor_stream(s), v); -} - -void MainWindow::createMonitorStreamForSource(uint32_t source_idx) { - pa_stream *s; - char t[16]; - pa_buffer_attr attr; - pa_sample_spec ss; - return; - - ss.channels = 1; - ss.format = PA_SAMPLE_FLOAT32; - ss.rate = 25; - - memset(&attr, 0, sizeof(attr)); - attr.fragsize = sizeof(float); - attr.maxlength = (uint32_t) -1; - - snprintf(t, sizeof(t), "%u", source_idx); - - if (!(s = pa_stream_new(context, _("Peak detect"), &ss, NULL))) { - show_error(_("Failed to create monitoring stream")); - return; - } - - pa_stream_set_read_callback(s, read_callback, this); - pa_stream_set_suspended_callback(s, suspended_callback, this); - - if (pa_stream_connect_record(s, t, &attr, (pa_stream_flags_t) (PA_STREAM_DONT_MOVE|PA_STREAM_PEAK_DETECT|PA_STREAM_ADJUST_LATENCY)) < 0) { - show_error(_("Failed to connect monitoring stream")); - pa_stream_unref(s); - return; - } -} - -void MainWindow::createMonitorStreamForSinkInput(uint32_t sink_input_idx, uint32_t sink_idx) { - pa_stream *s; - char t[16]; - pa_buffer_attr attr; - pa_sample_spec ss; - uint32_t monitor_source_idx; - return; - - ss.channels = 1; - ss.format = PA_SAMPLE_FLOAT32; - ss.rate = 25; - - if (!sinkWidgets.count(sink_idx)) - return; - - monitor_source_idx = sinkWidgets[sink_idx]->monitor_index; - - memset(&attr, 0, sizeof(attr)); - attr.fragsize = sizeof(float); - attr.maxlength = (uint32_t) -1; - - snprintf(t, sizeof(t), "%u", monitor_source_idx); - - if (!(s = pa_stream_new(context, _("Peak detect"), &ss, NULL))) { - show_error(_("Failed to create monitoring stream")); - return; - } - - pa_stream_set_monitor_stream(s, sink_input_idx); - pa_stream_set_read_callback(s, read_callback, this); - pa_stream_set_suspended_callback(s, suspended_callback, this); - - if (pa_stream_connect_record(s, t, &attr, (pa_stream_flags_t) (PA_STREAM_DONT_MOVE|PA_STREAM_PEAK_DETECT|PA_STREAM_ADJUST_LATENCY)) < 0) { - show_error(_("Failed to connect monitoring stream")); - pa_stream_unref(s); - return; - } -} - -void MainWindow::updateSource(const pa_source_info &info) { - SourceWidget *w; - bool is_new = false; - const char *icon; - - if (sourceWidgets.count(info.index)) - w = sourceWidgets[info.index]; - else { - sourceWidgets[info.index] = w = SourceWidget::create(); - w->setChannelMap(info.channel_map, !!(info.flags & PA_SOURCE_DECIBEL_VOLUME)); - sourcesVBox->pack_start(*w, false, false, 0); - w->index = info.index; - is_new = true; - - if (pa_context_get_server_protocol_version(context) >= 13) - createMonitorStreamForSource(info.index); - } - - w->updating = true; - - w->card_index = info.card; - w->name = info.name; - w->description = info.description; - w->type = info.monitor_of_sink != PA_INVALID_INDEX ? SOURCE_MONITOR : (info.flags & PA_SOURCE_HARDWARE ? SOURCE_HARDWARE : SOURCE_VIRTUAL); - - w->boldNameLabel->set_text(""); - gchar *txt; - w->nameLabel->set_markup(txt = g_markup_printf_escaped("%s", info.description)); - g_free(txt); - - icon = pa_proplist_gets(info.proplist, PA_PROP_DEVICE_ICON_NAME); - set_icon_name_fallback(w->iconImage, icon ? icon : "audio-input-microphone", Gtk::ICON_SIZE_SMALL_TOOLBAR); - - w->setVolume(info.volume); - w->muteToggleButton->set_active(info.mute); - - w->defaultMenuItem.set_active(w->name == defaultSourceName); - - w->updating = false; - - if (is_new) - updateDeviceVisibility(); -} - -void MainWindow::setIconFromProplist(Gtk::Image *icon, pa_proplist *l, const char *def) { - const char *t; - - if ((t = pa_proplist_gets(l, PA_PROP_MEDIA_ICON_NAME))) - goto finish; - - if ((t = pa_proplist_gets(l, PA_PROP_WINDOW_ICON_NAME))) - goto finish; - - if ((t = pa_proplist_gets(l, PA_PROP_APPLICATION_ICON_NAME))) - goto finish; - - if ((t = pa_proplist_gets(l, PA_PROP_MEDIA_ROLE))) { - - if (strcmp(t, "video") == 0 || - strcmp(t, "phone") == 0) - goto finish; - - if (strcmp(t, "music") == 0) { - t = "audio"; - goto finish; - } - - if (strcmp(t, "game") == 0) { - t = "applications-games"; - goto finish; - } - - if (strcmp(t, "event") == 0) { - t = "dialog-information"; - goto finish; - } - } - - t = def; - -finish: - - icon->set_from_icon_name(t, Gtk::ICON_SIZE_SMALL_TOOLBAR); -} - -void MainWindow::updateSinkInput(const pa_sink_input_info &info) { - SinkInputWidget *w; - bool is_new = false; - - if (sinkInputWidgets.count(info.index)) - w = sinkInputWidgets[info.index]; - else { - sinkInputWidgets[info.index] = w = SinkInputWidget::create(); - w->setChannelMap(info.channel_map, true); - streamsVBox->pack_start(*w, false, false, 0); - w->index = info.index; - w->clientIndex = info.client; - w->mainWindow = this; - is_new = true; - - if (pa_context_get_server_protocol_version(context) >= 13) - createMonitorStreamForSinkInput(info.index, info.sink); - } - - w->updating = true; - - w->type = info.client != PA_INVALID_INDEX ? SINK_INPUT_CLIENT : SINK_INPUT_VIRTUAL; - - w->sinkIndex = info.sink; - - char *txt; - if (clientNames.count(info.client)) { - w->boldNameLabel->set_markup(txt = g_markup_printf_escaped("<b>%s</b>", clientNames[info.client])); - g_free(txt); - w->nameLabel->set_markup(txt = g_markup_printf_escaped(": %s", info.name)); - g_free(txt); - } else { - w->boldNameLabel->set_text(""); - w->nameLabel->set_label(info.name); - } - - setIconFromProplist(w->iconImage, info.proplist, "audio-card"); - - w->setVolume(info.volume); - w->muteToggleButton->set_active(info.mute); - - w->updating = false; - - if (is_new) - updateDeviceVisibility(); -} - -void MainWindow::updateSourceOutput(const pa_source_output_info &info) { - SourceOutputWidget *w; - const char *app; - bool is_new = false; - - if ((app = pa_proplist_gets(info.proplist, PA_PROP_APPLICATION_ID))) - if (strcmp(app, "org.PulseAudio.pavucontrol") == 0) - return; - - if (sourceOutputWidgets.count(info.index)) - w = sourceOutputWidgets[info.index]; - else { - sourceOutputWidgets[info.index] = w = SourceOutputWidget::create(); - recsVBox->pack_start(*w, false, false, 0); - w->index = info.index; - w->clientIndex = info.client; - w->mainWindow = this; - } - - w->updating = true; - - w->type = info.client != PA_INVALID_INDEX ? SOURCE_OUTPUT_CLIENT : SOURCE_OUTPUT_VIRTUAL; - - w->sourceIndex = info.source; - - char *txt; - if (clientNames.count(info.client)) { - w->boldNameLabel->set_markup(txt = g_markup_printf_escaped("<b>%s</b>", clientNames[info.client])); - g_free(txt); - w->nameLabel->set_markup(txt = g_markup_printf_escaped(": %s", info.name)); - g_free(txt); - } else { - w->boldNameLabel->set_text(""); - w->nameLabel->set_label(info.name); - } - - setIconFromProplist(w->iconImage, info.proplist, "audio-input-microphone"); - - w->updating = false; - - if (is_new) - updateDeviceVisibility(); -} - -void MainWindow::updateClient(const pa_client_info &info) { - - g_free(clientNames[info.index]); - clientNames[info.index] = g_strdup(info.name); - - for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) { - SinkInputWidget *w = i->second; - - if (!w) - continue; - - if (w->clientIndex == info.index) { - gchar *txt; - w->boldNameLabel->set_markup(txt = g_markup_printf_escaped("<b>%s</b>", info.name)); - g_free(txt); - } - } -} - -void MainWindow::updateServer(const pa_server_info &info) { - - defaultSourceName = info.default_source_name ? info.default_source_name : ""; - defaultSinkName = info.default_sink_name ? info.default_sink_name : ""; - - for (std::map<uint32_t, SinkWidget*>::iterator i = sinkWidgets.begin(); i != sinkWidgets.end(); ++i) { - SinkWidget *w = i->second; - - if (!w) - continue; - - w->updating = true; - w->defaultMenuItem.set_active(w->name == defaultSinkName); - w->updating = false; - } - - for (std::map<uint32_t, SourceWidget*>::iterator i = sourceWidgets.begin(); i != sourceWidgets.end(); ++i) { - SourceWidget *w = i->second; - - if (!w) - continue; - - w->updating = true; - w->defaultMenuItem.set_active(w->name == defaultSourceName); - w->updating = false; - } -} - -bool MainWindow::createEventRoleWidget() { - if (eventRoleWidget) - return FALSE; - - pa_channel_map cm = { - 1, { PA_CHANNEL_POSITION_MONO } - }; - - eventRoleWidget = RoleWidget::create(); - streamsVBox->pack_start(*eventRoleWidget, false, false, 0); - eventRoleWidget->role = "sink-input-by-media-role:event"; - eventRoleWidget->setChannelMap(cm, true); - - eventRoleWidget->boldNameLabel->set_text(""); - eventRoleWidget->nameLabel->set_label(_("System Sounds")); - - eventRoleWidget->iconImage->set_from_icon_name("multimedia-volume-control", Gtk::ICON_SIZE_SMALL_TOOLBAR); - - eventRoleWidget->device = ""; - - eventRoleWidget->updating = true; - - pa_cvolume volume; - volume.channels = 1; - volume.values[0] = PA_VOLUME_NORM; - - eventRoleWidget->setVolume(volume); - eventRoleWidget->muteToggleButton->set_active(false); - - eventRoleWidget->updating = false; - - return TRUE; -} - -void MainWindow::deleteEventRoleWidget() { - - if (eventRoleWidget) - delete eventRoleWidget; - - eventRoleWidget = NULL; -} - -void MainWindow::updateRole(const pa_ext_stream_restore_info &info) { - pa_cvolume volume; - bool is_new = false; - - if (strcmp(info.name, "sink-input-by-media-role:event") != 0) - return; - - is_new = createEventRoleWidget(); - - eventRoleWidget->updating = true; - - eventRoleWidget->device = info.device ? info.device : ""; - - volume.channels = 1; - volume.values[0] = pa_cvolume_max(&info.volume); - - eventRoleWidget->setVolume(volume); - eventRoleWidget->muteToggleButton->set_active(info.mute); - - eventRoleWidget->updating = false; - - if (is_new) - updateDeviceVisibility(); -} - -void MainWindow::updateVolumeMeter(uint32_t source_index, uint32_t sink_input_idx, double v) { - - if (sink_input_idx != PA_INVALID_INDEX) { - SinkInputWidget *w; - - if (sinkInputWidgets.count(sink_input_idx)) { - w = sinkInputWidgets[sink_input_idx]; - w->updatePeak(v); - } - - } else { - - for (std::map<uint32_t, SinkWidget*>::iterator i = sinkWidgets.begin(); i != sinkWidgets.end(); ++i) { - SinkWidget* w = i->second; - - if (w->monitor_index == source_index) - w->updatePeak(v); - } - - for (std::map<uint32_t, SourceWidget*>::iterator i = sourceWidgets.begin(); i != sourceWidgets.end(); ++i) { - SourceWidget* w = i->second; - - if (w->index == source_index) - w->updatePeak(v); - } - - for (std::map<uint32_t, SourceOutputWidget*>::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) { - SourceOutputWidget* w = i->second; - - if (w->sourceIndex == source_index) - w->updatePeak(v); - } - } -} - -static guint idle_source = 0; - -gboolean idle_cb(gpointer data) { - ((MainWindow*) data)->reallyUpdateDeviceVisibility(); - idle_source = 0; - return FALSE; -} - -void MainWindow::updateDeviceVisibility() { - - if (idle_source) - return; - - idle_source = g_idle_add(idle_cb, this); -} - -void MainWindow::reallyUpdateDeviceVisibility() { - bool is_empty = true; - - for (std::map<uint32_t, SinkInputWidget*>::iterator i = sinkInputWidgets.begin(); i != sinkInputWidgets.end(); ++i) { - SinkInputWidget* w = i->second; - - if (showSinkInputType == SINK_INPUT_ALL || w->type == showSinkInputType) { - w->show(); - is_empty = false; - } else - w->hide(); - } - - if (eventRoleWidget) - is_empty = false; - - if (is_empty) - noStreamsLabel->show(); - else - noStreamsLabel->hide(); - - is_empty = true; - - for (std::map<uint32_t, SourceOutputWidget*>::iterator i = sourceOutputWidgets.begin(); i != sourceOutputWidgets.end(); ++i) { - SourceOutputWidget* w = i->second; - - if (showSourceOutputType == SOURCE_OUTPUT_ALL || w->type == showSourceOutputType) { - w->show(); - is_empty = false; - } else - w->hide(); - } - - if (is_empty) - noRecsLabel->show(); - else - noRecsLabel->hide(); - - is_empty = true; - - for (std::map<uint32_t, SinkWidget*>::iterator i = sinkWidgets.begin(); i != sinkWidgets.end(); ++i) { - SinkWidget* w = i->second; - - if (showSinkType == SINK_ALL || w->type == showSinkType) { - w->show(); - is_empty = false; - } else - w->hide(); - } - - if (is_empty) - noSinksLabel->show(); - else - noSinksLabel->hide(); - - is_empty = true; - - for (std::map<uint32_t, CardWidget*>::iterator i = cardWidgets.begin(); i != cardWidgets.end(); ++i) { - CardWidget* w = i->second; - - w->show(); - is_empty = false; - } - - if (is_empty) - noCardsLabel->show(); - else - noCardsLabel->hide(); - - is_empty = true; - - for (std::map<uint32_t, SourceWidget*>::iterator i = sourceWidgets.begin(); i != sourceWidgets.end(); ++i) { - SourceWidget* w = i->second; - - if (showSourceType == SOURCE_ALL || - w->type == showSourceType || - (showSourceType == SOURCE_NO_MONITOR && w->type != SOURCE_MONITOR)) { - w->show(); - is_empty = false; - } else - w->hide(); - } - - if (is_empty) - noSourcesLabel->show(); - else - noSourcesLabel->hide(); - - /* Hmm, if I don't call hide()/show() here some widgets will never - * get their proper space allocated */ - sinksVBox->hide(); - sinksVBox->show(); - sourcesVBox->hide(); - sourcesVBox->show(); - streamsVBox->hide(); - streamsVBox->show(); - recsVBox->hide(); - recsVBox->show(); - cardsVBox->hide(); - cardsVBox->show(); -} - -void MainWindow::removeCard(uint32_t index) { - if (!cardWidgets.count(index)) - return; - - delete cardWidgets[index]; - cardWidgets.erase(index); - updateDeviceVisibility(); -} - -void MainWindow::removeSink(uint32_t index) { - if (!sinkWidgets.count(index)) - return; - - delete sinkWidgets[index]; - sinkWidgets.erase(index); - updateDeviceVisibility(); -} - -void MainWindow::removeSource(uint32_t index) { - if (!sourceWidgets.count(index)) - return; - - delete sourceWidgets[index]; - sourceWidgets.erase(index); - updateDeviceVisibility(); -} - -void MainWindow::removeSinkInput(uint32_t index) { - if (!sinkInputWidgets.count(index)) - return; - - delete sinkInputWidgets[index]; - sinkInputWidgets.erase(index); - updateDeviceVisibility(); -} - -void MainWindow::removeSourceOutput(uint32_t index) { - if (!sourceOutputWidgets.count(index)) - return; - - delete sourceOutputWidgets[index]; - sourceOutputWidgets.erase(index); - updateDeviceVisibility(); -} - -void MainWindow::removeClient(uint32_t index) { - g_free(clientNames[index]); - clientNames.erase(index); -} - -void MainWindow::onSinkTypeComboBoxChanged() { - showSinkType = (SinkType) sinkTypeComboBox->get_active_row_number(); - - if (showSinkType == (SinkType) -1) - sinkTypeComboBox->set_active((int) SINK_ALL); - - updateDeviceVisibility(); -} - -void MainWindow::onSourceTypeComboBoxChanged() { - showSourceType = (SourceType) sourceTypeComboBox->get_active_row_number(); - - if (showSourceType == (SourceType) -1) - sourceTypeComboBox->set_active((int) SOURCE_NO_MONITOR); - - updateDeviceVisibility(); -} - -void MainWindow::onSinkInputTypeComboBoxChanged() { - showSinkInputType = (SinkInputType) sinkInputTypeComboBox->get_active_row_number(); - - if (showSinkInputType == (SinkInputType) -1) - sinkInputTypeComboBox->set_active((int) SINK_INPUT_CLIENT); - - updateDeviceVisibility(); -} - -void MainWindow::onSourceOutputTypeComboBoxChanged() { - showSourceOutputType = (SourceOutputType) sourceOutputTypeComboBox->get_active_row_number(); - - if (showSourceOutputType == (SourceOutputType) -1) - sourceOutputTypeComboBox->set_active((int) SOURCE_OUTPUT_CLIENT); - - updateDeviceVisibility(); -} - static void dec_outstanding(MainWindow *w) { if (n_outstanding <= 0) return; @@ -2012,7 +211,8 @@ void ext_stream_restore_read_cb( MainWindow *w = static_cast<MainWindow*>(userdata); if (eol < 0) { - g_debug(_("Failed to initialized stream_restore extension: %s"), pa_strerror(pa_context_errno(context))); + dec_outstanding(w); + g_debug(_("Failed to initialize stream_restore extension: %s"), pa_strerror(pa_context_errno(context))); w->deleteEventRoleWidget(); return; } @@ -2164,7 +364,7 @@ void context_state_callback(pa_context *c, void *userdata) { } pa_operation_unref(o); - // Keep track of the outstanding callbacks for UI tweaks + /* Keep track of the outstanding callbacks for UI tweaks */ n_outstanding = 0; if (!(o = pa_context_get_server_info(c, server_info_cb, w))) { @@ -2227,7 +427,8 @@ void context_state_callback(pa_context *c, void *userdata) { pa_operation_unref(o); } else - g_debug(_("Failed to initialized stream_restore extension: %s"), pa_strerror(pa_context_errno(context))); + g_debug(_("Failed to initialize stream_restore extension: %s"), pa_strerror(pa_context_errno(context))); + break; } @@ -2243,6 +444,10 @@ void context_state_callback(pa_context *c, void *userdata) { } } +pa_context* get_context(void) { + return context; +} + int main(int argc, char *argv[]) { /* Initialize the i18n stuff */ |