cardwidget: add flag to lock profile from switching automatically
Part-of: <https://gitlab.freedesktop.org/pulseaudio/pavucontrol/-/merge_requests/60>
This commit is contained in:
parent
b874058ae8
commit
a1b4622ad5
|
@ -35,6 +35,7 @@ CardWidget::CardWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>
|
||||||
x->get_widget("cardIconImage", iconImage);
|
x->get_widget("cardIconImage", iconImage);
|
||||||
x->get_widget("codecBox", codecBox);
|
x->get_widget("codecBox", codecBox);
|
||||||
x->get_widget("codecList", codecList);
|
x->get_widget("codecList", codecList);
|
||||||
|
x->get_widget("profileLockToggleButton", profileLockToggleButton);
|
||||||
|
|
||||||
profileListStore = Gtk::ListStore::create(profileModel);
|
profileListStore = Gtk::ListStore::create(profileModel);
|
||||||
profileList->set_model(profileListStore);
|
profileList->set_model(profileListStore);
|
||||||
|
@ -49,6 +50,12 @@ CardWidget::CardWidget(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>
|
||||||
codecList->pack_start(codecModel.desc);
|
codecList->pack_start(codecModel.desc);
|
||||||
|
|
||||||
codecList->signal_changed().connect( sigc::mem_fun(*this, &CardWidget::onCodecChange));
|
codecList->signal_changed().connect( sigc::mem_fun(*this, &CardWidget::onCodecChange));
|
||||||
|
|
||||||
|
hasProfileLock = false;
|
||||||
|
|
||||||
|
profileLockToggleButton->signal_clicked().connect(sigc::mem_fun(*this, &CardWidget::onProfileLockToggleButton));
|
||||||
|
profileLockToggleButton->set_sensitive(true);
|
||||||
|
profileLockToggleButton->set_visible(hasProfileLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
CardWidget* CardWidget::create() {
|
CardWidget* CardWidget::create() {
|
||||||
|
@ -96,6 +103,8 @@ void CardWidget::prepareMenu() {
|
||||||
codecBox->show();
|
codecBox->show();
|
||||||
else
|
else
|
||||||
codecBox->hide();
|
codecBox->hide();
|
||||||
|
|
||||||
|
profileLockToggleButton->set_visible(hasProfileLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardWidget::onProfileChange() {
|
void CardWidget::onProfileChange() {
|
||||||
|
@ -150,3 +159,31 @@ void CardWidget::onCodecChange() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardWidget::onProfileLockToggleButton() {
|
||||||
|
if (updating)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef HAVE_PULSE_MESSAGING_API
|
||||||
|
Gtk::TreeModel::iterator iter = profileList->get_active();
|
||||||
|
if (iter)
|
||||||
|
{
|
||||||
|
Gtk::TreeModel::Row row = *iter;
|
||||||
|
if (row)
|
||||||
|
{
|
||||||
|
pa_operation* o;
|
||||||
|
Glib::ustring profile = row[profileModel.name];
|
||||||
|
|
||||||
|
bool profileIsLocked = profileLockToggleButton->get_active();
|
||||||
|
|
||||||
|
if (!(o = pa_context_send_message_to_object(get_context(), card_message_handler_path(pulse_card_name).c_str(),
|
||||||
|
"set-profile-sticky", profileIsLocked ? "true" : "false", NULL, NULL))) {
|
||||||
|
g_debug(_("pa_context_send_message_to_object() failed: %s"), pa_strerror(pa_context_errno(get_context())));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_operation_unref(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
Glib::ustring name;
|
Glib::ustring name;
|
||||||
std::string pulse_card_name;
|
std::string pulse_card_name;
|
||||||
Gtk::Box *codecBox;
|
Gtk::Box *codecBox;
|
||||||
|
Gtk::ToggleButton *profileLockToggleButton;
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
bool updating;
|
bool updating;
|
||||||
|
|
||||||
|
@ -59,11 +60,14 @@ public:
|
||||||
std::vector<std::pair<Glib::ustring, Glib::ustring>> codecs;
|
std::vector<std::pair<Glib::ustring, Glib::ustring>> codecs;
|
||||||
Glib::ustring activeCodec;
|
Glib::ustring activeCodec;
|
||||||
|
|
||||||
|
bool hasProfileLock;
|
||||||
|
|
||||||
void prepareMenu();
|
void prepareMenu();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onProfileChange();
|
virtual void onProfileChange();
|
||||||
virtual void onCodecChange();
|
virtual void onCodecChange();
|
||||||
|
virtual void onProfileLockToggleButton();
|
||||||
|
|
||||||
/* Tree model columns */
|
/* Tree model columns */
|
||||||
class ModelColumns : public Gtk::TreeModel::ColumnRecord
|
class ModelColumns : public Gtk::TreeModel::ColumnRecord
|
||||||
|
|
|
@ -522,6 +522,28 @@ void MainWindow::setActiveCodec(const std::string& card_name, const std::string&
|
||||||
w->updating = false;
|
w->updating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::setCardProfileIsSticky(const std::string& card_name, gboolean profile_is_sticky) {
|
||||||
|
CardWidget *w = NULL;
|
||||||
|
|
||||||
|
for (auto c : cardWidgets) {
|
||||||
|
if (card_name.compare(c.second->pulse_card_name) == 0)
|
||||||
|
w = c.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!w)
|
||||||
|
return;
|
||||||
|
|
||||||
|
w->updating = true;
|
||||||
|
|
||||||
|
/* make sure that profile lock toggle button is visible */
|
||||||
|
w->hasProfileLock = true;
|
||||||
|
w->profileLockToggleButton->set_active(profile_is_sticky);
|
||||||
|
|
||||||
|
w->prepareMenu();
|
||||||
|
|
||||||
|
w->updating = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool MainWindow::updateSink(const pa_sink_info &info) {
|
bool MainWindow::updateSink(const pa_sink_info &info) {
|
||||||
SinkWidget *w;
|
SinkWidget *w;
|
||||||
bool is_new = false;
|
bool is_new = false;
|
||||||
|
|
|
@ -59,6 +59,8 @@ public:
|
||||||
void updateCardCodecs(const std::string& card_name, const std::unordered_map<std::string, std::string>& codecs);
|
void updateCardCodecs(const std::string& card_name, const std::unordered_map<std::string, std::string>& codecs);
|
||||||
void setActiveCodec(const std::string& card_name, const std::string& codec);
|
void setActiveCodec(const std::string& card_name, const std::string& codec);
|
||||||
|
|
||||||
|
void setCardProfileIsSticky(const std::string& card_name, gboolean profile_is_sticky);
|
||||||
|
|
||||||
void removeCard(uint32_t index);
|
void removeCard(uint32_t index);
|
||||||
void removeSink(uint32_t index);
|
void removeSink(uint32_t index);
|
||||||
void removeSource(uint32_t index);
|
void removeSource(uint32_t index);
|
||||||
|
|
|
@ -81,6 +81,10 @@ static void dec_outstanding(MainWindow *w) {
|
||||||
|
|
||||||
#ifdef HAVE_PULSE_MESSAGING_API
|
#ifdef HAVE_PULSE_MESSAGING_API
|
||||||
|
|
||||||
|
std::string card_message_handler_path(const std::string& name) {
|
||||||
|
return "/card/" + name;
|
||||||
|
}
|
||||||
|
|
||||||
std::string card_bluez_message_handler_path(const std::string& name) {
|
std::string card_bluez_message_handler_path(const std::string& name) {
|
||||||
return "/card/" + name + "/bluez";
|
return "/card/" + name + "/bluez";
|
||||||
}
|
}
|
||||||
|
@ -201,6 +205,39 @@ static void context_bluetooth_card_active_codec_cb(pa_context *c, int success, c
|
||||||
g_object_unref(parser);
|
g_object_unref(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void context_card_profile_is_sticky_cb(pa_context *c, int success, char *response, void *userdata) {
|
||||||
|
auto u = std::unique_ptr<WindowAndCardName>(reinterpret_cast<WindowAndCardName*>(userdata));
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
return;
|
||||||
|
|
||||||
|
gboolean profile_is_sticky;
|
||||||
|
GError *gerror = NULL;
|
||||||
|
|
||||||
|
JsonParser *parser = json_parser_new();
|
||||||
|
|
||||||
|
if (!json_parser_load_from_data(parser, response, strlen(response), &gerror)) {
|
||||||
|
g_debug(_("could not read JSON from get-profile-sticky message response: %s"), gerror->message);
|
||||||
|
g_error_free(gerror);
|
||||||
|
g_object_unref(parser);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode *root = json_parser_get_root(parser);
|
||||||
|
|
||||||
|
if (!root || JSON_NODE_TYPE(root) != JSON_NODE_VALUE) {
|
||||||
|
g_debug(_("get-profile-sticky message response is not a JSON value"));
|
||||||
|
g_object_unref(parser);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_is_sticky = json_node_get_boolean(root);
|
||||||
|
|
||||||
|
u->first->setCardProfileIsSticky(u->second, profile_is_sticky);
|
||||||
|
|
||||||
|
g_object_unref(parser);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename U> void send_message(pa_context *c, const char *target, const char *request, pa_context_string_cb_t cb, const U& u)
|
template<typename U> void send_message(pa_context *c, const char *target, const char *request, pa_context_string_cb_t cb, const U& u)
|
||||||
{
|
{
|
||||||
auto send_message_userdata = new U(u);
|
auto send_message_userdata = new U(u);
|
||||||
|
@ -300,6 +337,14 @@ static void context_message_handlers_cb(pa_context *c, int success, char *respon
|
||||||
/* list-codecs: retrieve list of codecs */
|
/* list-codecs: retrieve list of codecs */
|
||||||
send_message(c, e->first.c_str(), "list-codecs", context_bluetooth_card_codec_list_cb, *u);
|
send_message(c, e->first.c_str(), "list-codecs", context_bluetooth_card_codec_list_cb, *u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* send requests to card if card message handler is registered */
|
||||||
|
e = message_handler_map.find(card_message_handler_path(u->second));
|
||||||
|
|
||||||
|
if (e != message_handler_map.end()) {
|
||||||
|
/* get-profile-sticky: retrieve active codec name */
|
||||||
|
send_message(c, e->first.c_str(), "get-profile-sticky", context_card_profile_is_sticky_cb, *u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,41 @@
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox14">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="spacing">3</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkToggleButton" id="profileLockToggleButton">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Lock card to this profile</property>
|
||||||
|
<property name="relief">none</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="image4">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">changes-prevent</property>
|
||||||
|
<property name="icon_size">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
|
|
|
@ -79,6 +79,7 @@ void show_error(const char *txt);
|
||||||
MainWindow* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool retry, int tab_number);
|
MainWindow* pavucontrol_get_window(pa_glib_mainloop *m, bool maximize, bool retry, int tab_number);
|
||||||
|
|
||||||
#ifdef HAVE_PULSE_MESSAGING_API
|
#ifdef HAVE_PULSE_MESSAGING_API
|
||||||
|
std::string card_message_handler_path(const std::string& name);
|
||||||
std::string card_bluez_message_handler_path(const std::string& name);
|
std::string card_bluez_message_handler_path(const std::string& name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue