pidgin/pidgin

Parents 0a7a98da4f1b
Children 687260353985
Add a propagation signal for populate-menu to PurpleContactManager

Testing Done:
Ran the unit tests under valgrind.

Reviewed at https://reviews.imfreedom.org/r/2838/
--- a/libpurple/purplecontactinfo.c Tue Jan 23 01:34:53 2024 -0600
+++ b/libpurple/purplecontactinfo.c Tue Jan 23 01:38:28 2024 -0600
@@ -360,7 +360,7 @@
*
* The protocol specific id for the contact.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_ID] = g_param_spec_string(
"id", "id",
@@ -374,7 +374,7 @@
* The username for this contact. In rare cases this can change, like when
* a user changes their "nick" on IRC which is their user name.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_USERNAME] = g_param_spec_string(
"username", "username",
@@ -388,7 +388,7 @@
* The display name for this contact. This is generally set by the person
* the contact is representing and controlled via the protocol plugin.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_DISPLAY_NAME] = g_param_spec_string(
"display-name", "display-name",
@@ -402,7 +402,7 @@
* The alias for this contact. This is controlled by the libpurple user and
* may be used by the protocol if it allows for aliasing.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_ALIAS] = g_param_spec_string(
"alias", "alias",
@@ -418,7 +418,7 @@
* protocol plugin in the event that the protocol allows people to set a
* highlight/branding color.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_COLOR] = g_param_spec_string(
"color", "color",
@@ -432,7 +432,7 @@
* The primary email address for the contact. This may also be controlled
* via a protocol plugin in the event that the protocol makes it available.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_EMAIL] = g_param_spec_string(
"email", "email",
@@ -446,7 +446,7 @@
* The primary phone number for the contact. This may also be set via a
* protocol plugin in the event that the protocol knows it.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_PHONE_NUMBER] = g_param_spec_string(
"phone-number", "phone-number",
@@ -460,7 +460,7 @@
* The time zone for this contact. This is typically controlled by the
* protocol and should only be read by others.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_TIME_ZONE] = g_param_spec_boxed(
"time-zone", "time-zone",
@@ -475,7 +475,7 @@
* a contact and store it server side. This property is where that is kept
* track of.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_NOTE] = g_param_spec_string(
"note", "note",
@@ -489,7 +489,7 @@
* The avatar for this contact. This is typically controlled by the
* protocol and should only be read by others.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_AVATAR] = g_param_spec_object(
"avatar", "avatar",
@@ -503,7 +503,7 @@
* The [class@Purple.Presence] for this contact. This is typically
* controlled by the protocol and should only be read by others.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_PRESENCE] = g_param_spec_object(
"presence", "presence",
@@ -516,7 +516,7 @@
*
* The [class@Purple.Tags] for this contact.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_TAGS] = g_param_spec_object(
"tags", "tags",
@@ -529,7 +529,7 @@
*
* The [class@Purple.Person] that this contact belongs to.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_PERSON] = g_param_spec_object(
"person", "person",
@@ -542,7 +542,7 @@
*
* The permission level for the contact.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_PERMISSION] = g_param_spec_enum(
"permission", "permission",
@@ -560,7 +560,7 @@
* This could be used to hold the `ident` for an IRC contact, the
* `resource` for an XMPP contact, or something similar.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_SID] = g_param_spec_string(
"sid", "sid",
@@ -587,7 +587,7 @@
* * [property@Purple.ContactInfo:username]
* * [property@Purple.ContactInfo:id]
*
- * Since: 3.0.0
+ * Since: 3.0
*/
properties[PROP_NAME_FOR_DISPLAY] = g_param_spec_string(
"name-for-display", "name-for-display",
@@ -610,7 +610,7 @@
* something like `presence-changed::message` and your callback will only
* be called when the message property of @presence has been changed.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
signals[SIG_PRESENCE_CHANGED] = g_signal_new_class_handler(
"presence-changed",
@@ -637,7 +637,7 @@
* can add additional items, hide items, and lay them out however it
* pleases.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
signals[SIG_POPULATE_MENU] = g_signal_new_class_handler(
"populate-menu",
--- a/libpurple/purplecontactinfo.h Tue Jan 23 01:34:53 2024 -0600
+++ b/libpurple/purplecontactinfo.h Tue Jan 23 01:38:28 2024 -0600
@@ -52,7 +52,7 @@
* A representation of whether or not a contact has permission to contact the
* user.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_TYPE_IN_3_0
typedef enum {
@@ -68,7 +68,7 @@
*
* The class struct for [class@Purple.ContactInfo].
*
- * Since: 3.0.0
+ * Since: 3.0
*/
struct _PurpleContactInfoClass {
/*< private >*/
@@ -85,7 +85,7 @@
* need to refer to a user. Be it a chat, an direct message, a file transfer,
* etc.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
/**
@@ -98,7 +98,7 @@
*
* Returns: (transfer full): The new instance.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurpleContactInfo *purple_contact_info_new(const gchar *id);
@@ -114,7 +114,7 @@
*
* Returns: The id of the contact.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const gchar *purple_contact_info_get_id(PurpleContactInfo *info);
@@ -128,7 +128,7 @@
* at all. The main intent of this, is for protocols to update the id of an
* an account when it is connected if the id is missing.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_id(PurpleContactInfo *info, const char *id);
@@ -141,7 +141,7 @@
*
* Returns: The username of @info.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const gchar *purple_contact_info_get_username(PurpleContactInfo *info);
@@ -156,7 +156,7 @@
* This is primarily used by protocol plugins like IRC when a user changes
* their "nick" which is their username.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_username(PurpleContactInfo *info, const gchar *username);
@@ -171,7 +171,7 @@
* Returns: (nullable): The display name of @info if one is set, otherwise
* %NULL will be returned.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const gchar *purple_contact_info_get_display_name(PurpleContactInfo *info);
@@ -186,7 +186,7 @@
* This should primarily only be used by protocol plugins and everyone else
* should be using [method@Purple.ContactInfo.set_alias].
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_display_name(PurpleContactInfo *info, const gchar *display_name);
@@ -199,7 +199,7 @@
*
* Returns: (nullable): The alias of @info if one is set, otherwise %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const gchar *purple_contact_info_get_alias(PurpleContactInfo *info);
@@ -213,7 +213,7 @@
*
* Protocol plugins may use this value to synchronize across instances.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_alias(PurpleContactInfo *info, const gchar *alias);
@@ -227,7 +227,7 @@
*
* Returns: The RGB hex code.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const char *purple_contact_info_get_color(PurpleContactInfo *info);
@@ -243,7 +243,7 @@
* following it. Different user interfaces may be able to handle additional
* precision, but using `#RRGGBB` will have the highest compatibility.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_color(PurpleContactInfo *info, const char *color);
@@ -256,7 +256,7 @@
*
* Returns: (nullable): The primary email address or %NULL if not set.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const char *purple_contact_info_get_email(PurpleContactInfo *info);
@@ -268,7 +268,7 @@
*
* Sets the primary email address for @info.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_email(PurpleContactInfo *info, const char *email);
@@ -281,7 +281,7 @@
*
* Returns: (nullable): The primary phone number for the contact.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const char *purple_contact_info_get_phone_number(PurpleContactInfo *info);
@@ -293,7 +293,7 @@
*
* Sets the primary phone number for @info.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_phone_number(PurpleContactInfo *info, const char *phone_number);
@@ -306,7 +306,7 @@
*
* Returns: (transfer none) (nullable): The time zone if set, otherwise %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
GTimeZone *purple_contact_info_get_time_zone(PurpleContactInfo *info);
@@ -318,7 +318,7 @@
*
* Sets the time zone of @info to @time_zone.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_time_zone(PurpleContactInfo *info, GTimeZone *timezone);
@@ -331,7 +331,7 @@
*
* Returns: The note.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const char *purple_contact_info_get_note(PurpleContactInfo *info);
@@ -343,7 +343,7 @@
*
* Sets the note for @info to @note.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_note(PurpleContactInfo *info, const char *note);
@@ -356,7 +356,7 @@
*
* Returns: (transfer none): The avatar if set, otherwise %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurpleAvatar *purple_contact_info_get_avatar(PurpleContactInfo *info);
@@ -371,7 +371,7 @@
*
* Typically this should only called by the protocol plugin.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_avatar(PurpleContactInfo *info, PurpleAvatar *avatar);
@@ -385,7 +385,7 @@
* Returns: (transfer none) (nullable): The presence for @info if one is
* set, otherwise %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurplePresence *purple_contact_info_get_presence(PurpleContactInfo *info);
@@ -398,7 +398,7 @@
*
* Returns: (transfer none): The tags for @info.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurpleTags *purple_contact_info_get_tags(PurpleContactInfo *info);
@@ -410,7 +410,7 @@
*
* Sets the person that @info belongs to to @person.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_person(PurpleContactInfo *info, PurplePerson *person);
@@ -424,7 +424,7 @@
* Returns: (transfer none) (nullable): The [class@Purple.Person] that @info
* belongs to, or %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurplePerson *purple_contact_info_get_person(PurpleContactInfo *info);
@@ -437,7 +437,7 @@
*
* Returns: The permission for @info.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurpleContactInfoPermission purple_contact_info_get_permission(PurpleContactInfo *info);
@@ -449,7 +449,7 @@
*
* Sets the permission of @info to @permission.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_permission(PurpleContactInfo *info, PurpleContactInfoPermission permission);
@@ -462,7 +462,7 @@
*
* Returns: (transfer none) (nullable): The sid if set.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const char *purple_contact_info_get_sid(PurpleContactInfo *info);
@@ -474,7 +474,7 @@
*
* Sets the sid, or secondary id, of @info to @sid.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_info_set_sid(PurpleContactInfo *info, const char *sid);
@@ -488,7 +488,7 @@
*
* Returns: (transfer none): The name to display for @info.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
const char *purple_contact_info_get_name_for_display(PurpleContactInfo *info);
@@ -503,7 +503,7 @@
* Returns: less than 0 if @a should be sorted before @b, 0 if they sorted
* equally, and greater than 0 if @a should be sorted after @b.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
int purple_contact_info_compare(PurpleContactInfo *a, PurpleContactInfo *b);
@@ -522,7 +522,7 @@
* Returns: %TRUE if @needle matches any of the above properties, otherwise
* %FALSE.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
gboolean purple_contact_info_matches(PurpleContactInfo *info, const char *needle);
@@ -539,7 +539,7 @@
*
* Returns: (transfer full) (nullable): The menu for the contact info or %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
BirbActionMenu *purple_contact_info_get_menu(PurpleContactInfo *info);
--- a/libpurple/purplecontactmanager.c Tue Jan 23 01:34:53 2024 -0600
+++ b/libpurple/purplecontactmanager.c Tue Jan 23 01:38:28 2024 -0600
@@ -18,6 +18,8 @@
#include <glib/gi18n-lib.h>
+#include <birb.h>
+
#include "purplecontactmanager.h"
#include "purplegdkpixbuf.h"
@@ -30,6 +32,7 @@
SIG_REMOVED,
SIG_PERSON_ADDED,
SIG_PERSON_REMOVED,
+ SIG_POPULATE_MENU,
N_SIGNALS,
};
static guint signals[N_SIGNALS] = {0, };
@@ -191,6 +194,14 @@
}
static void
+purple_contact_manager_contact_populate_menu_cb(PurpleContactInfo *info,
+ GMenu *menu,
+ gpointer data)
+{
+ g_signal_emit(data, signals[SIG_POPULATE_MENU], 0, info, menu);
+}
+
+static void
purple_contact_manager_tags_changed_cb(G_GNUC_UNUSED PurpleTags *tags,
G_GNUC_UNUSED const char *tag,
G_GNUC_UNUSED const char *name,
@@ -295,7 +306,7 @@
*
* Emitted after @contact has been added to @manager.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
signals[SIG_ADDED] = g_signal_new_class_handler(
"added",
@@ -316,7 +327,7 @@
*
* Emitted after @contact has been removed from @manager.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
signals[SIG_REMOVED] = g_signal_new_class_handler(
"removed",
@@ -339,7 +350,7 @@
* when a contact is added via [method@Purple.ContactManager.add] but can
* also happen if [method@Purple.ContactManager.add_person] is called.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
signals[SIG_PERSON_ADDED] = g_signal_new_class_handler(
"person-added",
@@ -361,7 +372,7 @@
* Emitted after @person has been removed from @manager. This typically
* happens when [method@Purple.ContactManager.remove_person] is called.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
signals[SIG_PERSON_REMOVED] = g_signal_new_class_handler(
"person-removed",
@@ -374,6 +385,31 @@
G_TYPE_NONE,
1,
PURPLE_TYPE_PERSON);
+
+ /**
+ * PurpleContactManager::populate-menu:
+ * @manager: The instance.
+ * @info: The [class@ContactInfo] instance.
+ * @menu: The [class@Gio.Menu] to populate.
+ *
+ * This is a propagation of [signal@ContactInfo::populate-menu]. This means
+ * that your callback will be called for any contact info to populate its
+ * context menu.
+ *
+ * Since: 3.0
+ */
+ signals[SIG_POPULATE_MENU] = g_signal_new_class_handler(
+ "populate-menu",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ PURPLE_TYPE_CONTACT_INFO,
+ BIRB_TYPE_ACTION_MENU);
}
/******************************************************************************
@@ -455,15 +491,19 @@
tags = purple_contact_info_get_tags(info);
/* Add some notify signals to track changes. */
- g_signal_connect_object(contact, "notify::alias",
+ g_signal_connect_object(info, "notify::alias",
+ G_CALLBACK(purple_contact_manager_contact_update_cb),
+ manager, 0);
+ g_signal_connect_object(info, "notify::permission",
G_CALLBACK(purple_contact_manager_contact_update_cb),
manager, 0);
- g_signal_connect_object(contact, "notify::permission",
- G_CALLBACK(purple_contact_manager_contact_update_cb),
- manager, 0);
- g_signal_connect_object(contact, "notify::person",
+ g_signal_connect_object(info, "notify::person",
G_CALLBACK(purple_contact_manager_contact_person_changed_cb),
manager, 0);
+ g_signal_connect_object(info, "populate-menu",
+ G_CALLBACK(purple_contact_manager_contact_populate_menu_cb),
+ manager, 0);
+
g_signal_connect_object(tags, "added",
G_CALLBACK(purple_contact_manager_tags_changed_cb),
contact, 0);
--- a/libpurple/purplecontactmanager.h Tue Jan 23 01:34:53 2024 -0600
+++ b/libpurple/purplecontactmanager.h Tue Jan 23 01:38:28 2024 -0600
@@ -43,7 +43,7 @@
*
* A manager for [class@Purple.Contact]s.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
/**
@@ -56,7 +56,7 @@
*
* Returns: (transfer none): The default [class@Purple.ContactManager] instance.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurpleContactManager *purple_contact_manager_get_default(void);
@@ -69,7 +69,7 @@
* Adds @contact to @manager. If a contact with a matching account and id
* already exists, no action will be taken.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_manager_add(PurpleContactManager *manager, PurpleContact *contact);
@@ -84,7 +84,7 @@
* Returns: If @contact is found and removed %TRUE will be returned otherwise
* %FALSE will be returned.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
gboolean purple_contact_manager_remove(PurpleContactManager *manager, PurpleContact *contact);
@@ -98,7 +98,7 @@
*
* Returns: %TRUE if anything was removed, %FALSE if nothing was removed.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
gboolean purple_contact_manager_remove_all(PurpleContactManager *manager, PurpleAccount *account);
@@ -113,7 +113,7 @@
* Returns: (transfer none) (nullable): A [iface@Gio.ListModel] of all the
* contacts belonging to @account.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
GListModel *purple_contact_manager_get_all(PurpleContactManager *manager, PurpleAccount *account);
@@ -130,7 +130,7 @@
* Returns: (transfer full): The [class@Purple.Contact] if found, otherwise
* %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurpleContact *purple_contact_manager_find_with_username(PurpleContactManager *manager, PurpleAccount *account, const gchar *username);
@@ -146,7 +146,7 @@
* Returns: (transfer full): The [class@Purple.Contact] if found, otherwise
* %NULL.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
PurpleContact *purple_contact_manager_find_with_id(PurpleContactManager *manager, PurpleAccount *account, const gchar *id);
@@ -163,7 +163,7 @@
* This method is meant to help us transition to the new API and this method
* shouldn't be used elsewhere.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_DEPRECATED
void purple_contact_manager_add_buddy(PurpleContactManager *manager, PurpleBuddy *buddy);
@@ -180,7 +180,7 @@
* automatically add the [class@Purple.Person] instance when
* [method@Purple.ContactManager.add] is called.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_manager_add_person(PurpleContactManager *manager, PurplePerson *person);
@@ -195,7 +195,7 @@
* Removes @person from @manager optionally removing all of the contacts
* contained in @person as well if @remove_contacts is %TRUE.
*
- * Since: 3.0.0
+ * Since: 3.0
*/
PURPLE_AVAILABLE_IN_3_0
void purple_contact_manager_remove_person(PurpleContactManager *manager, PurplePerson *person, gboolean remove_contacts);
--- a/libpurple/tests/test_contact_manager.c Tue Jan 23 01:34:53 2024 -0600
+++ b/libpurple/tests/test_contact_manager.c Tue Jan 23 01:38:28 2024 -0600
@@ -20,6 +20,8 @@
#include <purple.h>
+#include <birb.h>
+
#include "test_ui.h"
/******************************************************************************
@@ -466,6 +468,64 @@
}
/******************************************************************************
+ * propagate_populate_menu tests
+ *****************************************************************************/
+static void
+test_purple_contact_manager_propagate_populate_menu_cb(PurpleContactManager *manager,
+ PurpleContactInfo *info,
+ BirbActionMenu *action_menu,
+ gpointer data)
+{
+ GMenu *menu = NULL;
+ guint *counter = data;
+
+ g_assert_true(PURPLE_IS_CONTACT_MANAGER(manager));
+ g_assert_true(PURPLE_IS_CONTACT_INFO(info));
+ g_assert_true(BIRB_IS_ACTION_MENU(action_menu));
+
+ menu = birb_action_menu_get_menu(action_menu);
+ g_menu_append(menu, "test", "test.action");
+
+ /* Increment our counter. */
+ *counter = *counter + 1;
+}
+
+static void
+test_purple_contact_manager_propagate_populate_menu(void) {
+ PurpleAccount *account = NULL;
+ PurpleContactManager *manager = NULL;
+ PurpleContact *contact = NULL;
+ BirbActionMenu *action_menu = NULL;
+ GMenu *menu = NULL;
+ guint counter = 0;
+
+ account = purple_account_new("test", "test");
+
+ manager = g_object_new(PURPLE_TYPE_CONTACT_MANAGER, NULL);
+ g_signal_connect(manager, "populate-menu",
+ G_CALLBACK(test_purple_contact_manager_propagate_populate_menu_cb),
+ &counter);
+
+ contact = purple_contact_new(account, NULL);
+ purple_contact_manager_add(manager, contact);
+
+ action_menu = purple_contact_info_get_menu(PURPLE_CONTACT_INFO(contact));
+ g_assert_true(BIRB_IS_ACTION_MENU(action_menu));
+
+ menu = birb_action_menu_get_menu(action_menu);
+ g_assert_true(G_IS_MENU(menu));
+
+ g_assert_cmpuint(counter, ==, 1);
+ g_assert_cmpuint(g_menu_model_get_n_items(G_MENU_MODEL(menu)), ==, 1);
+
+ g_assert_finalize_object(action_menu);
+
+ g_clear_object(&account);
+ g_clear_object(&manager);
+ g_clear_object(&contact);
+}
+
+/******************************************************************************
* Main
*****************************************************************************/
gint
@@ -501,6 +561,9 @@
g_test_add_func("/contact-manager/person/add-via-contact-remove-person-with-contacts",
test_purple_contact_manager_person_add_via_contact_remove_person_with_contacts);
+ g_test_add_func("/contact-manager/propagate-populate-menu",
+ test_purple_contact_manager_propagate_populate_menu);
+
ret = g_test_run();
test_ui_purple_uninit();