diff --git a/libpurple/purpleaccountmanager.h b/libpurple/purpleaccountmanager.h
--- a/libpurple/purpleaccountmanager.h
+++ b/libpurple/purpleaccountmanager.h
@@ -126,6 +126,19 @@
 GList *purple_account_manager_get_active(PurpleAccountManager *manager);
 
 /**
+ * purple_account_manager_get_disable:
+ * @manager: The account manager instance.
+ *
+ * Gets the list of all disabled accounts.
+ *
+ * Returns: (transfer container) (element-type PurpleAccount): The list of all
+ *          disabled accounts.
+ *
+ * Since: 3.0.0
+ */
+GList *purple_account_manager_get_disabled(PurpleAccountManager *manager);
+
+/**
  * purple_account_manager_find_by_id:
  * @manager: The account manager instance.
  * @id: The id of the account.
# HG changeset patch
# Node ID 2e7422016950
# Parent  84e92cf6f64a
diff --git a/libpurple/purpleaccountmanager.c b/libpurple/purpleaccountmanager.c
--- a/libpurple/purpleaccountmanager.c
+++ b/libpurple/purpleaccountmanager.c
@@ -205,6 +205,24 @@
 	return active;
 }
 
+GList *
+purple_account_manager_get_disabled(PurpleAccountManager *manager) {
+	GList *disabled = NULL, *l = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager), NULL);
+
+	for(l = manager->accounts; l != NULL; l = l->next) {
+		PurpleAccount *account = l->data;
+
+		if(!purple_account_get_enabled(account, purple_core_get_ui())) {
+			disabled = g_list_append(disabled, account);
+		}
+	}
+
+	return disabled;
+}
+
+
 void
 purple_account_manager_reorder(PurpleAccountManager *manager,
                                PurpleAccount *account,
diff --git a/pidgin/pidginaccountsdisabledmenu.h b/pidgin/pidginaccountsdisabledmenu.h
--- a/pidgin/pidginaccountsdisabledmenu.h
+++ b/pidgin/pidginaccountsdisabledmenu.h
@@ -34,6 +34,10 @@
 
 G_BEGIN_DECLS
 
+#define PIDGIN_TYPE_ACCOUNTS_DISABLED_MENU (pidgin_accounts_disabled_menu_get_type())
+G_DECLARE_FINAL_TYPE(PidginAccountsDisabledMenu, pidgin_accounts_disabled_menu,
+                     PIDGIN, ACCOUNTS_DISABLED_MENU, GMenuModel)
+
 /**
  * pidgin_accounts_disabled_menu_new:
  *
@@ -44,7 +48,7 @@
  *
  * Since: 3.0.0
  */
-GMenu *pidgin_accounts_disabled_menu_new(void);
+GMenuModel *pidgin_accounts_disabled_menu_new(void);
 
 G_END_DECLS
 
diff --git a/pidgin/pidginaccountsdisabledmenu.c b/pidgin/pidginaccountsdisabledmenu.c
--- a/pidgin/pidginaccountsdisabledmenu.c
+++ b/pidgin/pidginaccountsdisabledmenu.c
@@ -24,103 +24,193 @@
 
 #include "pidginaccountsdisabledmenu.h"
 
-#include "pidgincore.h"
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-pidgin_accounts_disabled_menu_refresh_helper(PurpleAccount *account,
-                                             gpointer data)
-{
-	GMenu *menu = data;
-
-	if(!purple_account_get_enabled(account, PIDGIN_UI)) {
-		gchar *label = NULL, *action = NULL;
-		const gchar *account_name = purple_account_get_username(account);
-		const gchar *protocol_name = purple_account_get_protocol_name(account);
+struct _PidginAccountsDisabledMenu {
+	GMenuModel parent;
 
-		/* translators: This format string is intended to contain the account
-		 * name followed by the protocol name to uniquely identify a specific
-		 * account.
-		 */
-		label = g_strdup_printf(_("%s (%s)"), account_name, protocol_name);
-		action = g_strdup_printf("app.enable-account::%s",
-		                         purple_account_get_id(account));
-
-		g_menu_append(menu, label, action);
-
-		g_free(label);
-		g_free(action);
-	}
-}
+	GList *accounts;
+};
 
-static void
-pidgin_accounts_disabled_menu_refresh(GMenu *menu) {
-	PurpleAccountManager *manager = NULL;
-
-	g_menu_remove_all(menu);
-
-	manager = purple_account_manager_get_default();
-	purple_account_manager_foreach(manager,
-	                               pidgin_accounts_disabled_menu_refresh_helper,
-	                               menu);
-
-	if(g_menu_model_get_n_items(G_MENU_MODEL(menu)) == 0) {
-		g_menu_append(menu, _("No disabled accounts"), "disabled");
-	}
-}
+G_DEFINE_TYPE(PidginAccountsDisabledMenu, pidgin_accounts_disabled_menu,
+              G_TYPE_MENU_MODEL)
 
 /******************************************************************************
  * Callbacks
  *****************************************************************************/
 static void
-pidgin_accounts_disabled_menu_enabled_cb(G_GNUC_UNUSED PurpleAccount *account,
+pidgin_accounts_disabled_menu_refresh(PidginAccountsDisabledMenu *menu) {
+	PurpleAccountManager *manager = NULL;
+	gint removed = 0, added = 0;
+
+	/* When refreshing we're always removing at least 1 item because of the
+	 * "no disabled accounts" item that we put in place when all accounts
+	 * are enabled.
+	 */
+	removed = MAX(1, g_list_length(menu->accounts));
+
+	/* Grab the manager and get all the disabled accounts. */
+	manager = purple_account_manager_get_default();
+	menu->accounts = purple_account_manager_get_disabled(manager);
+
+	/* Similar to the aboved note about removed items, if every account is
+	 * enabled, we add an item saying "no disabled accounts".
+	 */
+	added = MAX(1, g_list_length(menu->accounts));
+
+	/* Tell any listeners that our menu has changed. */
+	g_menu_model_items_changed(G_MENU_MODEL(menu), 0, removed, added);
+}
+
+static void
+pidgin_accounts_disabled_menu_changed_cb(G_GNUC_UNUSED PurpleAccount *account,
                                          gpointer data)
 {
-	pidgin_accounts_disabled_menu_refresh(data);
+	PidginAccountsDisabledMenu *menu = data;
+
+	pidgin_accounts_disabled_menu_refresh(menu);
+}
+
+/******************************************************************************
+ * GMenuModel Implementation
+ *****************************************************************************/
+static gboolean
+pidgin_accounts_disabled_menu_is_mutable(GMenuModel *model) {
+	return TRUE;
+}
+
+static gboolean
+pidgin_accounts_disabled_menu_get_n_items(GMenuModel *model) {
+	PidginAccountsDisabledMenu *menu = NULL;
+
+	menu = PIDGIN_ACCOUNTS_DISABLED_MENU(model);
+
+	if(menu->accounts == NULL) {
+		return 1;
+	}
+
+	return g_list_length(menu->accounts);
 }
 
 static void
-pidgin_accounts_disabled_menu_disabled_cb(G_GNUC_UNUSED PurpleAccount *account,
-                                          gpointer data)
+pidgin_accounts_disabled_menu_get_item_attributes(GMenuModel *model,
+                                                  gint index,
+                                                  GHashTable **attributes)
 {
-	pidgin_accounts_disabled_menu_refresh(data);
+	PidginAccountsDisabledMenu *menu = NULL;
+	PurpleAccount *account = NULL;
+	PurpleProtocol *protocol = NULL;
+	GVariant *value = NULL;
+	const gchar *account_name = NULL, *protocol_name = NULL;
+
+	menu = PIDGIN_ACCOUNTS_DISABLED_MENU(model);
+
+	/* Create our hash table of attributes to return. */
+	*attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+	                                    (GDestroyNotify)g_variant_unref);
+
+	/* If we don't have any disabled accounts, just return a single item,
+	 * stating as much.
+	 */
+	if(menu->accounts == NULL) {
+		value = g_variant_new_string(_("No disabled accounts"));
+		g_hash_table_insert(*attributes, g_strdup("label"),
+		                    g_variant_ref(value));
+
+		value = g_variant_new_string("disabled");
+		g_hash_table_insert(*attributes, g_strdup("action"),
+		                    g_variant_ref(value));
+
+		return;
+	}
+
+	account = g_list_nth_data(menu->accounts, index);
+	if(account == NULL) {
+		return;
+	}
+
+	account_name = purple_account_get_username(account);
+	protocol_name = purple_account_get_protocol_name(account);
+
+	/* translators: This format string is intended to contain the account
+	 * name followed by the protocol name to uniquely identify a specific
+	 * account.
+	 */
+	value = g_variant_new_printf(_("%s (%s)"), account_name, protocol_name);
+	g_hash_table_insert(*attributes, g_strdup(G_MENU_ATTRIBUTE_LABEL),
+	                    g_variant_ref(value));
+
+	value = g_variant_new_string("app.enable-account");
+	g_hash_table_insert(*attributes, g_strdup(G_MENU_ATTRIBUTE_ACTION),
+	                    g_variant_ref(value));
+
+	value = g_variant_new_printf("%s", purple_account_get_id(account));
+	g_hash_table_insert(*attributes, g_strdup(G_MENU_ATTRIBUTE_TARGET),
+	                    g_variant_ref(value));
+
+	protocol = purple_account_get_protocol(account);
+	if(protocol != NULL) {
+		value = g_variant_new_printf("%s", purple_protocol_get_icon_name(protocol));
+		g_hash_table_insert(*attributes, g_strdup(G_MENU_ATTRIBUTE_ICON),
+		                    g_variant_ref(value));
+	}
 }
 
 static void
-pidgin_accounts_disabled_menu_weak_notify_cb(G_GNUC_UNUSED gpointer data,
-                                             GObject *obj)
+pidgin_accounts_disabled_menu_get_item_links(GMenuModel *model, gint index,
+                                             GHashTable **links)
 {
+	*links = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+	                               g_object_unref);
+}
+
+/******************************************************************************
+ * GObjectImplementation
+ *****************************************************************************/
+static void
+pidgin_accounts_disabled_menu_dispose(GObject *obj) {
 	purple_signals_disconnect_by_handle(obj);
+
+	G_OBJECT_CLASS(pidgin_accounts_disabled_menu_parent_class)->dispose(obj);
+}
+
+static void
+pidgin_accounts_disabled_menu_constructed(GObject *obj) {
+	G_OBJECT_CLASS(pidgin_accounts_disabled_menu_parent_class)->constructed(obj);
+
+	pidgin_accounts_disabled_menu_refresh(PIDGIN_ACCOUNTS_DISABLED_MENU(obj));
+}
+
+static void
+pidgin_accounts_disabled_menu_init(PidginAccountsDisabledMenu *menu) {
+	gpointer handle = NULL;
+
+	/* Wire up the purple signals we care about. */
+	handle = purple_accounts_get_handle();
+	purple_signal_connect(handle, "account-enabled", menu,
+	                      G_CALLBACK(pidgin_accounts_disabled_menu_changed_cb),
+	                      menu);
+	purple_signal_connect(handle, "account-disabled", menu,
+	                      G_CALLBACK(pidgin_accounts_disabled_menu_changed_cb),
+	                      menu);
+}
+
+static void
+pidgin_accounts_disabled_menu_class_init(PidginAccountsDisabledMenuClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GMenuModelClass *model_class = G_MENU_MODEL_CLASS(klass);
+
+	obj_class->constructed = pidgin_accounts_disabled_menu_constructed;
+	obj_class->dispose = pidgin_accounts_disabled_menu_dispose;
+
+	model_class->is_mutable = pidgin_accounts_disabled_menu_is_mutable;
+	model_class->get_n_items = pidgin_accounts_disabled_menu_get_n_items;
+	model_class->get_item_attributes = pidgin_accounts_disabled_menu_get_item_attributes;
+	model_class->get_item_links = pidgin_accounts_disabled_menu_get_item_links;
 }
 
 /******************************************************************************
  * Public API
  *****************************************************************************/
-GMenu *
+GMenuModel *
 pidgin_accounts_disabled_menu_new(void) {
-	GMenu *menu = NULL;
-	gpointer handle = NULL;
-
-	/* Create the menu and set our instance as data on it so it'll be freed
-	 * when the menu is destroyed.
-	 */
-	menu = g_menu_new();
-	g_object_weak_ref(G_OBJECT(menu),
-	                  pidgin_accounts_disabled_menu_weak_notify_cb, NULL);
-
-	/* Populate ourselves with any accounts that are already disabled. */
-	pidgin_accounts_disabled_menu_refresh(menu);
-
-	/* Wire up the purple signals we care about. */
-	handle = purple_accounts_get_handle();
-	purple_signal_connect(handle, "account-enabled", menu,
-	                      G_CALLBACK(pidgin_accounts_disabled_menu_enabled_cb),
-	                      menu);
-	purple_signal_connect(handle, "account-disabled", menu,
-	                      G_CALLBACK(pidgin_accounts_disabled_menu_disabled_cb),
-	                      menu);
-
-	return menu;
+	return g_object_new(PIDGIN_TYPE_ACCOUNTS_DISABLED_MENU, NULL);
 }
diff --git a/pidgin/pidginapplication.c b/pidgin/pidginapplication.c
--- a/pidgin/pidginapplication.c
+++ b/pidgin/pidginapplication.c
@@ -130,12 +130,13 @@
 static void
 pidgin_application_populate_dynamic_menus(PidginApplication *application) {
 	GMenu *source = NULL, *target = NULL;
+	GMenuModel *model = NULL;
 
 	/* Link the AccountsDisabledMenu into its proper location. */
-	source = pidgin_accounts_disabled_menu_new();
+	model = pidgin_accounts_disabled_menu_new();
 	target = gtk_application_get_menu_by_id(GTK_APPLICATION(application),
 	                                        "disabled-accounts");
-	g_menu_append_section(target, NULL, G_MENU_MODEL(source));
+	g_menu_append_section(target, NULL, model);
 
 	/* Link the AccountsEnabledMenu into its proper location. */
 	source = pidgin_accounts_enabled_menu_new();
