# HG changeset patch
# Node ID 764571e090c6
# Parent  64805b295a5c
diff --git a/pidgin/glade/pidgin3.xml.in b/pidgin/glade/pidgin3.xml.in
--- a/pidgin/glade/pidgin3.xml.in
+++ b/pidgin/glade/pidgin3.xml.in
@@ -19,6 +19,8 @@
     <glade-widget-class name="PidginProtocolStore" generic-name="protocol_store" title="ProtocolStore"/>
     <glade-widget-class name="PidginScrollBook" generic-name="scroll_book" title="ScrollBook"/>
     <glade-widget-class name="PidginStatusBox" generic-name="status_box" title="StatusBox"/>
+    <glade-widget-class name="PidginStatusPrimitiveChooser" generic-name="status_primitive_chooser" title="StatusPrimitiveChooser"/>
+    <glade-widget-class name="PidginStatusPrimitiveStore" generic-name="status_primitive_store" title="StatusPrimitiveStore"/>
   </glade-widget-classes>
   <glade-widget-group name="pidgin" title="Pidgin">
     <glade-widget-class-ref name="PidginAccountChooser"/>
@@ -39,5 +41,7 @@
     <glade-widget-class-ref name="PidginProtocolStore"/>
     <glade-widget-class-ref name="PidginScrollBook"/>
     <glade-widget-class-ref name="PidginStatusBox"/>
+    <glade-widget-class-ref name="PidginStatusPrimitiveChooser"/>
+    <glade-widget-class-ref name="PidginStatusPrimitiveStore"/>
   </glade-widget-group>
 </glade-catalog>
diff --git a/pidgin/gtksavedstatuses.c b/pidgin/gtksavedstatuses.c
--- a/pidgin/gtksavedstatuses.c
+++ b/pidgin/gtksavedstatuses.c
@@ -32,6 +32,9 @@
 #include "pidgindialog.h"
 #include "pidginiconname.h"
 
+#include "pidginstatusprimitivechooser.h"
+#include "pidginstatusprimitivestore.h"
+
 /*
  * TODO: Should attach to the account-deleted and account-added signals
  *       and update the GtkListStores in any StatusEditor windows that
@@ -128,7 +131,6 @@
 	PurpleAccount *account;
 
 	GtkWidget *window;
-	GtkListStore *model;
 	GtkComboBox *box;
 	GtkWidget *message_view;
 	GtkTextBuffer *message_buffer;
@@ -805,61 +807,6 @@
 	gtk_widget_set_sensitive(GTK_WIDGET(dialog->save_button), (*text != '\0'));
 }
 
-static GtkWidget *
-create_status_type_menu(PurpleStatusPrimitive type)
-{
-	int i;
-	GtkWidget *dropdown;
-	GtkListStore *store;
-	GtkTreeIter iter;
-	GtkCellRenderer *renderer;
-
-	store = gtk_list_store_new(STATUS_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
-
-	for (i = PURPLE_STATUS_UNSET + 1; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
-	{
-		/* Someone should fix this for 3.0.0.  The independent boolean
-		 * should probably be set on the status type, not the status.
-		 * I guess that would prevent third party plugins from creating
-		 * independent statuses?
-		 */
-		if (i == PURPLE_STATUS_MOBILE ||
-		    i == PURPLE_STATUS_MOOD ||
-		    i == PURPLE_STATUS_TUNE)
-			/*
-			 * Special-case these.  They're intended to be independent
-			 * status types, so don't show them in the list.
-			 */
-			continue;
-
-		gtk_list_store_append(store, &iter);
-		gtk_list_store_set(store, &iter,
-		                   STATUS_COLUMN_ICON, pidgin_icon_name_from_status_primitive(i, NULL),
-		                   STATUS_COLUMN_STATUS_ID, purple_primitive_get_id_from_type(i),
-		                   STATUS_COLUMN_STATUS_NAME, purple_primitive_get_name_from_type(i),
-		                   -1);
-	}
-
-	dropdown = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
-
-	renderer = gtk_cell_renderer_pixbuf_new();
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, FALSE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer,
-	                               "icon-name", STATUS_COLUMN_ICON,
-	                               NULL);
-
-	renderer = gtk_cell_renderer_text_new();
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown), renderer, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown), renderer,
-	                               "text", STATUS_COLUMN_STATUS_NAME,
-	                               NULL);
-
-	gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown),
-	                         type - (PURPLE_STATUS_UNSET + 1));
-
-	return dropdown;
-}
-
 static void edit_substatus(StatusEditor *status_editor, PurpleAccount *account);
 
 static void
@@ -1066,6 +1013,8 @@
 	GtkWidget *hbox;
 	GtkWidget *vbox;
 	GtkWidget *win;
+	GtkListStore *store;
+	PurpleStatusPrimitive primitive = PURPLE_STATUS_AWAY;
 
 	if (edit)
 	{
@@ -1122,11 +1071,16 @@
 	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Title:"), sg, entry, TRUE, NULL);
 
 	/* Status type */
-	if (saved_status != NULL)
-		dropdown = create_status_type_menu(purple_savedstatus_get_primitive_type(saved_status));
-	else
-		dropdown = create_status_type_menu(PURPLE_STATUS_AWAY);
+	if (saved_status != NULL) {
+		primitive = purple_savedstatus_get_primitive_type(saved_status);
+	}
+
+	store = pidgin_status_primitive_store_new();
+	dropdown = pidgin_status_primitive_chooser_new();
 	dialog->type = GTK_COMBO_BOX(dropdown);
+	gtk_combo_box_set_model(GTK_COMBO_BOX(dropdown), GTK_TREE_MODEL(store));
+	gtk_combo_box_set_active_id(GTK_COMBO_BOX(dropdown),
+	                            purple_primitive_get_id_from_type(primitive));
 	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Status:"), sg, dropdown, TRUE, NULL);
 
 	/* Status message */
@@ -1215,24 +1169,26 @@
 substatus_selection_changed_cb(GtkComboBox *box, gpointer user_data)
 {
 	SubStatusEditor *select = user_data;
-	GtkTreeIter iter;
-	char *id;
 	PurpleStatusType *type;
+	PurpleStatusPrimitive primitive;
+	const gchar *id;
 
-	if (!gtk_combo_box_get_active_iter(box, &iter))
+	id = gtk_combo_box_get_active_id(box);
+	if(id == NULL) {
 		return;
-	gtk_tree_model_get(GTK_TREE_MODEL(select->model), &iter,
-					   STATUS_COLUMN_STATUS_ID, &id,
-					   -1);
-	type = purple_account_get_status_type(select->account, id);
-	g_free(id);
+	}
+
+	primitive = purple_primitive_get_type_from_id(id);
+	if(primitive == PURPLE_STATUS_UNSET) {
+		return;
+	}
 
-	if (purple_status_type_get_attr(type, "message") == NULL)
-	{
+	type = purple_account_get_status_type_with_primitive(select->account,
+	                                                     primitive);
+
+	if(purple_status_type_get_attr(type, "message") == NULL) {
 		gtk_widget_set_sensitive(select->message_view, FALSE);
-	}
-	else
-	{
+	} else {
 		gtk_widget_set_sensitive(select->message_view, TRUE);
 	}
 }
@@ -1298,25 +1254,30 @@
 	StatusEditor *status_editor;
 	GtkTreeIter iter;
 	PurpleStatusType *type;
-	char *id = NULL;
+	PurpleStatusPrimitive primitive;
+	const char *id = NULL;
 	char *message = NULL;
 	const gchar *name = NULL, *icon_name = NULL;
 
-	if (!gtk_combo_box_get_active_iter(dialog->box, &iter))
-	{
+	id = gtk_combo_box_get_active_id(GTK_COMBO_BOX(dialog->box));
+	if(id == NULL) {
 		gtk_widget_destroy(dialog->window);
 		return;
 	}
 
-	gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter,
-					   STATUS_COLUMN_STATUS_ID, &id,
-					   -1);
-	type = purple_account_get_status_type(dialog->account, id);
+	primitive = purple_primitive_get_type_from_id(id);
+	if(primitive == PURPLE_STATUS_UNSET) {
+		gtk_widget_destroy(dialog->window);
+		return;
+	}
+
+	type = purple_account_get_status_type_with_primitive(dialog->account,
+	                                                     primitive);
 	if (purple_status_type_get_attr(type, "message") != NULL) {
 		message = talkatu_markup_get_html(dialog->message_buffer, NULL);
 	}
 	name = purple_status_type_get_name(type);
-	icon_name = pidgin_icon_name_from_status_primitive(purple_status_type_get_primitive(type), NULL);
+	icon_name = pidgin_icon_name_from_status_primitive(primitive, NULL);
 
 	status_editor = dialog->status_editor;
 
@@ -1333,7 +1294,6 @@
 	}
 
 	gtk_widget_destroy(dialog->window);
-	g_free(id);
 	g_free(message);
 }
 
@@ -1368,12 +1328,11 @@
 	GtkWidget *vbox;
 	GtkWidget *win;
 	GtkTreeIter iter;
-	GtkCellRenderer *rend;
 	char *status_id = NULL;
 	char *message = NULL;
 	gboolean parent_dialog_has_substatus = FALSE;
-	GList *list;
-	gboolean select = FALSE;
+	GtkListStore *store;
+	PurpleStatusPrimitive primitive = PURPLE_STATUS_AWAY;
 
 	g_return_if_fail(status_editor != NULL);
 	g_return_if_fail(account       != NULL);
@@ -1419,23 +1378,13 @@
 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
 	gtk_size_group_add_widget(sg, label);
 
-	dialog->model = gtk_list_store_new(STATUS_NUM_COLUMNS,
-									   G_TYPE_STRING,
-									   G_TYPE_STRING,
-									   G_TYPE_STRING);
-	combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dialog->model));
+	store = pidgin_status_primitive_store_new();
+	pidgin_status_primitive_store_set_account(PIDGIN_STATUS_PRIMITIVE_STORE(store),
+	                                          account);
+	combo = pidgin_status_primitive_chooser_new();
+	gtk_combo_box_set_model(GTK_COMBO_BOX(combo), GTK_TREE_MODEL(store));
 	dialog->box = GTK_COMBO_BOX(combo);
 
-	rend = GTK_CELL_RENDERER(gtk_cell_renderer_pixbuf_new());
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, FALSE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend,
-	                               "icon-name", STATUS_COLUMN_ICON, NULL);
-
-	rend = GTK_CELL_RENDERER(gtk_cell_renderer_text_new());
-	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), rend, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), rend,
-						"text", STATUS_COLUMN_STATUS_NAME, NULL);
-
 	g_signal_connect(G_OBJECT(combo), "changed",
 					 G_CALLBACK(substatus_selection_changed_cb), dialog);
 
@@ -1484,46 +1433,20 @@
 	}
 	/* TODO: Else get the generic status type from our parent */
 
+	if(status_id != NULL) {
+		PurpleStatus *status = purple_account_get_status(account, status_id);
+		PurpleStatusType *type = purple_status_get_status_type(status);
+
+		primitive = purple_status_type_get_primitive(type);
+	}
+
+	gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo),
+	                            purple_primitive_get_id_from_type(primitive));
+
 	if (message) {
 		talkatu_markup_set_html(TALKATU_BUFFER(dialog->message_buffer), message, -1);
 	}
 
-	for (list = purple_account_get_status_types(account); list; list = list->next)
-	{
-		PurpleStatusType *status_type;
-		const char *id, *name;
-		PurpleStatusPrimitive prim;
-
-		status_type = list->data;
-
-		/*
-		 * Only allow users to select statuses that are flagged as
-		 * "user settable" and that aren't independent.
-		 */
-		if (!purple_status_type_is_user_settable(status_type) ||
-				purple_status_type_is_independent(status_type))
-			continue;
-
-		id = purple_status_type_get_id(status_type);
-		prim = purple_status_type_get_primitive(status_type);
-		name = purple_status_type_get_name(status_type);
-
-		gtk_list_store_append(dialog->model, &iter);
-		gtk_list_store_set(dialog->model, &iter,
-		                   STATUS_COLUMN_ICON, pidgin_icon_name_from_status_primitive(prim, NULL),
-		                   STATUS_COLUMN_STATUS_ID, id,
-		                   STATUS_COLUMN_STATUS_NAME, name,
-		                   -1);
-		if ((status_id != NULL) && purple_strequal(status_id, id))
-		{
-			gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter);
-			select = TRUE;
-		}
-	}
-
-	if (!select)
-		gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
-
 	if (parent_dialog_has_substatus) {
 		/* These two were gotten from the parent tree model, so they need to be freed */
 		g_free(status_id);
diff --git a/pidgin/meson.build b/pidgin/meson.build
--- a/pidgin/meson.build
+++ b/pidgin/meson.build
@@ -51,6 +51,8 @@
 	'pidginprotocolchooser.c',
 	'pidginprotocolstore.c',
 	'pidginscrollbook.c',
+	'pidginstatusprimitivechooser.c',
+	'pidginstatusprimitivestore.c',
 	'pidginstylecontext.c',
 	'pidgintalkatu.c',
 	'prefs/pidginprefs.c',
@@ -110,6 +112,8 @@
 	'pidginprotocolchooser.h',
 	'pidginprotocolstore.h',
 	'pidginscrollbook.h',
+	'pidginstatusprimitivechooser.h',
+	'pidginstatusprimitivestore.h',
 	'pidginstylecontext.h',
 	'pidgintalkatu.h',
 ]
diff --git a/pidgin/pidginstatusprimitivechooser.h b/pidgin/pidginstatusprimitivechooser.h
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginstatusprimitivechooser.h
@@ -0,0 +1,60 @@
+/*
+ * 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/>.
+ */
+
+#ifndef PIDGIN_STATUS_PRIMITIVE_CHOOSER_H
+#define PIDGIN_STATUS_PRIMITIVE_CHOOSER_H
+
+#include <gtk/gtk.h>
+
+#include <purple.h>
+
+G_BEGIN_DECLS
+
+/**
+ * PidginStatusPrimitiveChooser:
+ *
+ * A [class@Gtk.Combobox] for presenting [class@Purple.StatusPrimitive]'s to a
+ * user.
+ *
+ * Since: 3.0.0
+ */
+
+#define PIDGIN_TYPE_STATUS_PRIMITIVE_CHOOSER (pidgin_status_primitive_chooser_get_type())
+G_DECLARE_FINAL_TYPE(PidginStatusPrimitiveChooser,
+                     pidgin_status_primitive_chooser, PIDGIN,
+                     STATUS_PRIMITIVE_CHOOSER, GtkComboBox)
+
+/**
+ * pidgin_status_primitive_chooser_new:
+ *
+ * Creates a new combo box that contains all of the available status
+ * primitives in purple.
+ *
+ * Returns: (transfer full): The new combo box.
+ *
+ * Since: 3.0.0
+ */
+GtkWidget *pidgin_status_primitive_chooser_new(void);
+
+G_END_DECLS
+
+#endif /* PIDGIN_STATUS_PRIMITIVE_CHOOSER_H */
diff --git a/pidgin/pidginstatusprimitivechooser.c b/pidgin/pidginstatusprimitivechooser.c
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginstatusprimitivechooser.c
@@ -0,0 +1,56 @@
+/*
+ * 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 <pidgin/pidginstatusprimitivechooser.h>
+
+struct _PidginStatusPrimitiveChooser {
+	GtkComboBox parent;
+};
+
+G_DEFINE_TYPE(PidginStatusPrimitiveChooser, pidgin_status_primitive_chooser,
+              GTK_TYPE_COMBO_BOX)
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+
+static void
+pidgin_status_primitive_chooser_init(PidginStatusPrimitiveChooser *chooser) {
+	gtk_widget_init_template(GTK_WIDGET(chooser));
+}
+
+static void
+pidgin_status_primitive_chooser_class_init(PidginStatusPrimitiveChooserClass *klass) {
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+	/* Widget template */
+	gtk_widget_class_set_template_from_resource(
+	        widget_class, "/im/pidgin/Pidgin3/statusprimitivechooser.ui");
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+GtkWidget *
+pidgin_status_primitive_chooser_new(void) {
+	return g_object_new(PIDGIN_TYPE_STATUS_PRIMITIVE_CHOOSER, NULL);
+}
diff --git a/pidgin/pidginstatusprimitivestore.h b/pidgin/pidginstatusprimitivestore.h
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginstatusprimitivestore.h
@@ -0,0 +1,82 @@
+/*
+ * 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/>.
+ */
+
+#ifndef PIDGIN_STATUS_PRIMITIVE_STORE_H
+#define PIDGIN_STATUS_PRIMITIVE_STORE_H
+
+#include <gtk/gtk.h>
+
+#include <purple.h>
+
+G_BEGIN_DECLS
+
+/**
+ * PidginStatusPrimitiveStore:
+ *
+ * A [class@Gtk.ListStore] for use with [class@PidginStatusPrimitiveChooser].
+ *
+ * Since: 3.0.0
+ */
+
+#define PIDGIN_TYPE_STATUS_PRIMITIVE_STORE (pidgin_status_primitive_store_get_type())
+G_DECLARE_FINAL_TYPE(PidginStatusPrimitiveStore, pidgin_status_primitive_store,
+                     PIDGIN, STATUS_PRIMITIVE_STORE, GtkListStore)
+
+/**
+ * pidgin_status_primitive_store_new:
+ *
+ * Creates a new [class@Gtk.ListStore] that contains status primitives in
+ * purple.
+ *
+ * Returns: (transfer full): The new list store.
+ *
+ * Since: 3.0.0
+ */
+GtkListStore *pidgin_status_primitive_store_new(void);
+
+/**
+ * pidgin_status_primitive_store_set_account:
+ * @store: The status primitive store instance.
+ * @account: (nullable): The account to use.
+ *
+ * Sets the [class@Purple.Account] whose status primitives to show. If %NULL,
+ * all status primitives will be displayed.
+ *
+ * Since: 3.0.0
+ */
+void pidgin_status_primitive_store_set_account(PidginStatusPrimitiveStore *store, PurpleAccount *account);
+
+/**
+ * pidgin_status_primitive_store_get_account:
+ * @store: The store instance.
+ *
+ * Gets the [class@Purple.Account] that's associated with @store.
+ *
+ * Returns: (transfer none): The account of %NULL.
+ *
+ * Since: 3.0.0
+ */
+PurpleAccount *pidgin_status_primitive_store_get_account(PidginStatusPrimitiveStore *store);
+
+G_END_DECLS
+
+#endif /* PIDGIN_STATUS_PRIMITIVE_STORE_H */
diff --git a/pidgin/pidginstatusprimitivestore.c b/pidgin/pidginstatusprimitivestore.c
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginstatusprimitivestore.c
@@ -0,0 +1,254 @@
+/*
+ * 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 <pidgin/pidginstatusprimitivestore.h>
+
+#include <pidgin/pidginiconname.h>
+
+struct _PidginStatusPrimitiveStore {
+	GtkListStore parent;
+
+	PurpleAccount *account;
+};
+
+enum {
+	PROP_0,
+	PROP_ACCOUNT,
+	N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+enum {
+	COL_ID,
+	COL_ICON,
+	COL_TEXT,
+	N_COLUMNS,
+};
+
+G_DEFINE_TYPE(PidginStatusPrimitiveStore, pidgin_status_primitive_store,
+              GTK_TYPE_LIST_STORE)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static GList *
+pidgin_status_primitive_store_get_primitives_from_account(PidginStatusPrimitiveStore *store)
+{
+	GList *primitives = NULL;
+	GList *list = purple_account_get_status_types(store->account);
+
+	while(list != NULL) {
+		PurpleStatusType *type = (PurpleStatusType *)list->data;
+		PurpleStatusPrimitive primitive;
+		gboolean user_settable = FALSE, independent = FALSE;
+
+		/* iterate to the next item as we already have the data in type. */
+		list = list->next;
+
+		user_settable = purple_status_type_is_user_settable(type);
+		independent = purple_status_type_is_independent(type);
+		if(!user_settable || independent) {
+			continue;
+		}
+
+		primitive = purple_status_type_get_primitive(type);
+
+		primitives = g_list_append(primitives, GINT_TO_POINTER(primitive));
+	}
+
+	return primitives;
+}
+
+static GList *
+pidgin_status_primitive_store_get_primitives(PidginStatusPrimitiveStore *store)
+{
+	GList *primitives = NULL;
+
+	primitives = g_list_append(primitives,
+	                           GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
+	primitives = g_list_append(primitives,
+	                           GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
+	primitives = g_list_append(primitives,
+	                           GINT_TO_POINTER(PURPLE_STATUS_UNAVAILABLE));
+	primitives = g_list_append(primitives,
+	                           GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
+	primitives = g_list_append(primitives,
+	                           GINT_TO_POINTER(PURPLE_STATUS_AWAY));
+	primitives = g_list_append(primitives,
+	                           GINT_TO_POINTER(PURPLE_STATUS_EXTENDED_AWAY));
+
+	return primitives;
+}
+
+static void
+pidgin_status_primitive_store_populate(PidginStatusPrimitiveStore *store) {
+	GList *primitives = NULL;
+
+	/* clear out the list */
+	gtk_list_store_clear(GTK_LIST_STORE(store));
+
+	/* Get all the primitives and add them. */
+	if(PURPLE_IS_ACCOUNT(store->account)) {
+		primitives = pidgin_status_primitive_store_get_primitives_from_account(store);
+	} else {
+		primitives = pidgin_status_primitive_store_get_primitives(store);
+	}
+
+	while(primitives != NULL) {
+		PurpleStatusPrimitive primitive = GPOINTER_TO_INT(primitives->data);
+		GtkTreeIter iter;
+
+		gtk_list_store_append(GTK_LIST_STORE(store), &iter);
+		/* clang-format off */
+		gtk_list_store_set(
+			GTK_LIST_STORE(store), &iter,
+			COL_ID, purple_primitive_get_id_from_type(primitive),
+			COL_ICON, pidgin_icon_name_from_status_primitive(primitive, NULL),
+			COL_TEXT, purple_primitive_get_name_from_type(primitive),
+			-1);
+		/* clang-format on */
+
+		primitives = g_list_delete_link(primitives, primitives);
+	}
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+
+static void
+pidgin_status_primitive_store_get_property(GObject *obj, guint param_id,
+                                           GValue *value, GParamSpec *pspec)
+{
+	PidginStatusPrimitiveStore *store = PIDGIN_STATUS_PRIMITIVE_STORE(obj);
+
+	switch(param_id) {
+		case PROP_ACCOUNT:
+			g_value_set_object(value,
+			                   pidgin_status_primitive_store_get_account(store));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+pidgin_status_primitive_store_set_property(GObject *obj, guint param_id,
+                                           const GValue *value,
+                                           GParamSpec *pspec)
+{
+	PidginStatusPrimitiveStore *store = PIDGIN_STATUS_PRIMITIVE_STORE(obj);
+
+	switch(param_id) {
+		case PROP_ACCOUNT:
+			pidgin_status_primitive_store_set_account(store,
+			                                          g_value_get_object(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+			break;
+	}
+}
+
+static void
+pidgin_status_primitive_store_dispose(GObject *obj) {
+	PidginStatusPrimitiveStore *store = PIDGIN_STATUS_PRIMITIVE_STORE(obj);
+
+	g_clear_object(&store->account);
+
+	G_OBJECT_CLASS(pidgin_status_primitive_store_parent_class)->dispose(obj);
+}
+
+static void
+pidgin_status_primitive_store_constructed(GObject *obj) {
+	PidginStatusPrimitiveStore *store = PIDGIN_STATUS_PRIMITIVE_STORE(obj);
+
+	G_OBJECT_CLASS(pidgin_status_primitive_store_parent_class)->constructed(obj);
+
+	/* This exists to populate the store if it was created without a value for
+	 * the account property.
+	 */
+	pidgin_status_primitive_store_populate(store);
+}
+
+static void
+pidgin_status_primitive_store_init(PidginStatusPrimitiveStore *store) {
+	GType types[N_COLUMNS] = { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING };
+
+	gtk_list_store_set_column_types(GTK_LIST_STORE(store), N_COLUMNS, types);
+}
+
+static void
+pidgin_status_primitive_store_class_init(PidginStatusPrimitiveStoreClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	obj_class->get_property = pidgin_status_primitive_store_get_property;
+	obj_class->set_property = pidgin_status_primitive_store_set_property;
+	obj_class->constructed = pidgin_status_primitive_store_constructed;
+	obj_class->dispose = pidgin_status_primitive_store_dispose;
+
+	/**
+	 * PidginStatusPrimitiveStore::account:
+	 *
+	 * The account whose statuses to display.
+	 *
+	 * Since: 3.0.0
+	 */
+	/* clang-format off */
+	properties[PROP_ACCOUNT] = g_param_spec_object(
+		"account", "account",
+		"The account whose statuses to display",
+		PURPLE_TYPE_ACCOUNT,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+	/* clang-format on */
+
+	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+GtkListStore *
+pidgin_status_primitive_store_new(void) {
+	return g_object_new(PIDGIN_TYPE_STATUS_PRIMITIVE_STORE, NULL);
+}
+
+void
+pidgin_status_primitive_store_set_account(PidginStatusPrimitiveStore *store,
+                                          PurpleAccount *account)
+{
+	g_return_if_fail(PIDGIN_IS_STATUS_PRIMITIVE_STORE(store));
+
+	if(g_set_object(&store->account, account)) {
+		pidgin_status_primitive_store_populate(store);
+
+		g_object_notify_by_pspec(G_OBJECT(store), properties[PROP_ACCOUNT]);
+	}
+}
+
+PurpleAccount *
+pidgin_status_primitive_store_get_account(PidginStatusPrimitiveStore *store) {
+	g_return_val_if_fail(PIDGIN_IS_STATUS_PRIMITIVE_STORE(store), NULL);
+
+	return store->account;
+}
diff --git a/pidgin/resources/pidgin.gresource.xml b/pidgin/resources/pidgin.gresource.xml
--- a/pidgin/resources/pidgin.gresource.xml
+++ b/pidgin/resources/pidgin.gresource.xml
@@ -34,6 +34,7 @@
     <file compressed="true">Xfer/xfer.ui</file>
     <file compressed="true">closebutton.ui</file>
     <file compressed="true">gtk/menus.ui</file>
+    <file compressed="true">statusprimitivechooser.ui</file>
     <file>icons/16x16/status/pidgin-user-available.png</file>
     <file>icons/16x16/status/pidgin-user-away.png</file>
     <file>icons/16x16/status/pidgin-user-busy.png</file>
diff --git a/pidgin/resources/statusprimitivechooser.ui b/pidgin/resources/statusprimitivechooser.ui
new file mode 100644
--- /dev/null
+++ b/pidgin/resources/statusprimitivechooser.ui
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 
+
+Pidgin - Internet Messenger
+Copyright (C) Pidgin Developers <devel@pidgin.im>
+
+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/>.
+
+-->
+<interface>
+  <requires lib="gtk+" version="3.24"/>
+  <!-- interface-license-type gplv2 -->
+  <!-- interface-name Pidgin -->
+  <!-- interface-description Internet Messenger -->
+  <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
+  <template class="PidginStatusPrimitiveChooser" parent="GtkComboBox">
+    <property name="visible">True</property>
+    <property name="can-focus">False</property>
+    <property name="id-column">0</property>
+    <child>
+      <object class="GtkCellRendererPixbuf"/>
+      <attributes>
+        <attribute name="icon-name">1</attribute>
+      </attributes>
+    </child>
+    <child>
+      <object class="GtkCellRendererText"/>
+      <attributes>
+        <attribute name="markup">2</attribute>
+      </attributes>
+    </child>
+  </template>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -365,6 +365,8 @@
 pidgin/pidginprotocolchooser.c
 pidgin/pidginprotocolstore.c
 pidgin/pidginscrollbook.c
+pidgin/pidginstatusprimitivechooser.c
+pidgin/pidginstatusprimitivestore.c
 pidgin/pidginstylecontext.c
 pidgin/pidgintalkatu.c
 pidgin/plugins/disco/gtkdisco.c
