# HG changeset patch
# Node ID 1a9e0c0d9b5c
# Parent  d3c594113fe1
diff --git a/ChangeLog.API b/ChangeLog.API
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -326,6 +326,8 @@
 		* _PurpleSoundEventID
 		* _PurpleSslConnection
 		* _XMLNodeType
+		* account-actions-changed signal. Use
+		  PurpleProtocolActions::actions-changed instead.
 		* account-added signal. Use PurpleAccountManager::added instead.
 		* account-alias-changed signal
 		* account-authorization-denied, account-authorization-granted,
@@ -663,6 +665,7 @@
 		* PurplePounceEvent
 		* PurplePounceOption
 		* PurplePrefsUiOps
+		* purple_protocol_got_account_actions
 		* purple_protocol_got_account_idle
 		* purple_protocol_got_account_status
 		* purple_protocol_got_account_status_with_attributes
diff --git a/doc/reference/libpurple/signals_account.md b/doc/reference/libpurple/signals_account.md
--- a/doc/reference/libpurple/signals_account.md
+++ b/doc/reference/libpurple/signals_account.md
@@ -6,7 +6,6 @@
 ### Signal List
 
 * [account-status-changed](#account-status-changed)
-* [account-actions-changed](#account-actions-changed)
 * [account-signed-on](#account-signed-on)
 * [account-signed-off](#account-signed-off)
 
@@ -75,24 +74,6 @@
 
 ----
 
-#### account-actions-changed
-
-```c
-void user_function(PurpleAccount *account, gpointer user_data);
-```
-
-Emitted when the account actions are changed after initial connection.
-
-**Parameters:**
-
-**account**
-: The account whose actions changed.
-
-**user_data**
-: User data set when the signal handler was connected.
-
-----
-
 #### account-signed-on
 
 ```c
diff --git a/libpurple/accounts.c b/libpurple/accounts.c
--- a/libpurple/accounts.c
+++ b/libpurple/accounts.c
@@ -649,10 +649,6 @@
 						 G_TYPE_NONE, 3, PURPLE_TYPE_ACCOUNT,
 						 PURPLE_TYPE_STATUS, PURPLE_TYPE_STATUS);
 
-	purple_signal_register(handle, "account-actions-changed",
-						 purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-						 PURPLE_TYPE_ACCOUNT);
-
 	purple_signal_register(handle, "account-signed-on",
 	                       purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
 	                       PURPLE_TYPE_ACCOUNT);
diff --git a/libpurple/protocols.h b/libpurple/protocols.h
--- a/libpurple/protocols.h
+++ b/libpurple/protocols.h
@@ -41,20 +41,6 @@
 /**************************************************************************/
 
 /**
- * purple_protocol_got_account_actions:
- * @account:   The account.
- *
- * Notifies Purple that our account's actions have changed. This is only
- * called after the initial connection. Emits the account-actions-changed
- * signal.
- *
- * This is meant to be called from protocols.
- *
- * See <link linkend="accounts-account-actions-changed"><literal>"account-actions-changed"</literal></link>
- */
-void purple_protocol_got_account_actions(PurpleAccount *account);
-
-/**
  * purple_protocol_got_user_idle:
  * @account:   The account the user is on.
  * @name:      The name of the buddy.
diff --git a/libpurple/protocols.c b/libpurple/protocols.c
--- a/libpurple/protocols.c
+++ b/libpurple/protocols.c
@@ -42,17 +42,6 @@
 /* Protocol API                                                           */
 /**************************************************************************/
 void
-purple_protocol_got_account_actions(PurpleAccount *account)
-{
-
-	g_return_if_fail(account != NULL);
-	g_return_if_fail(purple_account_is_connected(account));
-
-	purple_signal_emit(purple_accounts_get_handle(), "account-actions-changed",
-	                   account);
-}
-
-void
 purple_protocol_got_user_idle(PurpleAccount *account, const char *name,
 		gboolean idle, time_t idle_time)
 {
diff --git a/libpurple/protocols/demo/purpledemoprotocol.c b/libpurple/protocols/demo/purpledemoprotocol.c
--- a/libpurple/protocols/demo/purpledemoprotocol.c
+++ b/libpurple/protocols/demo/purpledemoprotocol.c
@@ -39,7 +39,7 @@
 purple_demo_protocol_create_connection(PurpleProtocol *protocol,
                                        PurpleAccount *account,
                                        const char *password,
-                                       GError **error)
+                                       G_GNUC_UNUSED GError **error)
 {
 	g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), NULL);
 	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
diff --git a/libpurple/protocols/jabber/adhoccommands.c b/libpurple/protocols/jabber/adhoccommands.c
--- a/libpurple/protocols/jabber/adhoccommands.c
+++ b/libpurple/protocols/jabber/adhoccommands.c
@@ -266,8 +266,12 @@
 		js->commands = g_list_append(js->commands,cmd);
 	}
 
-	if (js->state == JABBER_STREAM_CONNECTED)
-		purple_protocol_got_account_actions(purple_connection_get_account(js->gc));
+	if (js->state == JABBER_STREAM_CONNECTED) {
+		PurpleProtocol *protocol = purple_connection_get_protocol(js->gc);
+
+		purple_protocol_actions_changed(PURPLE_PROTOCOL_ACTIONS(protocol),
+		                                purple_connection_get_account(js->gc));
+	}
 }
 
 static void
diff --git a/libpurple/purpleprotocolactions.h b/libpurple/purpleprotocolactions.h
--- a/libpurple/purpleprotocolactions.h
+++ b/libpurple/purpleprotocolactions.h
@@ -119,6 +119,19 @@
  */
 GMenu *purple_protocol_actions_get_menu(PurpleProtocolActions *actions, PurpleConnection *connection);
 
+/**
+ * purple_protocol_actions_changed:
+ * @actions: The instance.
+ * @account: The [class@Account] whose actions changed.
+ *
+ * Emits the [signal@ProtocolActions::actions-changed] signal. This is meant to
+ * be called by [iface@ProtocolActions] implementations when actions have
+ * changed.
+ *
+ * Since: 3.0.0
+ */
+void purple_protocol_actions_changed(PurpleProtocolActions *actions, PurpleAccount *account);
+
 G_END_DECLS
 
 #endif /* PURPLE_PROTOCOL_ACTIONS_H */
diff --git a/libpurple/purpleprotocolactions.c b/libpurple/purpleprotocolactions.c
--- a/libpurple/purpleprotocolactions.c
+++ b/libpurple/purpleprotocolactions.c
@@ -22,6 +22,12 @@
 
 #include "purpleprotocolactions.h"
 
+enum {
+	SIG_ACTIONS_CHANGED,
+	N_SIGNALS,
+};
+static guint signals[N_SIGNALS] = {0, };
+
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
@@ -29,8 +35,28 @@
                    PURPLE_TYPE_PROTOCOL)
 
 static void
-purple_protocol_actions_default_init(G_GNUC_UNUSED PurpleProtocolActionsInterface *iface)
-{
+purple_protocol_actions_default_init(PurpleProtocolActionsInterface *iface) {
+	/**
+	 * PurpleProtocolActions::actions-changed:
+	 * @self: The instance.
+	 * @account: The [class@Account] whose actions changed.
+	 *
+	 * A signal that is emitted to tell interested parties that the actions
+	 * have changed.
+	 *
+	 * Since: 3.0.0
+	 */
+	signals[SIG_ACTIONS_CHANGED] = g_signal_new_class_handler(
+		"actions-changed",
+		G_TYPE_FROM_INTERFACE(iface),
+		G_SIGNAL_RUN_LAST,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		G_TYPE_NONE,
+		1,
+		PURPLE_TYPE_ACCOUNT);
 }
 
 /******************************************************************************
@@ -86,3 +112,13 @@
 
 	return NULL;
 }
+
+void
+purple_protocol_actions_changed(PurpleProtocolActions *actions,
+                                PurpleAccount *account)
+{
+	g_return_if_fail(PURPLE_IS_PROTOCOL_ACTIONS(actions));
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+	g_signal_emit(actions, signals[SIG_ACTIONS_CHANGED], 0, account);
+}
diff --git a/libpurple/purpleprotocolmanager.c b/libpurple/purpleprotocolmanager.c
--- a/libpurple/purpleprotocolmanager.c
+++ b/libpurple/purpleprotocolmanager.c
@@ -21,9 +21,12 @@
 #include "purpleprotocolmanager.h"
 #include "purpleprivate.h"
 
+#include "purpleprotocolactions.h"
+
 enum {
 	SIG_REGISTERED,
 	SIG_UNREGISTERED,
+	SIG_ACCOUNT_ACTIONS_CHANGED,
 	N_SIGNALS,
 };
 static guint signals[N_SIGNALS] = {0, };
@@ -38,6 +41,19 @@
 static PurpleProtocolManager *default_manager = NULL;
 
 /******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+purple_protocol_manager_actions_changed_cb(PurpleProtocolActions *actions,
+                                           PurpleAccount *account,
+                                           gpointer data)
+{
+	/* Propagate the actions-changed signal. */
+	g_signal_emit(data, signals[SIG_ACCOUNT_ACTIONS_CHANGED], 0, actions,
+	              account);
+}
+
+/******************************************************************************
  * GListModel Implementation
  *****************************************************************************/
 static GType
@@ -145,6 +161,31 @@
 		G_TYPE_NONE,
 		1,
 		PURPLE_TYPE_PROTOCOL);
+
+	/**
+	 * PurpleProtocolManager::account-actions-changed:
+	 * @manager: The instance.
+	 * @protocol: The [class@Protocol] whose actions changed.
+	 * @account: The [class@Account] whose actions changed.
+	 *
+	 * This is a propagation of the [signal@ProtocolActions::actions-changed]
+	 * signal and will only be emitted for protocols that implement
+	 * [iface@ProtocolActions].
+	 *
+	 * Since: 3.0.0
+	 */
+	signals[SIG_ACCOUNT_ACTIONS_CHANGED] = g_signal_new_class_handler(
+		"account-actions-changed",
+		G_OBJECT_CLASS_TYPE(klass),
+		G_SIGNAL_RUN_LAST,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		G_TYPE_NONE,
+		2,
+		PURPLE_TYPE_PROTOCOL,
+		PURPLE_TYPE_ACCOUNT);
 }
 
 /******************************************************************************
@@ -194,6 +235,13 @@
 
 	g_signal_emit(G_OBJECT(manager), signals[SIG_REGISTERED], 0, protocol);
 
+	/* Connect the signals we want to propagate. */
+	if(PURPLE_IS_PROTOCOL_ACTIONS(protocol)) {
+		g_signal_connect_object(protocol, "actions-changed",
+		                        G_CALLBACK(purple_protocol_manager_actions_changed_cb),
+		                        manager, 0);
+	}
+
 	return TRUE;
 }
 
@@ -218,9 +266,19 @@
 
 	if(g_hash_table_remove(manager->protocols, id)) {
 		guint position;
+
 		if(g_ptr_array_find(manager->list, protocol, &position)) {
 			g_ptr_array_remove_index(manager->list, position);
 			g_list_model_items_changed(G_LIST_MODEL(manager), position, 1, 0);
+
+			/* Disconnect our signal handlers for tracking changes if this is a
+			 * PurpleProtocolActions implementation.
+			 */
+			if(PURPLE_IS_PROTOCOL_ACTIONS(protocol)) {
+				g_signal_handlers_disconnect_by_func(protocol,
+				                                     purple_protocol_manager_actions_changed_cb,
+				                                     manager);
+			}
 		}
 
 		g_signal_emit(G_OBJECT(manager), signals[SIG_UNREGISTERED], 0,
diff --git a/pidgin/pidginaccountsenabledmenu.c b/pidgin/pidginaccountsenabledmenu.c
--- a/pidgin/pidginaccountsenabledmenu.c
+++ b/pidgin/pidginaccountsenabledmenu.c
@@ -38,6 +38,43 @@
               G_TYPE_MENU_MODEL)
 
 /******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+pidgin_accounts_enabled_menu_update(PidginAccountsEnabledMenu *menu,
+                                    PurpleAccount *account)
+{
+	PurpleProtocol *protocol = NULL;
+	gint index = -1;
+
+	index = g_queue_index(menu->accounts, account);
+	if(index >= 0) {
+		/* Tell the model that the account needs to be updated. */
+		g_menu_model_items_changed(G_MENU_MODEL(menu), index, 0, 0);
+	}
+
+	/* If the protocol has actions add them to the application windows. */
+	protocol = purple_account_get_protocol(account);
+	if(PURPLE_IS_PROTOCOL_ACTIONS(protocol)) {
+		PurpleProtocolActions *actions = PURPLE_PROTOCOL_ACTIONS(protocol);
+		PurpleConnection *connection = NULL;
+		GActionGroup *action_group = NULL;
+
+		connection = purple_account_get_connection(account);
+		action_group = purple_protocol_actions_get_action_group(actions,
+		                                                        connection);
+		if(G_IS_ACTION_GROUP(action_group)) {
+			GApplication *application = g_application_get_default();
+			const gchar *prefix = purple_protocol_actions_get_prefix(actions);
+
+			pidgin_application_add_action_group(PIDGIN_APPLICATION(application),
+			                                    prefix, action_group);
+			g_object_unref(action_group);
+		}
+	}
+}
+
+/******************************************************************************
  * Callbacks
  *****************************************************************************/
 static void
@@ -72,35 +109,7 @@
 static void
 pidgin_accounts_enabled_menu_connected_cb(PurpleAccount *account, gpointer data)
 {
-	PidginAccountsEnabledMenu *menu = data;
-	PurpleProtocol *protocol = NULL;
-	gint index = -1;
-
-	index = g_queue_index(menu->accounts, account);
-	if(index >= 0) {
-		/* Tell the model that the account needs to be updated. */
-		g_menu_model_items_changed(G_MENU_MODEL(menu), index, 0, 0);
-	}
-
-	/* If the protocol has actions add them to the application windows. */
-	protocol = purple_account_get_protocol(account);
-	if(PURPLE_IS_PROTOCOL_ACTIONS(protocol)) {
-		PurpleProtocolActions *actions = PURPLE_PROTOCOL_ACTIONS(protocol);
-		PurpleConnection *connection = NULL;
-		GActionGroup *action_group = NULL;
-
-		connection = purple_account_get_connection(account);
-		action_group = purple_protocol_actions_get_action_group(actions,
-		                                                        connection);
-		if(G_IS_ACTION_GROUP(action_group)) {
-			GApplication *application = g_application_get_default();
-			const gchar *prefix = purple_protocol_actions_get_prefix(actions);
-
-			pidgin_application_add_action_group(PIDGIN_APPLICATION(application),
-			                                    prefix, action_group);
-			g_object_unref(action_group);
-		}
-	}
+	pidgin_accounts_enabled_menu_update(data, account);
 }
 
 static void
@@ -152,6 +161,15 @@
 	}
 }
 
+static void
+pidgin_accounts_enabled_menu_actions_changed_cb(G_GNUC_UNUSED PurpleProtocolManager *manager,
+                                                G_GNUC_UNUSED PurpleProtocol *protocol,
+                                                PurpleAccount *account,
+                                                gpointer data)
+{
+	pidgin_accounts_enabled_menu_update(data, account);
+}
+
 /******************************************************************************
  * GMenuModel Implementation
  *****************************************************************************/
@@ -313,6 +331,7 @@
 static void
 pidgin_accounts_enabled_menu_init(PidginAccountsEnabledMenu *menu) {
 	PurpleAccountManager *manager = NULL;
+	PurpleProtocolManager *protocol_manager = NULL;
 	gpointer handle = NULL;
 
 	menu->accounts = g_queue_new();
@@ -334,6 +353,12 @@
 	purple_signal_connect(handle, "account-signed-off", menu,
 	                      G_CALLBACK(pidgin_accounts_enabled_menu_disconnected_cb),
 	                      menu);
+
+	/* We also need to know when the protocol actions have changed. */
+	protocol_manager = purple_protocol_manager_get_default();
+	g_signal_connect_object(protocol_manager, "account-actions-changed",
+	                        G_CALLBACK(pidgin_accounts_enabled_menu_actions_changed_cb),
+	                        menu, 0);
 }
 
 static void
