pidgin/pidgin

Port VV preferences from GtkComboBox to AdwComboRow

13 months ago, Elliott Sales de Andrade
68380e709c16
Parents a8bad57aa8c3
Children 82dbf36ac6db
Port VV preferences from GtkComboBox to AdwComboRow

This removes another `GtkComboBox` and fixes the requested width of the row, so the label no longers gets squashed when you have a long device name.

Testing Done:
Opened Prefs, selected a different Audio Input, and confirmed it was saved/restored when re-opening.
Ran Test Audio and confirmed input was coming from the right input.
Disconnected an audio device and confirmed that the list re-populated correctly.
Disconnected the *selected* audio device and confirmed that the selection dropped back to Default.
Ran Test Audio, disconnected the selected audio device and confirmed the audio pipeline switched to Default device.

Reviewed at https://reviews.imfreedom.org/r/2398/
--- a/pidgin/prefs/pidginvvprefs.c Thu Mar 30 22:03:24 2023 -0500
+++ b/pidgin/prefs/pidginvvprefs.c Thu Mar 30 22:30:46 2023 -0500
@@ -40,8 +40,8 @@
AdwPreferencesPage parent;
struct {
- PidginPrefCombo input;
- PidginPrefCombo output;
+ AdwComboRow *input;
+ AdwComboRow *output;
GtkWidget *threshold_row;
GtkWidget *threshold;
GtkWidget *volume;
@@ -52,8 +52,8 @@
} voice;
struct {
- PidginPrefCombo input;
- PidginPrefCombo output;
+ AdwComboRow *input;
+ AdwComboRow *output;
GtkWidget *frame;
GtkWidget *test;
GstElement *pipeline;
@@ -70,31 +70,37 @@
* Helpers
*****************************************************************************/
static void
-populate_vv_device_menuitems(PurpleMediaElementType type, GtkListStore *store)
+populate_vv_device_menuitems(AdwComboRow *row, PurpleMediaElementType type,
+ const char *active)
{
PurpleMediaManager *manager = NULL;
+ GListStore *store = NULL;
GList *devices;
+ guint selected = 0; /* Default to auto{audio,video}{src,sink} elements. */
- gtk_list_store_clear(store);
+ store = G_LIST_STORE(adw_combo_row_get_model(row));
+
+ g_list_store_remove_all(store);
manager = purple_media_manager_get();
devices = purple_media_manager_enumerate_elements(manager, type);
for (; devices; devices = g_list_delete_link(devices, devices)) {
PurpleMediaElementInfo *info = devices->data;
- GtkTreeIter iter;
- char *name, *id;
-
- name = purple_media_element_info_get_name(info);
- id = purple_media_element_info_get_id(info);
+ char *id;
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, PIDGIN_PREF_COMBO_TEXT, name,
- PIDGIN_PREF_COMBO_VALUE, id, -1);
+ id = purple_media_element_info_get_id(info);
+ if(purple_strequal(id, active)) {
+ /* The index will be for the *next* appended item. */
+ selected = g_list_model_get_n_items(G_LIST_MODEL(store));
+ }
+ g_free(id);
- g_free(name);
- g_free(id);
+ g_list_store_append(store, info);
+
g_object_unref(info);
}
+
+ adw_combo_row_set_selected(row, selected);
}
static GstElement *
@@ -435,66 +441,80 @@
}
static void
-bind_vv_dropdown(PidginPrefCombo *combo, PurpleMediaElementType element_type)
+vv_combo_row_set(GObject *obj, G_GNUC_UNUSED GParamSpec *pspec, gpointer data)
{
- const gchar *preference_key;
- GtkTreeModel *model;
+ const char *key = data;
+ PurpleMediaElementInfo *item = NULL;
+ char *id = NULL;
- preference_key = purple_media_type_to_preference_key(element_type);
- model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo->combo));
- populate_vv_device_menuitems(element_type, GTK_LIST_STORE(model));
-
- combo->type = PURPLE_PREF_STRING;
- combo->key = preference_key;
- pidgin_prefs_bind_dropdown(combo);
+ item = adw_combo_row_get_selected_item(ADW_COMBO_ROW(obj));
+ id = purple_media_element_info_get_id(item);
+ purple_prefs_set_string(key, id);
+ g_free(id);
}
static void
-bind_vv_frame(PidginVVPrefs *prefs, PidginPrefCombo *combo,
+bind_vv_combo(PidginVVPrefs *prefs, AdwComboRow *row,
PurpleMediaElementType type)
{
- bind_vv_dropdown(combo, type);
+ const char *pref_key = NULL;
+ const char *pref_value = NULL;
+
+ pref_key = purple_media_type_to_preference_key(type);
+ pref_value = purple_prefs_get_string(pref_key);
+
+ populate_vv_device_menuitems(row, type, pref_value);
- purple_prefs_connect_callback(combo->combo,
- purple_media_type_to_preference_key(type),
- vv_device_changed_cb, prefs);
- g_signal_connect_swapped(combo->combo, "destroy",
+ g_signal_connect(row, "notify::selected", G_CALLBACK(vv_combo_row_set),
+ (gpointer)pref_key);
+
+ purple_prefs_connect_callback(row, pref_key, vv_device_changed_cb, prefs);
+ g_signal_connect_swapped(row, "destroy",
G_CALLBACK(purple_prefs_disconnect_by_handle),
- combo->combo);
+ row);
- g_object_set_data(G_OBJECT(combo->combo), "vv_media_type",
- (gpointer)type);
- g_object_set_data(G_OBJECT(combo->combo), "vv_combo", combo);
+ g_object_set_data(G_OBJECT(row), "vv_media_type", GINT_TO_POINTER(type));
}
static void
device_list_changed_cb(G_GNUC_UNUSED PurpleMediaManager *manager,
- GtkWidget *widget)
+ gpointer data)
{
- PidginPrefCombo *combo;
+ AdwComboRow *row = data;
+ PurpleMediaElementInfo *original = NULL;
+ PurpleMediaElementInfo *selected = NULL;
PurpleMediaElementType media_type;
- const gchar *preference_key;
- guint signal_id;
- GtkTreeModel *model;
+ const char *pref_key = NULL;
+ const char *pref_value = NULL;
+
+ original = g_object_ref(adw_combo_row_get_selected_item(row));
- combo = g_object_get_data(G_OBJECT(widget), "vv_combo");
- media_type = (PurpleMediaElementType)GPOINTER_TO_INT(g_object_get_data(
- G_OBJECT(widget),
- "vv_media_type"));
- preference_key = purple_media_type_to_preference_key(media_type);
+ media_type = (PurpleMediaElementType)GPOINTER_TO_INT(
+ g_object_get_data(
+ G_OBJECT(row),
+ "vv_media_type"));
+ pref_key = purple_media_type_to_preference_key(media_type);
+ pref_value = purple_prefs_get_string(pref_key);
/* Block signals so pref doesn't get re-saved while changing UI. */
- signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX);
- g_signal_handlers_block_matched(combo->combo, G_SIGNAL_MATCH_ID, signal_id,
- 0, NULL, NULL, NULL);
+ g_signal_handlers_block_by_func(row, vv_combo_row_set, (gpointer)pref_key);
+
+ populate_vv_device_menuitems(row, media_type, pref_value);
+
+ g_signal_handlers_unblock_by_func(row, vv_combo_row_set,
+ (gpointer)pref_key);
- model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo->combo));
- populate_vv_device_menuitems(media_type, GTK_LIST_STORE(model));
- gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo->combo),
- purple_prefs_get_string(preference_key));
+ selected = adw_combo_row_get_selected_item(row);
+ if(original != selected) {
+ /* We blocked signals to prevent accidentally changing the selected
+ * element while the combo row repopulates, but now the original
+ * element is gone, so we need to push this change back to the pref. */
+ char *id = purple_media_element_info_get_id(selected);
+ purple_prefs_set_string(pref_key, id);
+ g_free(id);
+ }
- g_signal_handlers_unblock_matched(combo->combo, G_SIGNAL_MATCH_ID,
- signal_id, 0, NULL, NULL, NULL);
+ g_clear_object(&original);
}
/******************************************************************************
@@ -511,9 +531,9 @@
);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
- voice.input.combo);
+ voice.input);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
- voice.output.combo);
+ voice.output);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
voice.volume);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
@@ -533,9 +553,9 @@
toggle_voice_test_cb);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
- video.input.combo);
+ video.input);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
- video.output.combo);
+ video.output);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
video.frame);
gtk_widget_class_bind_template_child(widget_class, PidginVVPrefs,
@@ -553,31 +573,31 @@
manager = purple_media_manager_get();
- bind_vv_frame(prefs, &prefs->voice.input,
+ bind_vv_combo(prefs, prefs->voice.input,
PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SRC);
g_signal_connect_object(manager, "elements-changed::audiosrc",
G_CALLBACK(device_list_changed_cb),
- prefs->voice.input.combo, 0);
+ prefs->voice.input, 0);
- bind_vv_frame(prefs, &prefs->voice.output,
+ bind_vv_combo(prefs, prefs->voice.output,
PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SINK);
g_signal_connect_object(manager, "elements-changed::audiosink",
G_CALLBACK(device_list_changed_cb),
- prefs->voice.output.combo, 0);
+ prefs->voice.output, 0);
bind_voice_test(prefs);
- bind_vv_frame(prefs, &prefs->video.input,
+ bind_vv_combo(prefs, prefs->video.input,
PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SRC);
g_signal_connect_object(manager, "elements-changed::videosrc",
G_CALLBACK(device_list_changed_cb),
- prefs->video.input.combo, 0);
+ prefs->video.input, 0);
- bind_vv_frame(prefs, &prefs->video.output,
+ bind_vv_combo(prefs, prefs->video.output,
PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SINK);
g_signal_connect_object(manager, "elements-changed::videosink",
G_CALLBACK(device_list_changed_cb),
- prefs->video.output.combo, 0);
+ prefs->video.output, 0);
}
/******************************************************************************
--- a/pidgin/resources/Prefs/vv.ui Thu Mar 30 22:03:24 2023 -0500
+++ b/pidgin/resources/Prefs/vv.ui Thu Mar 30 22:30:46 2023 -0500
@@ -33,78 +33,51 @@
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
- <object class="GtkListStore" id="video.input.store">
- <columns>
- <!-- column-name text -->
- <column type="gchararray"/>
- <!-- column-name value -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkListStore" id="video.output.store">
- <columns>
- <!-- column-name text -->
- <column type="gchararray"/>
- <!-- column-name value -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkListStore" id="voice.input.store">
- <columns>
- <!-- column-name text -->
- <column type="gchararray"/>
- <!-- column-name value -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkListStore" id="voice.output.store">
- <columns>
- <!-- column-name text -->
- <column type="gchararray"/>
- <!-- column-name value -->
- <column type="gchararray"/>
- </columns>
+ <object class="GtkBuilderListItemFactory" id="element-info-factory">
+ <property name="bytes">
+<![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkListItem">
+ <property name="child">
+ <object class="GtkLabel">
+ <property name="xalign">0</property>
+ <binding name="label">
+ <lookup name="name" type="PurpleMediaElementInfo">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </property>
+ </template>
+</interface>
+]]>
+ </property>
</object>
<template class="PidginVVPrefs" parent="AdwPreferencesPage">
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="1">Audio</property>
<child>
- <object class="AdwActionRow">
- <property name="activatable-widget">voice.input.combo</property>
+ <object class="AdwComboRow" id="voice.input">
<property name="title" translatable="1" context="Input for Audio">Input Device</property>
- <child>
- <object class="GtkComboBox" id="voice.input.combo">
- <property name="id-column">1</property>
- <property name="model">voice.input.store</property>
- <property name="valign">center</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
+ <property name="factory">element-info-factory</property>
+ <property name="model">
+ <object class="GListStore">
+ <property name="item-type">PurpleMediaElementInfo</property>
</object>
- </child>
+ </property>
</object>
</child>
<child>
- <object class="AdwActionRow">
- <property name="activatable-widget">voice.output.combo</property>
+ <object class="AdwComboRow" id="voice.output">
<property name="title" translatable="1" context="Device for Audio Output">Output Device</property>
- <child>
- <object class="GtkComboBox" id="voice.output.combo">
- <property name="id-column">1</property>
- <property name="model">voice.output.store</property>
- <property name="valign">center</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
+ <property name="factory">element-info-factory</property>
+ <property name="model">
+ <object class="GListStore">
+ <property name="item-type">PurpleMediaElementInfo</property>
</object>
- </child>
+ </property>
</object>
</child>
<child>
@@ -188,43 +161,25 @@
<object class="AdwPreferencesGroup">
<property name="title" translatable="1">Video</property>
<child>
- <object class="AdwActionRow">
- <property name="activatable-widget">video.input.combo</property>
+ <object class="AdwComboRow" id="video.input">
<property name="title" translatable="1" context="Device for Video Input">Input Device</property>
- <child>
- <object class="GtkComboBox" id="video.input.combo">
- <property name="id-column">1</property>
- <property name="hexpand">1</property>
- <property name="model">video.input.store</property>
- <property name="valign">center</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
+ <property name="factory">element-info-factory</property>
+ <property name="model">
+ <object class="GListStore">
+ <property name="item-type">PurpleMediaElementInfo</property>
</object>
- </child>
+ </property>
</object>
</child>
<child>
- <object class="AdwActionRow">
- <property name="activatable-widget">video.output.combo</property>
+ <object class="AdwComboRow" id="video.output">
<property name="title" translatable="1" context="Device for Video Output">Output Device</property>
- <child>
- <object class="GtkComboBox" id="video.output.combo">
- <property name="hexpand">1</property>
- <property name="id-column">1</property>
- <property name="valign">center</property>
- <property name="model">video.output.store</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
+ <property name="factory">element-info-factory</property>
+ <property name="model">
+ <object class="GListStore">
+ <property name="item-type">PurpleMediaElementInfo</property>
</object>
- </child>
+ </property>
</object>
</child>
<child>