Fri, 03 Mar 2023 04:49:01 -0600
Propagate the notify signal for the Presence object on a ContactInfo
Testing Done:
Ran the unit tests under valgrind and verified now no leaks.
Also checked the docs and made sure the signal was documented properly.
Reviewed at https://reviews.imfreedom.org/r/2306/
| libpurple/purplecontactinfo.c | file | annotate | diff | comparison | revisions | |
| libpurple/tests/test_contact_info.c | file | annotate | diff | comparison | revisions |
--- a/libpurple/purplecontactinfo.c Fri Mar 03 01:24:36 2023 -0600 +++ b/libpurple/purplecontactinfo.c Fri Mar 03 04:49:01 2023 -0600 @@ -59,6 +59,12 @@ }; static GParamSpec *properties[N_PROPERTIES] = {NULL, }; +enum { + SIG_PRESENCE_CHANGED, + N_SIGNALS, +}; +static guint signals[N_SIGNALS] = {0, }; + G_DEFINE_TYPE_WITH_PRIVATE(PurpleContactInfo, purple_contact_info, G_TYPE_OBJECT) @@ -126,6 +132,19 @@ purple_contact_info_update_name_for_display(data); } +/* + * This is a notify callback on the presence for a contact info, it is used + * to emit the presence-changed signal. + */ +static void +purple_contact_info_presence_notify_cb(GObject *source, GParamSpec *pspec, + gpointer data) +{ + g_signal_emit(data, signals[SIG_PRESENCE_CHANGED], + g_param_spec_get_name_quark(pspec), + source, pspec); +} + /****************************************************************************** * GObject Implementation *****************************************************************************/ @@ -271,7 +290,11 @@ priv = purple_contact_info_get_instance_private(info); priv->tags = purple_tags_new(); + priv->presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL); + g_signal_connect_object(priv->presence, "notify", + G_CALLBACK(purple_contact_info_presence_notify_cb), + info, 0); } static void @@ -451,6 +474,34 @@ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, N_PROPERTIES, properties); + + /** + * PurpleContactInfo::presence-changed: + * @info: The instance. + * @presence: The presence that was changed. + * @pspec: The [class@GObject.ParamSpec] for the property that changed. + * + * This is a propagation of the notify signal from @presence. This means + * that your callback will be called when anything in the presence changes. + * + * This also supports details, so you can specify the signal name as + * 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 + */ + signals[SIG_PRESENCE_CHANGED] = g_signal_new_class_handler( + "presence-changed", + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + NULL, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + PURPLE_TYPE_PRESENCE, + G_TYPE_PARAM); } /******************************************************************************
--- a/libpurple/tests/test_contact_info.c Fri Mar 03 01:24:36 2023 -0600 +++ b/libpurple/tests/test_contact_info.c Fri Mar 03 04:49:01 2023 -0600 @@ -382,6 +382,57 @@ } /****************************************************************************** + * presence-changed signal tests + *****************************************************************************/ +static void +test_purple_contact_info_presence_changed_callback(PurpleContactInfo *info, + PurplePresence *presence, + GParamSpec *pspec, + gpointer data) +{ + guint *counter = data; + + g_assert_true(PURPLE_IS_CONTACT_INFO(info)); + g_assert_true(PURPLE_IS_PRESENCE(presence)); + g_assert_true(G_IS_PARAM_SPEC(pspec)); + + *counter = *counter + 1; +} + +static void +test_purple_contact_info_presence_changed_signal(void) { + PurpleContactInfo *info = NULL; + PurplePresence *presence = NULL; + guint counter = 0; + + /* Create the info and add our callbacks, one for everything and another + * for just idle to make sure detail works. + */ + info = purple_contact_info_new(NULL); + g_signal_connect(info, "presence-changed", + G_CALLBACK(test_purple_contact_info_presence_changed_callback), + &counter); + g_signal_connect(info, "presence-changed::idle", + G_CALLBACK(test_purple_contact_info_presence_changed_callback), + &counter); + + /* Grab the presence and start changing stuff. */ + presence = purple_contact_info_get_presence(info); + g_assert_true(PURPLE_IS_PRESENCE(presence)); + + /* Set the presence as idle with no time, which should call our callback + * three times, twice for the non-detailed callback, and once for the + * detailed callback. + */ + g_assert_cmpint(counter, ==, 0); + purple_presence_set_idle(presence, TRUE, NULL); + g_assert_cmpint(counter, ==, 3); + + /* Cleanup. */ + g_clear_object(&info); +} + +/****************************************************************************** * Main *****************************************************************************/ gint @@ -432,5 +483,8 @@ g_test_add_func("/contact-info/matches/none", test_purple_contact_info_matches_none); + g_test_add_func("/contact-info/presence-changed-signal", + test_purple_contact_info_presence_changed_signal); + return g_test_run(); }