Merge patch from sjoerd that adds a new panel for listing recording streams, and makes the menu more visible by adding a button for it
git-svn-id: file:///home/lennart/svn/public/pavucontrol/trunk@71 c17c95f2-f111-0410-90bf-f30a9569010c
This commit is contained in:
parent
3d45d8bf53
commit
d8b6b58fe3
|
@ -3,6 +3,9 @@
|
|||
/***
|
||||
This file is part of pavucontrol.
|
||||
|
||||
Copyright 2006-2008 Lennart Poettering <mzcnihpbageby (at) 0pointer (dot) de>
|
||||
Copyright 2008 Sjoerd Simons <sjoerd@luon.net>
|
||||
|
||||
pavucontrol is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 2 of the License,
|
||||
|
@ -50,6 +53,12 @@ enum SinkType {
|
|||
SINK_VIRTUAL,
|
||||
};
|
||||
|
||||
enum SourceOutputType {
|
||||
SOURCE_OUTPUT_ALL,
|
||||
SOURCE_OUTPUT_CLIENT,
|
||||
SOURCE_OUTPUT_VIRTUAL
|
||||
};
|
||||
|
||||
enum SourceType{
|
||||
SOURCE_ALL,
|
||||
SOURCE_NO_MONITOR,
|
||||
|
@ -82,7 +91,27 @@ public:
|
|||
virtual void set_sensitive(bool enabled);
|
||||
};
|
||||
|
||||
class StreamWidget : public Gtk::VBox {
|
||||
class MinimalStreamWidget : public Gtk::VBox {
|
||||
public:
|
||||
MinimalStreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
|
||||
|
||||
Gtk::Label *nameLabel, *boldNameLabel;
|
||||
Gtk::ToggleButton *streamToggleButton;
|
||||
Gtk::Menu menu;
|
||||
|
||||
bool updating;
|
||||
|
||||
void onStreamToggleButton();
|
||||
void onMenuDeactivated();
|
||||
void popupMenuPosition(int& x, int& y, bool& push_in);
|
||||
|
||||
virtual void prepareMenu(void);
|
||||
|
||||
protected:
|
||||
virtual bool on_button_press_event(GdkEventButton* event);
|
||||
};
|
||||
|
||||
class StreamWidget : public MinimalStreamWidget {
|
||||
public:
|
||||
StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x);
|
||||
|
||||
|
@ -90,12 +119,9 @@ public:
|
|||
void setVolume(const pa_cvolume &volume, bool force);
|
||||
virtual void updateChannelVolume(int channel, pa_volume_t v);
|
||||
|
||||
Gtk::Label *nameLabel, *boldNameLabel;
|
||||
Gtk::VBox *channelsVBox;
|
||||
Gtk::ToggleButton *lockToggleButton, *muteToggleButton;
|
||||
|
||||
bool updating;
|
||||
|
||||
pa_channel_map channelMap;
|
||||
pa_cvolume volume;
|
||||
|
||||
|
@ -120,15 +146,11 @@ public:
|
|||
Glib::ustring name;
|
||||
uint32_t index;
|
||||
|
||||
Gtk::Menu menu;
|
||||
Gtk::CheckMenuItem defaultMenuItem;
|
||||
|
||||
virtual void onMuteToggleButton();
|
||||
virtual void executeVolumeUpdate();
|
||||
virtual void onDefaultToggle();
|
||||
|
||||
protected:
|
||||
virtual bool on_button_press_event(GdkEventButton* event);
|
||||
};
|
||||
|
||||
class SourceWidget : public StreamWidget {
|
||||
|
@ -138,17 +160,14 @@ public:
|
|||
|
||||
SourceType type;
|
||||
Glib::ustring name;
|
||||
Glib::ustring description;
|
||||
uint32_t index;
|
||||
|
||||
Gtk::Menu menu;
|
||||
Gtk::CheckMenuItem defaultMenuItem;
|
||||
|
||||
virtual void onMuteToggleButton();
|
||||
virtual void executeVolumeUpdate();
|
||||
virtual void onDefaultToggle();
|
||||
|
||||
protected:
|
||||
virtual bool on_button_press_event(GdkEventButton* event);
|
||||
};
|
||||
|
||||
class SinkInputWidget : public StreamWidget {
|
||||
|
@ -163,9 +182,10 @@ public:
|
|||
virtual void executeVolumeUpdate();
|
||||
virtual void onMuteToggleButton();
|
||||
virtual void onKill();
|
||||
virtual void prepareMenu();
|
||||
|
||||
MainWindow *mainWindow;
|
||||
Gtk::Menu menu, submenu;
|
||||
Gtk::Menu submenu;
|
||||
Gtk::MenuItem titleMenuItem, killMenuItem;
|
||||
|
||||
struct SinkMenuItem {
|
||||
|
@ -188,9 +208,44 @@ public:
|
|||
|
||||
void clearMenu();
|
||||
void buildMenu();
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual bool on_button_press_event(GdkEventButton* event);
|
||||
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 MainWindow : public Gtk::Window {
|
||||
|
@ -202,29 +257,34 @@ public:
|
|||
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 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::VBox *streamsVBox, *sinksVBox, *sourcesVBox;
|
||||
Gtk::VBox *streamsVBox, *recsVBox, *sinksVBox, *sourcesVBox;
|
||||
Gtk::EventBox *titleEventBox;
|
||||
Gtk::Label *noStreamsLabel, *noSinksLabel, *noSourcesLabel;
|
||||
Gtk::ComboBox *sinkInputTypeComboBox, *sinkTypeComboBox, *sourceTypeComboBox;
|
||||
Gtk::Label *noStreamsLabel, *noRecsLabel, *noSinksLabel, *noSourcesLabel;
|
||||
Gtk::ComboBox *sinkInputTypeComboBox, *sourceOutputTypeComboBox, *sinkTypeComboBox, *sourceTypeComboBox;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -302,15 +362,70 @@ void ChannelWidget::set_sensitive(bool enabled) {
|
|||
volumeScale->set_sensitive(enabled);
|
||||
}
|
||||
|
||||
/*** StreamWidget ***/
|
||||
|
||||
StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
||||
/*** MinimalStreamWidget ***/
|
||||
MinimalStreamWidget::MinimalStreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
||||
Gtk::VBox(cobject),
|
||||
updating(false) {
|
||||
|
||||
x->get_widget("channelsVBox", channelsVBox);
|
||||
x->get_widget("nameLabel", nameLabel);
|
||||
x->get_widget("boldNameLabel", boldNameLabel);
|
||||
x->get_widget("streamToggle", streamToggleButton);
|
||||
|
||||
streamToggleButton->set_active(false);
|
||||
streamToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onStreamToggleButton));
|
||||
menu.signal_deactivate().connect(sigc::mem_fun(*this, &MinimalStreamWidget::onMenuDeactivated));
|
||||
}
|
||||
|
||||
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) {
|
||||
int menu_width, menu_height;
|
||||
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;
|
||||
}
|
||||
|
||||
/*** StreamWidget ***/
|
||||
|
||||
StreamWidget::StreamWidget(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
||||
MinimalStreamWidget(cobject, x) {
|
||||
|
||||
x->get_widget("channelsVBox", channelsVBox);
|
||||
x->get_widget("lockToggleButton", lockToggleButton);
|
||||
x->get_widget("muteToggleButton", muteToggleButton);
|
||||
|
||||
|
@ -425,19 +540,6 @@ void SinkWidget::onMuteToggleButton() {
|
|||
pa_operation_unref(o);
|
||||
}
|
||||
|
||||
bool SinkWidget::on_button_press_event(GdkEventButton* event) {
|
||||
if (StreamWidget::on_button_press_event(event))
|
||||
return TRUE;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
|
||||
|
||||
menu.popup(0, event->time);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void SinkWidget::onDefaultToggle() {
|
||||
pa_operation* o;
|
||||
|
||||
|
@ -496,19 +598,6 @@ void SourceWidget::onMuteToggleButton() {
|
|||
pa_operation_unref(o);
|
||||
}
|
||||
|
||||
bool SourceWidget::on_button_press_event(GdkEventButton* event) {
|
||||
if (StreamWidget::on_button_press_event(event))
|
||||
return TRUE;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
|
||||
|
||||
menu.popup(0, event->time);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void SourceWidget::onDefaultToggle() {
|
||||
pa_operation* o;
|
||||
|
||||
|
@ -574,18 +663,9 @@ void SinkInputWidget::onMuteToggleButton() {
|
|||
pa_operation_unref(o);
|
||||
}
|
||||
|
||||
bool SinkInputWidget::on_button_press_event(GdkEventButton* event) {
|
||||
if (StreamWidget::on_button_press_event(event))
|
||||
return TRUE;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
|
||||
clearMenu();
|
||||
buildMenu();
|
||||
menu.popup(0, event->time);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
void SinkInputWidget::prepareMenu() {
|
||||
clearMenu();
|
||||
buildMenu();
|
||||
}
|
||||
|
||||
void SinkInputWidget::clearMenu() {
|
||||
|
@ -634,6 +714,83 @@ void SinkInputWidget::SinkMenuItem::onToggle() {
|
|||
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, "minimalStreamWidget");
|
||||
x->get_widget_derived("minimalStreamWidget", 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);
|
||||
}
|
||||
|
||||
/*** MainWindow ***/
|
||||
|
||||
MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& x) :
|
||||
|
@ -643,13 +800,16 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
|
|||
showSourceType(SOURCE_NO_MONITOR) {
|
||||
|
||||
x->get_widget("streamsVBox", streamsVBox);
|
||||
x->get_widget("recsVBox", recsVBox);
|
||||
x->get_widget("sinksVBox", sinksVBox);
|
||||
x->get_widget("sourcesVBox", sourcesVBox);
|
||||
x->get_widget("titleEventBox", titleEventBox);
|
||||
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);
|
||||
|
||||
|
@ -658,10 +818,12 @@ MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade:
|
|||
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));
|
||||
|
||||
|
@ -743,6 +905,7 @@ void MainWindow::updateSource(const pa_source_info &info) {
|
|||
w->updating = true;
|
||||
|
||||
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("");
|
||||
|
@ -803,6 +966,45 @@ void MainWindow::updateSinkInput(const pa_sink_input_info &info) {
|
|||
w->updating = false;
|
||||
}
|
||||
|
||||
void MainWindow::updateSourceOutput(const pa_source_output_info &info) {
|
||||
SourceOutputWidget *w;
|
||||
bool is_new = false;
|
||||
|
||||
if (sourceOutputWidgets.count(info.index))
|
||||
w = sourceOutputWidgets[info.index];
|
||||
else {
|
||||
sourceOutputWidgets[info.index] = w = SourceOutputWidget::create();
|
||||
//w->setChannelMap(info.channel_map);
|
||||
recsVBox->pack_start(*w, false, false, 0);
|
||||
w->index = info.index;
|
||||
w->clientIndex = info.client;
|
||||
w->mainWindow = this;
|
||||
is_new = true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (is_new)
|
||||
updateDeviceVisibility();
|
||||
|
||||
w->updating = false;
|
||||
}
|
||||
|
||||
void MainWindow::updateClient(const pa_client_info &info) {
|
||||
|
||||
g_free(clientNames[info.index]);
|
||||
|
@ -851,8 +1053,8 @@ void MainWindow::updateServer(const pa_server_info &info) {
|
|||
}
|
||||
|
||||
void MainWindow::updateDeviceVisibility() {
|
||||
|
||||
streamsVBox->hide_all();
|
||||
recsVBox->hide_all();
|
||||
sourcesVBox->hide_all();
|
||||
sinksVBox->hide_all();
|
||||
|
||||
|
@ -870,6 +1072,18 @@ void MainWindow::updateDeviceVisibility() {
|
|||
if (is_empty)
|
||||
noStreamsLabel->show();
|
||||
|
||||
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_all();
|
||||
is_empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_empty)
|
||||
noRecsLabel->show();
|
||||
|
||||
is_empty = true;
|
||||
|
||||
for (std::map<uint32_t, SinkWidget*>::iterator i = sinkWidgets.begin(); i != sinkWidgets.end(); ++i) {
|
||||
|
@ -901,6 +1115,7 @@ void MainWindow::updateDeviceVisibility() {
|
|||
noSourcesLabel->show();
|
||||
|
||||
sourcesVBox->show();
|
||||
recsVBox->show();
|
||||
sinksVBox->show();
|
||||
streamsVBox->show();
|
||||
}
|
||||
|
@ -932,6 +1147,15 @@ void MainWindow::removeSinkInput(uint32_t 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);
|
||||
|
@ -964,6 +1188,15 @@ void MainWindow::onSinkInputTypeComboBoxChanged() {
|
|||
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;
|
||||
|
@ -1020,6 +1253,22 @@ void sink_input_cb(pa_context *, const pa_sink_input_info *i, int eol, void *use
|
|||
w->updateSinkInput(*i);
|
||||
}
|
||||
|
||||
void source_output_cb(pa_context *, const pa_source_output_info *i, int eol, void *userdata) {
|
||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||
|
||||
if (eol) {
|
||||
dec_outstanding(w);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!i) {
|
||||
show_error("Source output callback failure");
|
||||
return;
|
||||
}
|
||||
|
||||
w->updateSourceOutput(*i);
|
||||
}
|
||||
|
||||
void client_cb(pa_context *, const pa_client_info *i, int eol, void *userdata) {
|
||||
MainWindow *w = static_cast<MainWindow*>(userdata);
|
||||
|
||||
|
@ -1091,6 +1340,19 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index,
|
|||
}
|
||||
break;
|
||||
|
||||
case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
|
||||
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
||||
w->removeSourceOutput(index);
|
||||
else {
|
||||
pa_operation *o;
|
||||
if (!(o = pa_context_get_source_output_info(c, index, source_output_cb, w))) {
|
||||
show_error("pa_context_get_sink_input_info() failed");
|
||||
return;
|
||||
}
|
||||
pa_operation_unref(o);
|
||||
}
|
||||
break;
|
||||
|
||||
case PA_SUBSCRIPTION_EVENT_CLIENT:
|
||||
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
|
||||
w->removeClient(index);
|
||||
|
@ -1136,6 +1398,7 @@ void context_state_callback(pa_context *c, void *userdata) {
|
|||
(PA_SUBSCRIPTION_MASK_SINK|
|
||||
PA_SUBSCRIPTION_MASK_SOURCE|
|
||||
PA_SUBSCRIPTION_MASK_SINK_INPUT|
|
||||
PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
|
||||
PA_SUBSCRIPTION_MASK_CLIENT|
|
||||
PA_SUBSCRIPTION_MASK_SERVER), NULL, NULL))) {
|
||||
show_error("pa_context_subscribe() failed");
|
||||
|
@ -1173,7 +1436,13 @@ void context_state_callback(pa_context *c, void *userdata) {
|
|||
}
|
||||
pa_operation_unref(o);
|
||||
|
||||
n_outstanding = 5;
|
||||
if (!(o = pa_context_get_source_output_info_list(c, source_output_cb, w))) {
|
||||
show_error("pa_context_get_source_output_info_list() failed");
|
||||
return;
|
||||
}
|
||||
pa_operation_unref(o);
|
||||
|
||||
n_outstanding = 6;
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,135 @@ Virtual Streams</property>
|
|||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox2">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<child>
|
||||
<widget class="GtkViewport" id="viewport5">
|
||||
<property name="visible">True</property>
|
||||
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="recsVBox">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="noRecsLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xpad">16</property>
|
||||
<property name="ypad">16</property>
|
||||
<property name="label" translatable="yes"><i>No Streams Available</i></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment9">
|
||||
<property name="visible">True</property>
|
||||
<property name="bottom_padding">12</property>
|
||||
<property name="left_padding">12</property>
|
||||
<property name="right_padding">12</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox7">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkImage" id="image3">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="stock">gtk-dialog-info</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment10">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="right_padding">12</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label7">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes"><b>Hint:</b> <i>Right click on a recording stream to move it to another input device.</i></property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label8">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="label" translatable="yes"><b>_Show:</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkComboBox" id="sourceOutputTypeComboBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
<property name="items" translatable="yes" comments="Applications All streams">All Streams
|
||||
Applications
|
||||
Virtual Streams</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">_Recording</property>
|
||||
<property name="use_underline">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox30">
|
||||
<property name="visible">True</property>
|
||||
|
@ -324,7 +453,7 @@ Virtual Output Devices</property>
|
|||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -335,7 +464,7 @@ Virtual Output Devices</property>
|
|||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
<property name="position">1</property>
|
||||
<property name="position">2</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -453,7 +582,7 @@ Monitors</property>
|
|||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -464,7 +593,7 @@ Monitors</property>
|
|||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">3</property>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
@ -518,6 +647,27 @@ Monitors</property>
|
|||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkToggleButton" id="streamToggle">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<child>
|
||||
<widget class="GtkArrow" id="arrow3">
|
||||
<property name="visible">True</property>
|
||||
<property name="arrow_type">GTK_ARROW_DOWN</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">2</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
@ -673,4 +823,93 @@ Monitors</property>
|
|||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<widget class="GtkWindow" id="minimalStreamWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">window1</property>
|
||||
<child>
|
||||
<widget class="GtkEventBox" id="minimalStreamWidget">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="streamWidget7">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox7">
|
||||
<property name="visible">True</property>
|
||||
<property name="border_width">12</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox9">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="boldNameLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="use_markup">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkLabel" id="nameLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Stream Title</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="wrap_mode">PANGO_WRAP_CHAR</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_MIDDLE</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkToggleButton" id="streamToggle">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<child>
|
||||
<widget class="GtkArrow" id="arrow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="arrow_type">GTK_ARROW_DOWN</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="padding">2</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="hseparator5">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</glade-interface>
|
||||
|
|
Loading…
Reference in New Issue