summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-04-20 22:13:20 +0000
committerLennart Poettering <lennart@poettering.net>2008-04-20 22:13:20 +0000
commitd8b6b58fe3eb20bc5d418497b69ed05a2fa11c94 (patch)
tree718624f59c06effa03c51bc80e66978eecf419f9
parent3d45d8bf538b03d972545f9cd7a6a84cb9c37661 (diff)
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
-rw-r--r--src/pavucontrol.cc393
-rw-r--r--src/pavucontrol.glade247
2 files changed, 574 insertions, 66 deletions
diff --git a/src/pavucontrol.cc b/src/pavucontrol.cc
index 5040f16..dd6aead 100644
--- a/src/pavucontrol.cc
+++ b/src/pavucontrol.cc
@@ -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;
}
diff --git a/src/pavucontrol.glade b/src/pavucontrol.glade
index 3f7918c..e9434d4 100644
--- a/src/pavucontrol.glade
+++ b/src/pavucontrol.glade
@@ -213,6 +213,135 @@ Virtual Streams</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">&lt;i&gt;No Streams Available&lt;/i&gt;</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">&lt;b&gt;Hint:&lt;/b&gt; &lt;i&gt;Right click on a recording stream to move it to another input device.&lt;/i&gt;</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">&lt;b&gt;_Show:&lt;/b&gt;</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&#10;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>
<child>
@@ -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>