Move PidginAccountChooser to GtkDropDown

Sun, 30 Oct 2022 03:29:33 -0500

author
Elliott Sales de Andrade <quantum.analyst@gmail.com>
date
Sun, 30 Oct 2022 03:29:33 -0500
changeset 41864
6f490dec468f
parent 41863
0067a0ff5b74
child 41865
41e66d907bc9

Move PidginAccountChooser to GtkDropDown

The chooser connects to the default account manager automatically.
Additionally, re-parent the `GtkTreeModelFilter` subclasses to `GtkFilter`, and use them on the `filter` property.

This also means the previous `filter_func` that was moved to `GtkFilter` in /r/1995 are now used again.

Testing Done:
Opened most of the affected dialogs. Disabled XMPP account and saw that it was removed from all connected-only filtered choosers. Re-enabled account and it was back in the choosers.

Confirmed that only XMPP, and not Demo accounts appeared in the two XMPP-specific plugins.

Request API is still only compile-tested.

Reviewed at https://reviews.imfreedom.org/r/1992/

pidgin/gtkblist.c file | annotate | diff | comparison | revisions
pidgin/gtkprivacy.c file | annotate | diff | comparison | revisions
pidgin/gtkrequest.c file | annotate | diff | comparison | revisions
pidgin/meson.build file | annotate | diff | comparison | revisions
pidgin/pidginaccountchooser.c file | annotate | diff | comparison | revisions
pidgin/pidginaccountchooser.h file | annotate | diff | comparison | revisions
pidgin/pidginaccountfilterconnected.c file | annotate | diff | comparison | revisions
pidgin/pidginaccountfilterconnected.h file | annotate | diff | comparison | revisions
pidgin/pidginaccountfilterprotocol.c file | annotate | diff | comparison | revisions
pidgin/pidginaccountfilterprotocol.h file | annotate | diff | comparison | revisions
pidgin/pidginaccountstore.c file | annotate | diff | comparison | revisions
pidgin/pidginaccountstore.h file | annotate | diff | comparison | revisions
pidgin/pidginaddbuddydialog.c file | annotate | diff | comparison | revisions
pidgin/pidginaddchatdialog.c file | annotate | diff | comparison | revisions
pidgin/plugins/disco/resources/disco.ui file | annotate | diff | comparison | revisions
pidgin/plugins/xmppconsole/console.ui file | annotate | diff | comparison | revisions
pidgin/plugins/xmppconsole/xmppconsole.c file | annotate | diff | comparison | revisions
pidgin/resources/Accounts/chooser.ui file | annotate | diff | comparison | revisions
pidgin/resources/Dialogs/addbuddy.ui file | annotate | diff | comparison | revisions
pidgin/resources/Dialogs/addchat.ui file | annotate | diff | comparison | revisions
pidgin/resources/Privacy/dialog.ui file | annotate | diff | comparison | revisions
pidgin/resources/Roomlist/roomlist.ui file | annotate | diff | comparison | revisions
po/POTFILES.in file | annotate | diff | comparison | revisions
--- a/pidgin/gtkblist.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/gtkblist.c	Sun Oct 30 03:29:33 2022 -0500
@@ -37,7 +37,6 @@
 #include "gtkutils.h"
 #include "pidgin/pidginaccountchooser.h"
 #include "pidgin/pidginaccountfilterconnected.h"
-#include "pidgin/pidginaccountstore.h"
 #include "pidgin/pidginactiongroup.h"
 #include "pidgin/pidginaddbuddydialog.h"
 #include "pidgin/pidginaddchatdialog.h"
@@ -995,8 +994,8 @@
 	GtkWidget *hbox;
 	GtkWidget *vbox;
 	GtkWindow *blist_window;
-	GtkTreeModel *model = NULL, *filter = NULL;
-	GtkCustomFilter *custom_filter = NULL;
+	GtkEveryFilter *every = NULL;
+	GtkFilter *filter = NULL;
 	PidginBuddyList *gtkblist;
 
 	data->account = account;
@@ -1034,25 +1033,22 @@
 
 	data->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
-	model = GTK_TREE_MODEL(pidgin_account_store_new());
-	filter = pidgin_account_filter_connected_new(model, NULL);
-	g_object_unref(G_OBJECT(model));
 	data->account_menu = pidgin_account_chooser_new();
-	gtk_combo_box_set_model(GTK_COMBO_BOX(data->account_menu), filter);
-	g_object_unref(G_OBJECT(filter));
+	every = gtk_every_filter_new();
+	filter = pidgin_account_filter_connected_new();
+	gtk_multi_filter_append(GTK_MULTI_FILTER(every), filter);
+	filter = GTK_FILTER(gtk_custom_filter_new(filter_func, NULL, NULL));
+	gtk_multi_filter_append(GTK_MULTI_FILTER(every), filter);
+	pidgin_account_chooser_set_filter(
+	        PIDGIN_ACCOUNT_CHOOSER(data->account_menu),
+	        GTK_FILTER(every));
+	g_object_unref(every);
+
 	if(PURPLE_IS_ACCOUNT(account)) {
 		pidgin_account_chooser_set_selected(PIDGIN_ACCOUNT_CHOOSER(
 			data->account_menu), account);
-	} else {
-		gtk_combo_box_set_active(GTK_COMBO_BOX(data->account_menu), 0);
 	}
 
-	custom_filter = gtk_custom_filter_new(filter_func, NULL, NULL);
-	pidgin_account_chooser_set_filter(
-	        PIDGIN_ACCOUNT_CHOOSER(data->account_menu),
-	        GTK_FILTER(custom_filter));
-	g_object_unref(custom_filter);
-
 	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("A_ccount"), data->sg, data->account_menu, TRUE, NULL);
 	g_signal_connect(data->account_menu, "notify::account",
 	                 G_CALLBACK(callback_func), data);
@@ -1162,7 +1158,9 @@
 	PurpleAccount *account = pidgin_account_chooser_get_selected(chooser);
 
 	g_return_if_fail(data != NULL);
-	g_return_if_fail(account != NULL);
+	if(account == NULL) {
+		return;
+	}
 
 	if (purple_strequal(purple_account_get_protocol_id(data->rq_data.account),
 	                    purple_account_get_protocol_id(account)))
--- a/pidgin/gtkprivacy.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/gtkprivacy.c	Sun Oct 30 03:29:33 2022 -0500
@@ -28,7 +28,6 @@
 #include "gtkprivacy.h"
 #include "gtkutils.h"
 #include "pidginaccountchooser.h"
-#include "pidginaccountstore.h"
 
 #define PIDGIN_TYPE_PRIVACY_DIALOG (pidgin_privacy_dialog_get_type())
 G_DECLARE_FINAL_TYPE(PidginPrivacyDialog, pidgin_privacy_dialog, PIDGIN,
--- a/pidgin/gtkrequest.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/gtkrequest.c	Sun Oct 30 03:29:33 2022 -0500
@@ -30,7 +30,6 @@
 #include "gtkutils.h"
 #include "pidginaccountchooser.h"
 #include "pidginaccountfilterconnected.h"
-#include "pidginaccountstore.h"
 #include "pidgincore.h"
 #include "pidgindialog.h"
 
@@ -1401,40 +1400,32 @@
 {
 	GtkWidget *widget;
 	PurpleAccount *account;
-	GtkCustomFilter *custom_filter = NULL;
+	GtkFilter *filter = NULL;
 
 	widget = pidgin_account_chooser_new();
 	account  = purple_request_field_account_get_default_value(field);
 
-	if(purple_request_field_account_get_show_all(field)) {
-		GtkListStore *store = pidgin_account_store_new();
-
-		gtk_combo_box_set_model(GTK_COMBO_BOX(widget), GTK_TREE_MODEL(store));
-
-		g_object_unref(G_OBJECT(store));
-	} else {
-		GtkListStore *store = NULL;
-		GtkTreeModel *filter = NULL;
-
-		store = pidgin_account_store_new();
-		filter = pidgin_account_filter_connected_new(GTK_TREE_MODEL(store),
-		                                             NULL);
-		g_object_unref(G_OBJECT(store));
-
-		gtk_combo_box_set_model(GTK_COMBO_BOX(widget), GTK_TREE_MODEL(filter));
-		g_object_unref(G_OBJECT(filter));
+	filter = GTK_FILTER(gtk_custom_filter_new(
+	        field_custom_account_filter_cb,
+	        purple_request_field_account_get_filter(field),
+	        NULL));
+
+	if(!purple_request_field_account_get_show_all(field)) {
+		GtkEveryFilter *every = NULL;
+
+		every = gtk_every_filter_new();
+		gtk_multi_filter_append(GTK_MULTI_FILTER(every), filter);
+
+		filter = pidgin_account_filter_connected_new();
+		gtk_multi_filter_append(GTK_MULTI_FILTER(every), filter);
+
+		filter = GTK_FILTER(every);
 	}
 
 	pidgin_account_chooser_set_selected(PIDGIN_ACCOUNT_CHOOSER(widget),
 	                                    account);
-	custom_filter = gtk_custom_filter_new(
-	        field_custom_account_filter_cb,
-	        purple_request_field_account_get_filter(field),
-	        NULL);
-	pidgin_account_chooser_set_filter(
-	        PIDGIN_ACCOUNT_CHOOSER(widget),
-	        GTK_FILTER(custom_filter));
-	g_object_unref(custom_filter);
+	pidgin_account_chooser_set_filter(PIDGIN_ACCOUNT_CHOOSER(widget), filter);
+	g_object_unref(filter);
 
 	g_signal_connect(widget, "notify::account", G_CALLBACK(field_account_cb),
 	                 field);
--- a/pidgin/meson.build	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/meson.build	Sun Oct 30 03:29:33 2022 -0500
@@ -28,7 +28,6 @@
 	'pidginaccountmanager.c',
 	'pidginaccountsdisabledmenu.c',
 	'pidginaccountsenabledmenu.c',
-	'pidginaccountstore.c',
 	'pidginactiongroup.c',
 	'pidginaddbuddydialog.c',
 	'pidginaddchatdialog.c',
@@ -97,7 +96,6 @@
 	'pidginaccountmanager.h',
 	'pidginaccountsdisabledmenu.h',
 	'pidginaccountsenabledmenu.h',
-	'pidginaccountstore.h',
 	'pidginactiongroup.h',
 	'pidginaddbuddydialog.h',
 	'pidginaddchatdialog.h',
@@ -149,7 +147,6 @@
 	'gtkblist.h',
 	'gtkconv.h',
 	'gtkutils.h',
-	'pidginaccountstore.h',
 ]
 
 pidgin_SOURCES = [
--- a/pidgin/pidginaccountchooser.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaccountchooser.c	Sun Oct 30 03:29:33 2022 -0500
@@ -20,16 +20,17 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301 USA
  */
+#include <glib/gi18n-lib.h>
+
 #include <gtk/gtk.h>
 
 #include "pidginaccountchooser.h"
 
-#include "pidginaccountstore.h"
+struct _PidginAccountChooser {
+	AdwBin parent;
 
-struct _PidginAccountChooser {
-	GtkComboBox parent;
-
-	GtkFilter *filter;
+	GtkDropDown *chooser;
+	GtkFilterListModel *filter;
 };
 
 enum
@@ -45,15 +46,60 @@
 /******************************************************************************
  * Callbacks
  *****************************************************************************/
+static char *
+pidgin_account_chooser_icon_name_cb(G_GNUC_UNUSED GObject *self,
+                                    PurpleAccount *account,
+                                    G_GNUC_UNUSED gpointer data)
+{
+	const char *icon_name = NULL;
+
+	if(PURPLE_IS_ACCOUNT(account)) {
+		PurpleProtocol *protocol = purple_account_get_protocol(account);
+		icon_name = purple_protocol_get_icon_name(protocol);
+	}
+
+	return g_strdup(icon_name);
+}
+
+static char *
+pidgin_account_chooser_label_cb(G_GNUC_UNUSED GObject *self,
+                                PurpleAccount *account,
+                                G_GNUC_UNUSED gpointer data)
+{
+	gchar *markup = NULL;
+	const gchar *alias = NULL;
+
+	if(!PURPLE_IS_ACCOUNT(account)) {
+		return NULL;
+	}
+
+	alias = purple_account_get_private_alias(account);
+	if(alias != NULL) {
+		markup = g_strdup_printf(_("%s (%s) (%s)"),
+		                         purple_account_get_username(account),
+		                         alias,
+		                         purple_account_get_protocol_name(account));
+	} else {
+		markup = g_strdup_printf(_("%s (%s)"),
+		                         purple_account_get_username(account),
+		                         purple_account_get_protocol_name(account));
+	}
+
+	return markup;
+}
+
 static void
-pidgin_account_chooser_changed_cb(GtkComboBox *widget, gpointer user_data) {
-	g_object_notify_by_pspec(G_OBJECT(widget), properties[PROP_ACCOUNT]);
+pidgin_account_chooser_changed_cb(G_GNUC_UNUSED GObject *obj,
+                                  G_GNUC_UNUSED GParamSpec *pspec,
+                                  gpointer data)
+{
+	g_object_notify_by_pspec(G_OBJECT(data), properties[PROP_ACCOUNT]);
 }
 
 /******************************************************************************
  * GObject implementation
  *****************************************************************************/
-G_DEFINE_TYPE(PidginAccountChooser, pidgin_account_chooser, GTK_TYPE_COMBO_BOX)
+G_DEFINE_TYPE(PidginAccountChooser, pidgin_account_chooser, ADW_TYPE_BIN)
 
 static void
 pidgin_account_chooser_get_property(GObject *object, guint prop_id,
@@ -121,15 +167,28 @@
 	/* Widget template */
 	gtk_widget_class_set_template_from_resource(
 	        widget_class, "/im/pidgin/Pidgin3/Accounts/chooser.ui");
+
+	gtk_widget_class_bind_template_child(widget_class, PidginAccountChooser,
+	                                     chooser);
+	gtk_widget_class_bind_template_child(widget_class, PidginAccountChooser,
+	                                     filter);
+
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        pidgin_account_chooser_icon_name_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        pidgin_account_chooser_label_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        pidgin_account_chooser_changed_cb);
 }
 
 static void
 pidgin_account_chooser_init(PidginAccountChooser *chooser) {
+	GListModel *model = NULL;
+
 	gtk_widget_init_template(GTK_WIDGET(chooser));
 
-	/* this callback emits the notify for the account property */
-	g_signal_connect(chooser, "changed",
-	                 G_CALLBACK(pidgin_account_chooser_changed_cb), NULL);
+	model = purple_account_manager_get_default_as_model();
+	gtk_filter_list_model_set_model(chooser->filter, model);
 }
 
 /******************************************************************************
@@ -148,7 +207,7 @@
 pidgin_account_chooser_get_filter(PidginAccountChooser *chooser) {
 	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser), NULL);
 
-	return chooser->filter;
+	return gtk_filter_list_model_get_filter(chooser->filter);
 }
 
 void
@@ -157,56 +216,44 @@
 {
 	g_return_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser));
 
-	if(g_set_object(&chooser->filter, filter)) {
-		g_object_notify_by_pspec(G_OBJECT(chooser), properties[PROP_FILTER]);
-	}
+	gtk_filter_list_model_set_filter(chooser->filter, filter);
+	g_object_notify_by_pspec(G_OBJECT(chooser), properties[PROP_FILTER]);
 }
 
 PurpleAccount *
 pidgin_account_chooser_get_selected(PidginAccountChooser *chooser) {
-	GtkTreeIter iter;
-	gpointer account = NULL;
-
 	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser), NULL);
 
-	if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(chooser), &iter)) {
-		GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(chooser));
-		gtk_tree_model_get(model, &iter,
-		                   PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT, &account, -1);
-	}
-
-	return account;
+	return gtk_drop_down_get_selected_item(chooser->chooser);
 }
 
 void
 pidgin_account_chooser_set_selected(PidginAccountChooser *chooser,
                                     PurpleAccount *account)
 {
-	GtkTreeModel *model = NULL;
-	GtkTreeIter iter;
-	PurpleAccount *acc = NULL;
+	GListModel *model = NULL;
+	guint n_items = 0;
 
 	g_return_if_fail(PIDGIN_IS_ACCOUNT_CHOOSER(chooser));
 
-	model = gtk_combo_box_get_model(GTK_COMBO_BOX(chooser));
-	g_return_if_fail(GTK_IS_TREE_MODEL(model));
+	model = gtk_drop_down_get_model(chooser->chooser);
+	g_return_if_fail(G_IS_LIST_MODEL(model));
+
+	n_items = g_list_model_get_n_items(model);
+	for(guint position = 0; position < n_items; position++) {
+		PurpleAccount *acc = g_list_model_get_item(model, position);
 
-	if(gtk_tree_model_get_iter_first(model, &iter)) {
-		do {
-			gtk_tree_model_get(model, &iter,
-			                   PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT, &acc, -1);
-			if(acc == account) {
-				/* NOTE: Property notification occurs in 'changed' signal
-				 * callback.
-				 */
-				gtk_combo_box_set_active_iter(GTK_COMBO_BOX(chooser), &iter);
+		if(acc == account) {
+			/* NOTE: Property notification occurs in 'changed' signal
+			 * callback.
+			 */
+			gtk_drop_down_set_selected(chooser->chooser, position);
 
-				g_object_unref(G_OBJECT(acc));
+			g_object_unref(acc);
 
-				return;
-			}
-			g_object_unref(G_OBJECT(acc));
-		} while(gtk_tree_model_iter_next(model, &iter));
+			return;
+		}
+
+		g_object_unref(acc);
 	}
 }
-
--- a/pidgin/pidginaccountchooser.h	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaccountchooser.h	Sun Oct 30 03:29:33 2022 -0500
@@ -27,6 +27,7 @@
 #define PIDGIN_ACCOUNT_CHOOSER_H
 
 #include <gtk/gtk.h>
+#include <adwaita.h>
 
 #include <purple.h>
 
@@ -35,7 +36,7 @@
 #define PIDGIN_TYPE_ACCOUNT_CHOOSER (pidgin_account_chooser_get_type())
 
 G_DECLARE_FINAL_TYPE(PidginAccountChooser, pidgin_account_chooser, PIDGIN,
-                     ACCOUNT_CHOOSER, GtkComboBox)
+                     ACCOUNT_CHOOSER, AdwBin)
 
 /**
  * pidgin_account_chooser_new:
--- a/pidgin/pidginaccountfilterconnected.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaccountfilterconnected.c	Sun Oct 30 03:29:33 2022 -0500
@@ -22,12 +22,10 @@
 
 #include "pidgin/pidginaccountfilterconnected.h"
 
-#include "pidgin/pidginaccountstore.h"
-
 #include <purple.h>
 
 struct _PidginAccountFilterConnected {
-	GtkTreeModelFilter parent;
+	GtkFilter parent;
 };
 
 /******************************************************************************
@@ -38,36 +36,35 @@
                                         gpointer data)
 {
 	PidginAccountFilterConnected *filter = NULL;
+	PurpleConnectionState state;
 
 	filter = PIDGIN_ACCOUNT_FILTER_CONNECTED(data);
 
-	gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(filter));
+	state = purple_connection_get_state(connection);
+	gtk_filter_changed(GTK_FILTER(filter),
+	                   (state == PURPLE_CONNECTION_STATE_CONNECTED) ?
+	                   GTK_FILTER_CHANGE_LESS_STRICT :
+	                   GTK_FILTER_CHANGE_MORE_STRICT);
 }
 
 /******************************************************************************
- * GObject Implementation
+ * GtkFilter Implementation
  *****************************************************************************/
+static GtkFilterMatch
+pidgin_account_filter_connected_get_strictness(G_GNUC_UNUSED GtkFilter *self) {
+	return GTK_FILTER_MATCH_SOME;
+}
+
 static gboolean
-pidgin_account_filter_connected_func(GtkTreeModel *model, GtkTreeIter *iter,
-                                     gpointer data)
+pidgin_account_filter_connected_match(G_GNUC_UNUSED GtkFilter *self,
+                                      gpointer item)
 {
-	PurpleAccount *account = NULL;
 	gboolean ret = FALSE;
 
-	g_return_val_if_fail(GTK_IS_TREE_MODEL(model), FALSE);
-	g_return_val_if_fail(iter != NULL, FALSE);
-
-	gtk_tree_model_get(model, iter, PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT,
-	                   &account, -1);
-
-	if(!PURPLE_IS_ACCOUNT(account)) {
-		return FALSE;
+	if(PURPLE_IS_ACCOUNT(item)) {
+		ret = purple_account_is_connected(PURPLE_ACCOUNT(item));
 	}
 
-	ret = purple_account_is_connected(account);
-
-	g_object_unref(G_OBJECT(account));
-
 	return ret;
 }
 
@@ -75,16 +72,12 @@
  * GObject Implementation
  *****************************************************************************/
 G_DEFINE_TYPE(PidginAccountFilterConnected, pidgin_account_filter_connected,
-              GTK_TYPE_TREE_MODEL_FILTER)
+              GTK_TYPE_FILTER)
 
 static void
 pidgin_account_filter_connected_init(PidginAccountFilterConnected *filter) {
 	gpointer connections_handle = NULL;
 
-	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter),
-	                                       pidgin_account_filter_connected_func,
-	                                       NULL, NULL);
-
 	/* we connect to the connections signals to force a refresh of the filter */
 	connections_handle = purple_connections_get_handle();
 	purple_signal_connect(connections_handle, "signed-on", filter,
@@ -105,19 +98,19 @@
 static void
 pidgin_account_filter_connected_class_init(PidginAccountFilterConnectedClass *klass) {
 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GtkFilterClass *filter_class = GTK_FILTER_CLASS(klass);
 
 	obj_class->finalize = pidgin_account_filter_connected_finalize;
+
+	filter_class->get_strictness = pidgin_account_filter_connected_get_strictness;
+	filter_class->match = pidgin_account_filter_connected_match;
 }
 
 /******************************************************************************
  * API
  *****************************************************************************/
-GtkTreeModel *
-pidgin_account_filter_connected_new(GtkTreeModel *child_model,
-                                    GtkTreePath *root)
+GtkFilter *
+pidgin_account_filter_connected_new(void)
 {
-	g_return_val_if_fail(GTK_IS_TREE_MODEL(child_model), NULL);
-
-	return g_object_new(PIDGIN_TYPE_ACCOUNT_FILTER_CONNECTED, "child-model",
-	                    child_model, "virtual-root", root, NULL);
+	return g_object_new(PIDGIN_TYPE_ACCOUNT_FILTER_CONNECTED, NULL);
 }
--- a/pidgin/pidginaccountfilterconnected.h	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaccountfilterconnected.h	Sun Oct 30 03:29:33 2022 -0500
@@ -34,9 +34,10 @@
 /**
  * PidginAccountFilterConnected:
  *
- * #PidginAccountFilterConnected is a #GtkTreeModelFilter that will only show
- * accounts that are connected.  It's intended to be used with
- * #PidginAccountStore.
+ * #PidginAccountFilterConnected is a [class@Gtk.Filter] that will only show
+ * accounts that are connected. It's intended to be used with
+ * [class@Pidgin.AccountChooser] or a [iface@Gio.ListModel] that contains
+ * [class@Purple.Account].
  *
  * Since: 3.0.0
  */
@@ -44,21 +45,19 @@
 #define PIDGIN_TYPE_ACCOUNT_FILTER_CONNECTED pidgin_account_filter_connected_get_type()
 G_DECLARE_FINAL_TYPE(PidginAccountFilterConnected,
                      pidgin_account_filter_connected, PIDGIN,
-                     ACCOUNT_FILTER_CONNECTED, GtkTreeModelFilter)
+                     ACCOUNT_FILTER_CONNECTED, GtkFilter)
 
 /**
  * pidgin_account_filter_connected_new:
- * @child_model: The #GtkTreeModel instance to filter.
- * @root: The #GtkTreePath to start at or %NULL.
  *
  * Creates a new #PidginAccountFilterConnected that should be used to filter
- * only online accounts in a #PidginAccountStore.
+ * only online accounts.
  *
  * Returns: (transfer full): The new #PidginAccountFilterConnected instance.
  *
  * Since: 3.0.0
  */
-GtkTreeModel *pidgin_account_filter_connected_new(GtkTreeModel *child_model, GtkTreePath *root);
+GtkFilter *pidgin_account_filter_connected_new(void);
 
 G_END_DECLS
 
--- a/pidgin/pidginaccountfilterprotocol.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaccountfilterprotocol.c	Sun Oct 30 03:29:33 2022 -0500
@@ -22,12 +22,10 @@
 
 #include "pidgin/pidginaccountfilterprotocol.h"
 
-#include "pidgin/pidginaccountstore.h"
-
 #include <purple.h>
 
 struct _PidginAccountFilterProtocol {
-	GtkTreeModelFilter parent;
+	GtkFilter parent;
 
 	gchar *protocol_id;
 };
@@ -48,34 +46,36 @@
 {
 	g_free(filter->protocol_id);
 	filter->protocol_id = g_strdup(protocol_id);
+
+	gtk_filter_changed(GTK_FILTER(filter), GTK_FILTER_CHANGE_DIFFERENT);
+}
+
+/******************************************************************************
+ * GtkFilter Implementation
+ *****************************************************************************/
+static GtkFilterMatch
+pidgin_account_filter_protocol_get_strictness(G_GNUC_UNUSED GtkFilter *self) {
+	return GTK_FILTER_MATCH_SOME;
 }
 
 static gboolean
-pidgin_account_filter_protocol_func(GtkTreeModel *model, GtkTreeIter *iter,
-                                    gpointer data)
+pidgin_account_filter_protocol_match(G_GNUC_UNUSED GtkFilter *self,
+                                     gpointer item)
 {
-	PidginAccountFilterProtocol *filter = NULL;
-	PurpleAccount *account = NULL;
 	gboolean ret = FALSE;
 
-	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_FILTER_PROTOCOL(data), FALSE);
-	g_return_val_if_fail(GTK_IS_TREE_MODEL(model), FALSE);
-	g_return_val_if_fail(iter != NULL, FALSE);
+	g_return_val_if_fail(PIDGIN_IS_ACCOUNT_FILTER_PROTOCOL(self), FALSE);
 
-	filter = PIDGIN_ACCOUNT_FILTER_PROTOCOL(data);
-
-	gtk_tree_model_get(model, iter, PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT,
-	                   &account, -1);
+	if(PURPLE_IS_ACCOUNT(item)) {
+		PidginAccountFilterProtocol *filter = NULL;
+		PurpleAccount *account = NULL;
 
-	if(!PURPLE_IS_ACCOUNT(account)) {
-		return FALSE;
+		filter = PIDGIN_ACCOUNT_FILTER_PROTOCOL(self);
+		account = PURPLE_ACCOUNT(item);
+		ret = purple_strequal(purple_account_get_protocol_id(account),
+		                      filter->protocol_id);
 	}
 
-	ret = purple_strequal(purple_account_get_protocol_id(account),
-	                      filter->protocol_id);
-
-	g_object_unref(G_OBJECT(account));
-
 	return ret;
 }
 
@@ -83,7 +83,7 @@
  * GObject Implementation
  *****************************************************************************/
 G_DEFINE_TYPE(PidginAccountFilterProtocol, pidgin_account_filter_protocol,
-              GTK_TYPE_TREE_MODEL_FILTER)
+              GTK_TYPE_FILTER)
 
 static void
 pidgin_account_filter_protocol_get_property(GObject *obj, guint param_id,
@@ -130,20 +130,22 @@
 }
 
 static void
-pidgin_account_filter_protocol_init(PidginAccountFilterProtocol *filter) {
-	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filter),
-	                                       pidgin_account_filter_protocol_func,
-	                                       filter, NULL);
+pidgin_account_filter_protocol_init(G_GNUC_UNUSED PidginAccountFilterProtocol *filter)
+{
 }
 
 static void
 pidgin_account_filter_protocol_class_init(PidginAccountFilterProtocolClass *klass) {
 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GtkFilterClass *filter_class = GTK_FILTER_CLASS(klass);
 
 	obj_class->get_property = pidgin_account_filter_protocol_get_property;
 	obj_class->set_property = pidgin_account_filter_protocol_set_property;
 	obj_class->finalize = pidgin_account_filter_protocol_finalize;
 
+	filter_class->get_strictness = pidgin_account_filter_protocol_get_strictness;
+	filter_class->match = pidgin_account_filter_protocol_match;
+
 	/**
 	 * PidginAccountFilterProtocol:protocol-id:
 	 *
@@ -160,18 +162,11 @@
 /******************************************************************************
  * API
  *****************************************************************************/
-GtkTreeModel *
-pidgin_account_filter_protocol_new(const gchar *protocol_id,
-                                   GtkTreeModel *child_model,
-                                   GtkTreePath *root)
-{
-	g_return_val_if_fail(GTK_IS_TREE_MODEL(child_model), NULL);
-
+GtkFilter *
+pidgin_account_filter_protocol_new(const gchar *protocol_id) {
 	return g_object_new(
 		PIDGIN_TYPE_ACCOUNT_FILTER_PROTOCOL,
 		"protocol-id", protocol_id,
-		"child-model", child_model,
-		"virtual-root", root,
 		NULL);
 }
 
--- a/pidgin/pidginaccountfilterprotocol.h	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaccountfilterprotocol.h	Sun Oct 30 03:29:33 2022 -0500
@@ -34,9 +34,10 @@
 /**
  * PidginAccountFilterProtocol:
  *
- * #PidginAccountFilterProtocol is a #GtkTreeModelFilter that will only show
+ * #PidginAccountFilterProtocol is a [class@Gtk.Filter] that will only show
  * accounts for the given protocol.  It's intended to be used with
- * #PidginAccountStore.
+ * [class@Pidgin.AccountChooser] or a [iface@Gio.ListModel] that contains
+ * [class@Purple.Account].
  *
  * Since: 3.0.0
  */
@@ -44,24 +45,20 @@
 #define PIDGIN_TYPE_ACCOUNT_FILTER_PROTOCOL pidgin_account_filter_protocol_get_type()
 G_DECLARE_FINAL_TYPE(PidginAccountFilterProtocol,
                      pidgin_account_filter_protocol, PIDGIN,
-                     ACCOUNT_FILTER_PROTOCOL, GtkTreeModelFilter)
+                     ACCOUNT_FILTER_PROTOCOL, GtkFilter)
 
 /**
  * pidgin_account_filter_protocol_new:
  * @protocol_id: The ID of the protocol to filter for.
- * @child_model: The #GtkTreeModel that should be filtered.
- * @root: The root path that should be filtered.
  *
  * Creates a new #PidginAccountFilterProtocol that should be used to filter
- * only online accounts in a #PidginAccountStore.
- *
- * See gtk_tree_model_filter_new() for more information.
+ * only protocols with the given @protocol_id.
  *
  * Returns: (transfer full): The new #PidginAccountFilterProtocol instance.
  *
  * Since: 3.0.0
  */
-GtkTreeModel *pidgin_account_filter_protocol_new(const gchar *protocol_id, GtkTreeModel *child_model, GtkTreePath *root);
+GtkFilter *pidgin_account_filter_protocol_new(const gchar *protocol_id);
 
 /**
  * pidgin_account_filter_protocol_get_protocol_id:
--- a/pidgin/pidginaccountstore.c	Sat Oct 29 02:05:16 2022 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/*
- * Pidgin - Internet Messenger
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Pidgin is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program 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, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <glib/gi18n-lib.h>
-
-#include "pidgin/pidginaccountstore.h"
-
-#include "gtkutils.h"
-
-struct _PidginAccountStore {
-	GtkListStore parent;
-};
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-pidgin_account_store_add_account(PidginAccountStore *store,
-                                 PurpleAccount *account)
-{
-	PurpleProtocol *protocol = NULL;
-	GtkTreeIter iter;
-	gchar *markup = NULL;
-	const gchar *alias = NULL, *icon_name = NULL;
-
-	protocol = purple_account_get_protocol(account);
-	icon_name = purple_protocol_get_icon_name(protocol);
-
-	alias = purple_account_get_private_alias(account);
-	if(alias != NULL) {
-		markup = g_strdup_printf(_("%s (%s) (%s)"),
-		                         purple_account_get_username(account),
-		                         alias,
-		                         purple_account_get_protocol_name(account));
-	} else {
-		markup = g_strdup_printf(_("%s (%s)"),
-		                         purple_account_get_username(account),
-		                         purple_account_get_protocol_name(account));
-	}
-
-	gtk_list_store_append(GTK_LIST_STORE(store), &iter);
-	gtk_list_store_set(
-		GTK_LIST_STORE(store),
-		&iter,
-		PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT, account,
-		PIDGIN_ACCOUNT_STORE_COLUMN_MARKUP, markup,
-		PIDGIN_ACCOUNT_STORE_COLUMN_ICON_NAME, icon_name,
-		-1
-	);
-
-	g_free(markup);
-}
-
-static void
-pidgin_account_store_add_account_helper(PurpleAccount *account, gpointer data) {
-	if(PURPLE_IS_ACCOUNT(account)) {
-		pidgin_account_store_add_account(PIDGIN_ACCOUNT_STORE(data),
-		                                 PURPLE_ACCOUNT(account));
-	}
-}
-
-static void
-pidgin_account_store_remove_account(PidginAccountStore *store,
-                                    PurpleAccount *account)
-{
-	GtkTreeIter iter;
-
-	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) == FALSE) {
-		purple_debug_warning("account-store",
-		                     "account %s was removed but not in the store",
-		                     purple_account_get_username(account));
-		return;
-	}
-
-	/* walk through the store and look for the account to remove */
-	do {
-		PurpleAccount *found = NULL;
-
-		gtk_tree_model_get(
-			GTK_TREE_MODEL(store),
-			&iter,
-			PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT, &found,
-			-1
-		);
-
-		if(found == account) {
-			g_object_unref(G_OBJECT(found));
-
-			gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
-
-			return;
-		}
-	} while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
-}
-
-/******************************************************************************
- * Callbacks
- *****************************************************************************/
-static void
-pidgin_account_store_account_added_cb(G_GNUC_UNUSED PurpleAccountManager *manager,
-                                      PurpleAccount *account,
-                                      gpointer data)
-{
-	pidgin_account_store_add_account(PIDGIN_ACCOUNT_STORE(data), account);
-}
-
-static void
-pidgin_account_store_account_removed_cb(G_GNUC_UNUSED PurpleAccountManager *manager,
-                                        PurpleAccount *account,
-                                        gpointer data)
-{
-	pidgin_account_store_remove_account(PIDGIN_ACCOUNT_STORE(data), account);
-}
-
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-G_DEFINE_TYPE(PidginAccountStore, pidgin_account_store, GTK_TYPE_LIST_STORE)
-
-static void
-pidgin_account_store_init(PidginAccountStore *store) {
-	PurpleAccountManager *manager = NULL;
-	GType types[PIDGIN_ACCOUNT_STORE_N_COLUMNS] = {
-		PURPLE_TYPE_ACCOUNT,
-		G_TYPE_STRING,
-		G_TYPE_STRING,
-	};
-
-	gtk_list_store_set_column_types(
-		GTK_LIST_STORE(store),
-		PIDGIN_ACCOUNT_STORE_N_COLUMNS,
-		types
-	);
-
-	/* add the known accounts */
-	manager = purple_account_manager_get_default();
-	purple_account_manager_foreach(manager,
-	                               pidgin_account_store_add_account_helper,
-	                               store);
-
-	/* add the signal handlers to dynamically add/remove accounts */
-	g_signal_connect_object(manager, "added",
-	                        G_CALLBACK(pidgin_account_store_account_added_cb),
-	                        store, 0);
-	g_signal_connect_object(manager, "removed",
-	                        G_CALLBACK(pidgin_account_store_account_removed_cb),
-	                        store, 0);
-}
-
-static void
-pidgin_account_store_finalize(GObject *obj) {
-	purple_signals_disconnect_by_handle(obj);
-
-	G_OBJECT_CLASS(pidgin_account_store_parent_class)->finalize(obj);
-}
-
-static void
-pidgin_account_store_class_init(PidginAccountStoreClass *klass) {
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->finalize = pidgin_account_store_finalize;
-}
-
-/******************************************************************************
- * API
- *****************************************************************************/
-GtkListStore *
-pidgin_account_store_new(void) {
-	return GTK_LIST_STORE(g_object_new(PIDGIN_TYPE_ACCOUNT_STORE, NULL));
-}
--- a/pidgin/pidginaccountstore.h	Sat Oct 29 02:05:16 2022 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Pidgin - Internet Messenger
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Pidgin is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program 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, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION)
-# error "only <pidgin.h> may be included directly"
-#endif
-
-#ifndef PIDGIN_ACCOUNT_STORE_H
-#define PIDGIN_ACCOUNT_STORE_H
-
-#include <gtk/gtk.h>
-
-#include <purple.h>
-
-/**
- * PidginAccountStore:
- *
- * #PidginAccountStore is a #GtkListStore that automatically keeps track of
- * what accounts are currently available in libpurple.  It's intended to be
- * used any time that you need to present an account selection to the user.
- *
- * Since: 3.0.0
- */
-
-/**
- * PidginAccountStoreColumn:
- * @PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT: This column holds a reference to the
- *                                       #PurpleAccount.
- * @PIDGIN_ACCOUNT_STORE_COLUMN_MARKUP: This column holds a pango markup to
- *                                      display the account to the user.
- * @PIDGIN_ACCOUNT_STORE_COLUMN_ICON: This column holds an icon in a #GdkPixbuf
- *                                    for the account.
- *
- * Constants for accessing columns in a #PidginAccountStore.
- *
- * Since: 3.0.0
- */
-typedef enum {
-	PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT,
-	PIDGIN_ACCOUNT_STORE_COLUMN_MARKUP,
-	PIDGIN_ACCOUNT_STORE_COLUMN_ICON_NAME,
-	/*< private >*/
-	PIDGIN_ACCOUNT_STORE_N_COLUMNS,
-} PidginAccountStoreColumn;
-
-G_BEGIN_DECLS
-
-#define PIDGIN_TYPE_ACCOUNT_STORE pidgin_account_store_get_type()
-G_DECLARE_FINAL_TYPE(PidginAccountStore, pidgin_account_store, PIDGIN,
-                     ACCOUNT_STORE, GtkListStore)
-
-/**
- * pidgin_account_store_new:
- *
- * Creates a new #PidginAccountStore that can be used anywhere a #GtkListStore
- * can be used.
- *
- * Returns: (transfer full): The new #PidginAccountStore instance.
- *
- * Since: 3.0.0
- */
-GtkListStore *pidgin_account_store_new(void);
-
-/**
- * pidgin_account_store_filter_connected:
- * @model: The #GtkTreeModel that's being filtered.
- * @iter: The #GtkTreeIter to check.
- * @data: Userdata passed to gtk_tree_model_filter_set_visible_func().
- *
- * pidgin_account_store_filter_connected() is a #GtkTreeModelFilterVisibleFunc
- * that can be set on a #GtkTreeModelFilter via
- * gtk_tree_model_filter_set_visible_func(), to only show accounts that are
- * currently connected.
- *
- * Returns: %TRUE if the account will be displayed, %FALSE otherwise.
- */
-gboolean pidgin_account_store_filter_connected(GtkTreeModel *model, GtkTreeIter *iter, gpointer data);
-
-G_END_DECLS
-
-#endif /* PIDGIN_ACCOUNT_STORE_H */
--- a/pidgin/pidginaddbuddydialog.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaddbuddydialog.c	Sun Oct 30 03:29:33 2022 -0500
@@ -26,13 +26,12 @@
 
 #include "gtkaccount.h"
 #include "pidginaccountchooser.h"
-#include "pidginaccountstore.h"
 #include "pidgincore.h"
 
 struct _PidginAddBuddyDialog {
 	GtkDialog parent;
 
-	GtkTreeModel *filter;
+	GtkCustomFilter *filter;
 
 	GtkWidget *account;
 	GtkWidget *username;
@@ -47,30 +46,20 @@
  * Helpers
  *****************************************************************************/
 static gboolean
-pidgin_add_buddy_dialog_filter_accounts(GtkTreeModel *model, GtkTreeIter *iter,
-                                        gpointer data)
+pidgin_add_buddy_dialog_filter_accounts(gpointer item,
+                                        G_GNUC_UNUSED gpointer data)
 {
-	PurpleAccount *account = NULL;
-	PurpleProtocol *protocol = NULL;
 	gboolean ret = FALSE;
 
-	g_return_val_if_fail(GTK_IS_TREE_MODEL(model), FALSE);
-	g_return_val_if_fail(iter != NULL, FALSE);
-
-	gtk_tree_model_get(model, iter, PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT,
-	                   &account, -1);
+	if(PURPLE_IS_ACCOUNT(item)) {
+		PurpleAccount *account = PURPLE_ACCOUNT(item);
+		PurpleProtocol *protocol = purple_account_get_protocol(account);
 
-	if(!PURPLE_IS_ACCOUNT(account)) {
-		return FALSE;
+		if(PURPLE_IS_PROTOCOL(protocol)) {
+			ret = PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, add_buddy);
+		}
 	}
 
-	protocol = purple_account_get_protocol(account);
-	if(PURPLE_IS_PROTOCOL(protocol)) {
-		ret = PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, add_buddy);
-	}
-
-	g_object_unref(G_OBJECT(account));
-
 	return ret;
 }
 
@@ -248,12 +237,9 @@
 
 	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
 
-	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(dialog->filter),
-	                                       pidgin_add_buddy_dialog_filter_accounts,
-	                                       NULL, NULL);
-	gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(dialog->filter));
-
-	gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->account), 0);
+	gtk_custom_filter_set_filter_func(dialog->filter,
+	                                  pidgin_add_buddy_dialog_filter_accounts,
+	                                  NULL, NULL);
 
 	purple_blist_walk(pidgin_add_buddy_dialog_group_cb, NULL, NULL, NULL,
 	                  dialog);
--- a/pidgin/pidginaddchatdialog.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/pidginaddchatdialog.c	Sun Oct 30 03:29:33 2022 -0500
@@ -27,13 +27,12 @@
 #include "gtkaccount.h"
 #include "gtkroomlist.h"
 #include "pidginaccountchooser.h"
-#include "pidginaccountstore.h"
 #include "pidgincore.h"
 
 struct _PidginAddChatDialog {
 	GtkDialog parent;
 
-	GtkTreeModel *filter;
+	GtkCustomFilter *filter;
 
 	const gchar *default_name;
 
@@ -183,30 +182,20 @@
 }
 
 static gboolean
-pidgin_add_chat_dialog_filter_accounts(GtkTreeModel *model, GtkTreeIter *iter,
-                                       gpointer data)
+pidgin_add_chat_dialog_filter_accounts(gpointer item,
+                                       G_GNUC_UNUSED gpointer data)
 {
-	PurpleAccount *account = NULL;
-	PurpleProtocol *protocol = NULL;
 	gboolean ret = FALSE;
 
-	g_return_val_if_fail(GTK_IS_TREE_MODEL(model), FALSE);
-	g_return_val_if_fail(iter != NULL, FALSE);
-
-	gtk_tree_model_get(model, iter, PIDGIN_ACCOUNT_STORE_COLUMN_ACCOUNT,
-	                   &account, -1);
+	if(PURPLE_IS_ACCOUNT(item)) {
+		PurpleAccount *account = PURPLE_ACCOUNT(item);
+		PurpleProtocol *protocol = purple_account_get_protocol(account);
 
-	if(!PURPLE_IS_ACCOUNT(account)) {
-		return FALSE;
+		if(PURPLE_IS_PROTOCOL(protocol)) {
+			ret = PURPLE_PROTOCOL_IMPLEMENTS(protocol, CHAT, info);
+		}
 	}
 
-	protocol = purple_account_get_protocol(account);
-	if(PURPLE_IS_PROTOCOL(protocol)) {
-		ret = PURPLE_PROTOCOL_IMPLEMENTS(protocol, CHAT, info);
-	}
-
-	g_object_unref(G_OBJECT(account));
-
 	return ret;
 }
 
@@ -379,12 +368,9 @@
 
 	gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
 
-	gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(dialog->filter),
-	                                       pidgin_add_chat_dialog_filter_accounts,
-	                                       NULL, NULL);
-	gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(dialog->filter));
-
-	gtk_combo_box_set_active(GTK_COMBO_BOX(dialog->account), 0);
+	gtk_custom_filter_set_filter_func(dialog->filter,
+	                                  pidgin_add_chat_dialog_filter_accounts,
+	                                  NULL, NULL);
 
 	purple_blist_walk(pidgin_add_chat_dialog_group_cb, NULL, NULL, NULL,
 	                  dialog);
--- a/pidgin/plugins/disco/resources/disco.ui	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/plugins/disco/resources/disco.ui	Sun Oct 30 03:29:33 2022 -0500
@@ -37,14 +37,6 @@
       </item>
     </section>
   </menu>
-  <object class="PidginAccountStore" id="accounts"/>
-  <object class="PidginAccountFilterConnected" id="accounts_connected">
-    <property name="child_model">accounts</property>
-  </object>
-  <object class="PidginAccountFilterProtocol" id="xmpp_accounts">
-    <property name="child_model">accounts_connected</property>
-    <property name="protocol_id">prpl-jabber</property>
-  </object>
   <object class="GtkTreeStore" id="model">
     <columns>
       <!-- column-name pixbuf -->
@@ -76,8 +68,18 @@
             </child>
             <child>
               <object class="PidginAccountChooser" id="account_chooser">
-                <property name="model">xmpp_accounts</property>
-                <property name="active">0</property>
+                <property name="filter">
+                  <object class="GtkEveryFilter">
+                    <child>
+                      <object class="PidginAccountFilterProtocol">
+                        <property name="protocol_id">prpl-jabber</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="PidginAccountFilterConnected"/>
+                    </child>
+                  </object>
+                </property>
                 <signal name="notify::account" handler="dialog_select_account_cb" swapped="no"/>
               </object>
             </child>
--- a/pidgin/plugins/xmppconsole/console.ui	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/plugins/xmppconsole/console.ui	Sun Oct 30 03:29:33 2022 -0500
@@ -106,19 +106,18 @@
             </child>
             <child>
               <object class="PidginAccountChooser" id="account_chooser">
-                <property name="model">
-                  <object class="PidginAccountFilterProtocol">
-                    <property name="child-model">
-                      <object class="PidginAccountFilterConnected">
-                        <property name="child-model">
-                          <object class="PidginAccountStore"/>
-                        </property>
+                <property name="filter">
+                  <object class="GtkEveryFilter">
+                    <child>
+                      <object class="PidginAccountFilterProtocol">
+                        <property name="protocol-id">prpl-jabber</property>
                       </object>
-                    </property>
-                    <property name="protocol-id">prpl-jabber</property>
+                    </child>
+                    <child>
+                      <object class="PidginAccountFilterConnected"/>
+                    </child>
                   </object>
                 </property>
-                <property name="active">0</property>
                 <property name="hexpand">1</property>
                 <signal name="notify::account" handler="dropdown_changed_cb" swapped="no"/>
               </object>
--- a/pidgin/plugins/xmppconsole/xmppconsole.c	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/plugins/xmppconsole/xmppconsole.c	Sun Oct 30 03:29:33 2022 -0500
@@ -35,7 +35,7 @@
 struct _PidginXmppConsole {
 	GtkWindow parent;
 
-	GtkComboBox *account_chooser;
+	PidginAccountChooser *account_chooser;
 	PurpleConnection *gc;
 	GtkTextBuffer *buffer;
 	struct {
--- a/pidgin/resources/Accounts/chooser.ui	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/resources/Accounts/chooser.ui	Sun Oct 30 03:29:33 2022 -0500
@@ -22,18 +22,52 @@
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
   <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <template class="PidginAccountChooser" parent="GtkComboBox">
-    <child>
-      <object class="GtkCellRendererPixbuf"/>
-      <attributes>
-        <attribute name="icon-name">2</attribute>
-      </attributes>
-    </child>
-    <child>
-      <object class="GtkCellRendererText"/>
-      <attributes>
-        <attribute name="text">1</attribute>
-      </attributes>
-    </child>
+  <template class="PidginAccountChooser" parent="AdwBin">
+    <property name="child">
+      <object class="GtkDropDown" id="chooser">
+        <property name="factory">
+          <object class="GtkBuilderListItemFactory">
+            <property name="bytes">
+<![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkBox">
+        <property name="orientation">horizontal</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkImage">
+            <binding name="icon-name">
+              <closure type="gchararray" function="pidgin_account_chooser_icon_name_cb">
+                <lookup name="item">GtkListItem</lookup>
+              </closure>
+            </binding>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="xalign">0</property>
+            <binding name="label">
+              <closure type="gchararray" function="pidgin_account_chooser_label_cb">
+                <lookup name="item">GtkListItem</lookup>
+              </closure>
+            </binding>
+          </object>
+        </child>
+      </object>
+    </property>
   </template>
 </interface>
+]]>
+            </property>
+          </object>
+        </property>
+        <property name="model">
+          <object class="GtkFilterListModel" id="filter"/>
+        </property>
+        <signal name="notify::selected" handler="pidgin_account_chooser_changed_cb" swapped="no"/>
+      </object>
+    </property>
+  </template>
+</interface>
--- a/pidgin/resources/Dialogs/addbuddy.ui	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/resources/Dialogs/addbuddy.ui	Sun Oct 30 03:29:33 2022 -0500
@@ -25,13 +25,6 @@
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
   <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <object class="PidginAccountStore" id="account_store"/>
-  <object class="PidginAccountFilterConnected" id="account_filter_connected">
-    <property name="child-model">account_store</property>
-  </object>
-  <object class="GtkTreeModelFilter" id="filter">
-    <property name="child-model">account_filter_connected</property>
-  </object>
   <template class="PidginAddBuddyDialog" parent="GtkDialog">
     <property name="title" translatable="1">Add Buddy</property>
     <property name="resizable">0</property>
@@ -65,7 +58,16 @@
             <child>
               <object class="PidginAccountChooser" id="account">
                 <property name="hexpand">1</property>
-                <property name="model">filter</property>
+                <property name="filter">
+                  <object class="GtkEveryFilter">
+                    <child>
+                      <object class="GtkCustomFilter" id="filter"/>
+                    </child>
+                    <child>
+                      <object class="PidginAccountFilterConnected"/>
+                    </child>
+                  </object>
+                </property>
                 <signal name="notify::account" handler="pidgin_add_buddy_dialog_account_changed_cb" swapped="no"/>
                 <accessibility>
                   <relation name="labelled-by">label1</relation>
--- a/pidgin/resources/Dialogs/addchat.ui	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/resources/Dialogs/addchat.ui	Sun Oct 30 03:29:33 2022 -0500
@@ -25,13 +25,6 @@
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
   <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <object class="PidginAccountStore" id="account_store"/>
-  <object class="PidginAccountFilterConnected" id="account_filter_connected">
-    <property name="child-model">account_store</property>
-  </object>
-  <object class="GtkTreeModelFilter" id="filter">
-    <property name="child-model">account_filter_connected</property>
-  </object>
   <template class="PidginAddChatDialog" parent="GtkDialog">
     <property name="title" translatable="1">Add Chat</property>
     <property name="resizable">0</property>
@@ -66,7 +59,16 @@
             <child>
               <object class="PidginAccountChooser" id="account">
                 <property name="hexpand">1</property>
-                <property name="model">filter</property>
+                <property name="filter">
+                  <object class="GtkEveryFilter">
+                    <child>
+                      <object class="GtkCustomFilter" id="filter"/>
+                    </child>
+                    <child>
+                      <object class="PidginAccountFilterConnected"/>
+                    </child>
+                  </object>
+                </property>
                 <signal name="notify::account" handler="pidgin_add_chat_dialog_account_changed_cb" swapped="no"/>
               </object>
             </child>
--- a/pidgin/resources/Privacy/dialog.ui	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/resources/Privacy/dialog.ui	Sun Oct 30 03:29:33 2022 -0500
@@ -23,10 +23,6 @@
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
   <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <object class="PidginAccountStore" id="account_store"/>
-  <object class="PidginAccountFilterConnected" id="connected_account_store">
-    <property name="child-model">account_store</property>
-  </object>
   <object class="GtkListStore" id="allow_store">
     <columns>
       <column type="gchararray"/>
@@ -66,8 +62,9 @@
             <child>
               <object class="PidginAccountChooser" id="account_chooser">
                 <property name="hexpand">1</property>
-                <property name="model">connected_account_store</property>
-                <property name="active">0</property>
+                <property name="filter">
+                  <object class="PidginAccountFilterConnected"/>
+                </property>
                 <signal name="notify::account" handler="select_account_cb" swapped="no"/>
                 <accessibility>
                   <relation name="labelled-by">label1</relation>
--- a/pidgin/resources/Roomlist/roomlist.ui	Sat Oct 29 02:05:16 2022 -0500
+++ b/pidgin/resources/Roomlist/roomlist.ui	Sun Oct 30 03:29:33 2022 -0500
@@ -23,7 +23,6 @@
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
   <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <object class="PidginAccountStore" id="accounts"/>
   <template class="PidginRoomlistDialog" parent="GtkDialog">
     <property name="title" translatable="1">Room List</property>
     <signal name="close-request" handler="close_request_cb" swapped="no"/>
@@ -47,8 +46,6 @@
               <object class="PidginAccountChooser" id="account_widget">
                 <property name="hexpand">1</property>
                 <property name="can-focus">1</property>
-                <property name="model">accounts</property>
-                <property name="active">0</property>
                 <signal name="notify::account" handler="dialog_select_account_cb" swapped="no"/>
                 <accessibility>
                   <relation name="labelled-by">label1</relation>
--- a/po/POTFILES.in	Sat Oct 29 02:05:16 2022 -0500
+++ b/po/POTFILES.in	Sun Oct 30 03:29:33 2022 -0500
@@ -282,7 +282,6 @@
 pidgin/pidginaccountmanager.c
 pidgin/pidginaccountsdisabledmenu.c
 pidgin/pidginaccountsenabledmenu.c
-pidgin/pidginaccountstore.c
 pidgin/pidginactiongroup.c
 pidgin/pidginaddbuddydialog.c
 pidgin/pidginaddchatdialog.c

mercurial