Thu, 07 Aug 2025 21:34:33 -0500
Replace Purple.Avatar with Purple.Image
Purple.Avatar was unnecessary and this just moves everything to Purple.Image
which should work just fine.
Testing Done:
Loaded a demo account and verified that the avatars were shown in the contact list properly. Also called in the turtles.
Reviewed at https://reviews.imfreedom.org/r/4084/
--- a/libpurple/meson.build Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/meson.build Thu Aug 07 21:34:33 2025 -0500 @@ -14,7 +14,6 @@ 'purpleattachment.c', 'purpleattachments.c', 'purpleauthorizationrequest.c', - 'purpleavatar.c', 'purplebadge.c', 'purplebadgemanager.c', 'purplebadges.c', @@ -109,7 +108,6 @@ 'purpleattachment.h', 'purpleattachments.h', 'purpleauthorizationrequest.h', - 'purpleavatar.h', 'purplebadge.h', 'purplebadgemanager.h', 'purplebadges.h',
--- a/libpurple/purpleavatar.c Thu Aug 07 21:32:18 2025 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,306 +0,0 @@ -/* - * Purple - Internet Messaging Library - * Copyright (C) Pidgin Developers <devel@pidgin.im> - * - * Purple 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>. - */ - -#include "purpleavatar.h" - -struct _PurpleAvatar { - GObject parent; - - char *filename; - - GdkPixbuf *pixbuf; - - gboolean animated; - GdkPixbufAnimation *animation; - - PurpleTags *tags; -}; - -enum { - PROP_0, - PROP_FILENAME, - PROP_PIXBUF, - PROP_ANIMATED, - PROP_ANIMATION, - PROP_TAGS, - N_PROPERTIES, -}; -static GParamSpec *properties[N_PROPERTIES] = {NULL, }; - -/****************************************************************************** - * Helpers - *****************************************************************************/ -static void -purple_avatar_set_filename(PurpleAvatar *avatar, const char *filename) { - g_return_if_fail(PURPLE_IS_AVATAR(avatar)); - - if(g_set_str(&avatar->filename, filename)) { - g_object_notify_by_pspec(G_OBJECT(avatar), properties[PROP_FILENAME]); - } -} - -static PurpleAvatar * -purple_avatar_new_common(const char *filename, GdkPixbufAnimation *animation) { - PurpleAvatar *avatar = NULL; - - avatar = g_object_new(PURPLE_TYPE_AVATAR, "filename", filename, NULL); - - if(gdk_pixbuf_animation_is_static_image(animation)) { - /* If we loaded a static image, grab the static image and set it to our - * pixbuf member, clear the animation, and return the new avatar. - */ - - avatar->pixbuf = gdk_pixbuf_animation_get_static_image(animation); - g_object_ref(avatar->pixbuf); - - g_clear_object(&animation); - } else { - /* If we did load an animation, set the appropriate properties and - * return the avatar. - */ - avatar->animated = TRUE; - avatar->animation = animation; - } - - return avatar; -} - -/****************************************************************************** - * GObject Implementation - *****************************************************************************/ -G_DEFINE_FINAL_TYPE(PurpleAvatar, purple_avatar, G_TYPE_OBJECT) - -static void -purple_avatar_get_property(GObject *obj, guint param_id, GValue *value, - GParamSpec *pspec) -{ - PurpleAvatar *avatar = PURPLE_AVATAR(obj); - - switch(param_id) { - case PROP_FILENAME: - g_value_set_string(value, purple_avatar_get_filename(avatar)); - break; - case PROP_PIXBUF: - g_value_set_object(value, purple_avatar_get_pixbuf(avatar)); - break; - case PROP_ANIMATED: - g_value_set_boolean(value, purple_avatar_get_animated(avatar)); - break; - case PROP_ANIMATION: - g_value_set_object(value, purple_avatar_get_animation(avatar)); - break; - case PROP_TAGS: - g_value_set_object(value, purple_avatar_get_tags(avatar)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); - break; - } -} - -static void -purple_avatar_set_property(GObject *obj, guint param_id, const GValue *value, - GParamSpec *pspec) -{ - PurpleAvatar *avatar = PURPLE_AVATAR(obj); - - switch(param_id) { - case PROP_FILENAME: - purple_avatar_set_filename(avatar, g_value_get_string(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); - break; - } -} - -static void -purple_avatar_finalize(GObject *obj) { - PurpleAvatar *avatar = PURPLE_AVATAR(obj); - - g_clear_pointer(&avatar->filename, g_free); - g_clear_object(&avatar->pixbuf); - g_clear_object(&avatar->animation); - g_clear_object(&avatar->tags); - - G_OBJECT_CLASS(purple_avatar_parent_class)->finalize(obj); -} - -static void -purple_avatar_init(PurpleAvatar *avatar) { - avatar->tags = purple_tags_new(); -} - -static void -purple_avatar_class_init(PurpleAvatarClass *klass) { - GObjectClass *obj_class = G_OBJECT_CLASS(klass); - - obj_class->finalize = purple_avatar_finalize; - obj_class->get_property = purple_avatar_get_property; - obj_class->set_property = purple_avatar_set_property; - - /** - * PurpleAvatar:filename: - * - * The filename that this avatar was created from. - * - * Since: 3.0 - */ - properties[PROP_FILENAME] = g_param_spec_string( - "filename", NULL, NULL, - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - /** - * PurpleAvatar:pixbuf: - * - * The [class@GdkPixbuf.Pixbuf] of the avatar. If - * [property@Purple.Avatar:animated] is %TRUE, this will be a static frame - * from the animation. - * - * Since: 3.0 - */ - properties[PROP_PIXBUF] = g_param_spec_object( - "pixbuf", NULL, NULL, - GDK_TYPE_PIXBUF, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - /** - * PurpleAvatar:animated: - * - * Whether or not this avatar is animated. - * - * Since: 3.0 - */ - properties[PROP_ANIMATED] = g_param_spec_boolean( - "animated", NULL, NULL, - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - /** - * PurpleAvatar:animation: - * - * The [class@GdkPixbuf.PixbufAnimation] if - * [property@Purple.Avatar:animated] is %TRUE. - * - * Since: 3.0 - */ - properties[PROP_ANIMATION] = g_param_spec_object( - "animation", NULL, NULL, - GDK_TYPE_PIXBUF_ANIMATION, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - /** - * PurpleAvatar:tags: - * - * The [class@Purple.Tags] for the avatar. - * - * Since: 3.0 - */ - properties[PROP_TAGS] = g_param_spec_object( - "tags", NULL, NULL, - PURPLE_TYPE_TAGS, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(obj_class, N_PROPERTIES, properties); -} - -/****************************************************************************** - * Public API - *****************************************************************************/ -PurpleAvatar * -purple_avatar_new_from_filename(const char *filename, GError **error) { - GdkPixbufAnimation *animation = NULL; - GError *local_error = NULL; - - g_return_val_if_fail(filename != NULL, NULL); - - animation = gdk_pixbuf_animation_new_from_file(filename, &local_error); - if(!GDK_IS_PIXBUF_ANIMATION(animation) || local_error != NULL) { - g_clear_object(&animation); - - g_propagate_error(error, local_error); - - return NULL; - } - - return purple_avatar_new_common(filename, animation); -} - -PurpleAvatar * -purple_avatar_new_from_resource(const char *resource_path, GError **error) { - GdkPixbufAnimation *animation = NULL; - GError *local_error = NULL; - - g_return_val_if_fail(resource_path != NULL, NULL); - - animation = gdk_pixbuf_animation_new_from_resource(resource_path, - &local_error); - if(!GDK_IS_PIXBUF_ANIMATION(animation) || local_error != NULL) { - g_clear_object(&animation); - - g_propagate_error(error, local_error); - - return NULL; - } - - return purple_avatar_new_common(NULL, animation); -} - -const char * -purple_avatar_get_filename(PurpleAvatar *avatar) { - g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); - - return avatar->filename; -} - -GdkPixbuf * -purple_avatar_get_pixbuf(PurpleAvatar *avatar) { - g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); - - if(avatar->animated) { - return gdk_pixbuf_animation_get_static_image(avatar->animation); - } - - return avatar->pixbuf; -} - -gboolean -purple_avatar_get_animated(PurpleAvatar *avatar) { - g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), FALSE); - - return avatar->animated; -} - -GdkPixbufAnimation * -purple_avatar_get_animation(PurpleAvatar *avatar) { - g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); - - return avatar->animation; -} - -PurpleTags * -purple_avatar_get_tags(PurpleAvatar *avatar) { - g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); - - return avatar->tags; -}
--- a/libpurple/purpleavatar.h Thu Aug 07 21:32:18 2025 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Purple - Internet Messaging Library - * Copyright (C) Pidgin Developers <devel@pidgin.im> - * - * Purple 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>. - */ - -#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION) -# error "only <purple.h> may be included directly" -#endif - -#ifndef PURPLE_AVATAR_H -#define PURPLE_AVATAR_H - -#include <glib.h> -#include <glib-object.h> - -#include <gdk-pixbuf/gdk-pixbuf.h> - -#include "purpletags.h" -#include "purpleversion.h" - -G_BEGIN_DECLS - -#define PURPLE_TYPE_AVATAR (purple_avatar_get_type()) - -PURPLE_AVAILABLE_IN_3_0 -G_DECLARE_FINAL_TYPE(PurpleAvatar, purple_avatar, PURPLE, AVATAR, GObject) - -/** - * PurpleAvatar: - * - * A representation of an Avatar that is used for accounts, contacts, and - * conversations. - * - * Since: 3.0 - */ - -/** - * purple_avatar_new_from_filename: - * @filename: The filename for the avatar. - * @error: Return address for a #GError, or %NULL. - * - * Creates a new avatar from @filename. - * - * Returns: (transfer full): The new instance. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -PurpleAvatar *purple_avatar_new_from_filename(const char *filename, GError **error); - -/** - * purple_avatar_new_from_resource: - * @resource_path: The path of the resource file. - * @error: Return address for a #GError, or %NULL. - * - * Creates a new avatar from the resource at @resource_path. - * - * Returns: (transfer full): The new instance. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -PurpleAvatar *purple_avatar_new_from_resource(const char *resource_path, GError **error); - -/** - * purple_avatar_get_filename: - * @avatar: The instance. - * - * Gets the base filename of @avatar. - * - * Returns: The base filename of @avatar. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -const char *purple_avatar_get_filename(PurpleAvatar *avatar); - -/** - * purple_avatar_get_pixbuf: - * @avatar: The instance. - * - * Gets the [class@GdkPixbuf.Pixbuf] of @avatar. - * - * If [property@Purple.Avatar:animated] is %TRUE, this returns a single frame - * of the animation. To get the animation see - * [method@Purple.Avatar.get_animation]. - * - * Returns: (transfer none): The pixbuf of the avatar which could be %NULL. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -GdkPixbuf *purple_avatar_get_pixbuf(PurpleAvatar *avatar); - -/** - * purple_avatar_get_animated: - * @avatar: The instance. - * - * Gets whether or not @avatar is animated. - * - * Returns: %TRUE if @avatar is animated, %FALSE otherwise. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -gboolean purple_avatar_get_animated(PurpleAvatar *avatar); - -/** - * purple_avatar_get_animation: - * @avatar: The instance. - * - * Gets the [class@GdkPixbuf.PixbufAnimation] if - * [property@Purple.Avatar:animated] is %TRUE, otherwise %NULL. - * - * Returns: (transfer none): The animation or %NULL. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -GdkPixbufAnimation *purple_avatar_get_animation(PurpleAvatar *avatar); - -/** - * purple_avatar_get_tags: - * @avatar: The instance. - * - * Gets the [class@Purple.Tags] for @avatar. - * - * Returns: (transfer none): The [class@Purple.Tags] for @avatar. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -PurpleTags *purple_avatar_get_tags(PurpleAvatar *avatar); - -G_END_DECLS - -#endif /* PURPLE_AVATAR_H */
--- a/libpurple/purplecontactinfo.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purplecontactinfo.c Thu Aug 07 21:34:33 2025 -0500 @@ -42,7 +42,7 @@ char *name_for_display; - PurpleAvatar *avatar; + PurpleImage *avatar; PurplePresence *presence; @@ -498,7 +498,7 @@ */ properties[PROP_AVATAR] = g_param_spec_object( "avatar", NULL, NULL, - PURPLE_TYPE_AVATAR, + PURPLE_TYPE_IMAGE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** @@ -947,7 +947,7 @@ } } -PurpleAvatar * +PurpleImage * purple_contact_info_get_avatar(PurpleContactInfo *info) { PurpleContactInfoPrivate *priv = NULL; @@ -959,7 +959,7 @@ } void -purple_contact_info_set_avatar(PurpleContactInfo *info, PurpleAvatar *avatar) { +purple_contact_info_set_avatar(PurpleContactInfo *info, PurpleImage *avatar) { PurpleContactInfoPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_CONTACT_INFO(info));
--- a/libpurple/purplecontactinfo.h Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purplecontactinfo.h Thu Aug 07 21:34:33 2025 -0500 @@ -32,7 +32,7 @@ #include <birb.h> -#include "purpleavatar.h" +#include "purpleimage.h" #include "purplepresence.h" #include "purpletags.h" #include "purpleversion.h" @@ -356,7 +356,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -PurpleAvatar *purple_contact_info_get_avatar(PurpleContactInfo *info); +PurpleImage *purple_contact_info_get_avatar(PurpleContactInfo *info); /** * purple_contact_info_set_avatar: @@ -371,7 +371,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -void purple_contact_info_set_avatar(PurpleContactInfo *info, PurpleAvatar *avatar); +void purple_contact_info_set_avatar(PurpleContactInfo *info, PurpleImage *avatar); /** * purple_contact_info_get_presence:
--- a/libpurple/purpleconversation.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purpleconversation.c Thu Aug 07 21:34:33 2025 -0500 @@ -43,7 +43,7 @@ PurpleAccount *account; gboolean avatar_editable; - PurpleAvatar *avatar; + PurpleImage *avatar; char *alias; @@ -917,7 +917,7 @@ /** * PurpleConversation:avatar: * - * The [class@Avatar] for the conversation. + * The avatar for the conversation. * * Not all protocols support this and most user interfaces will use the * avatar of the remote contact for direct messages. @@ -926,7 +926,7 @@ */ properties[PROP_AVATAR] = g_param_spec_object( "avatar", NULL, NULL, - PURPLE_TYPE_AVATAR, + PURPLE_TYPE_IMAGE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** @@ -2011,7 +2011,7 @@ return NULL; } -PurpleAvatar * +PurpleImage * purple_conversation_get_avatar(PurpleConversation *conversation) { g_return_val_if_fail(PURPLE_IS_CONVERSATION(conversation), NULL); @@ -2020,7 +2020,7 @@ void purple_conversation_set_avatar(PurpleConversation *conversation, - PurpleAvatar *avatar) + PurpleImage *avatar) { g_return_if_fail(PURPLE_IS_CONVERSATION(conversation));
--- a/libpurple/purpleconversation.h Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purpleconversation.h Thu Aug 07 21:34:33 2025 -0500 @@ -30,6 +30,7 @@ #include <glib.h> #include <glib-object.h> +#include "purpleimage.h" #include "purpleconversationmembers.h" #include "purpletyping.h" #include "purpleversion.h" @@ -51,7 +52,6 @@ G_DECLARE_FINAL_TYPE(PurpleConversation, purple_conversation, PURPLE, CONVERSATION, GObject) -#include "purpleavatar.h" #include "purplecontactinfo.h" #include "purpleconversationmember.h" #include "purplemessage.h" @@ -789,7 +789,7 @@ * purple_conversation_get_avatar: * @conversation: The instance. * - * Gets the [class@Avatar] from @conversation if set. + * Gets the avatar for the conversation. * * > Note: Not all protocols support this and user interfaces generally use * the avatar of a contact info for a direct message. @@ -799,7 +799,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -PurpleAvatar *purple_conversation_get_avatar(PurpleConversation *conversation); +PurpleImage *purple_conversation_get_avatar(PurpleConversation *conversation); /** * purple_conversation_set_avatar: @@ -814,7 +814,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -void purple_conversation_set_avatar(PurpleConversation *conversation, PurpleAvatar *avatar); +void purple_conversation_set_avatar(PurpleConversation *conversation, PurpleImage *avatar); /** * purple_conversation_get_avatar_editable:
--- a/libpurple/purpleperson.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purpleperson.c Thu Aug 07 21:34:33 2025 -0500 @@ -32,7 +32,7 @@ char *id; gchar *alias; - PurpleAvatar *avatar; + PurpleImage *avatar; char *color; PurpleTags *tags; @@ -117,8 +117,8 @@ /* See if the priority contact changed. */ if(original_priority != new_priority) { - PurpleAvatar *old_avatar = NULL; - PurpleAvatar *new_avatar = NULL; + PurpleImage *old_avatar = NULL; + PurpleImage *new_avatar = NULL; GObject *obj = G_OBJECT(person); const char *old_color = NULL; const char *new_color = NULL; @@ -158,7 +158,7 @@ /* If the person doesn't have an avatar set, check if the avatar * changed and notify if it has. */ - if(!PURPLE_IS_AVATAR(person->avatar)) { + if(!PURPLE_IS_IMAGE(person->avatar)) { if(old_avatar != new_avatar) { g_object_notify_by_pspec(obj, properties[PROP_AVATAR_FOR_DISPLAY]); } @@ -471,7 +471,7 @@ */ properties[PROP_AVATAR] = g_param_spec_object( "avatar", NULL, NULL, - PURPLE_TYPE_AVATAR, + PURPLE_TYPE_IMAGE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** @@ -486,7 +486,7 @@ */ properties[PROP_AVATAR_FOR_DISPLAY] = g_param_spec_object( "avatar-for-display", NULL, NULL, - PURPLE_TYPE_AVATAR, + PURPLE_TYPE_IMAGE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); /** @@ -605,13 +605,13 @@ } } -PurpleAvatar * +PurpleImage * purple_person_get_avatar_for_display(PurplePerson *person) { PurpleContactInfo *priority = NULL; g_return_val_if_fail(PURPLE_IS_PERSON(person), NULL); - if(PURPLE_IS_AVATAR(person->avatar)) { + if(PURPLE_IS_IMAGE(person->avatar)) { return person->avatar; } @@ -623,7 +623,7 @@ return NULL; } -PurpleAvatar * +PurpleImage * purple_person_get_avatar(PurplePerson *person) { g_return_val_if_fail(PURPLE_IS_PERSON(person), NULL); @@ -631,7 +631,7 @@ } void -purple_person_set_avatar(PurplePerson *person, PurpleAvatar *avatar) { +purple_person_set_avatar(PurplePerson *person, PurpleImage *avatar) { g_return_if_fail(PURPLE_IS_PERSON(person)); if(g_set_object(&person->avatar, avatar)) {
--- a/libpurple/purpleperson.h Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purpleperson.h Thu Aug 07 21:34:33 2025 -0500 @@ -30,7 +30,7 @@ #include <glib.h> #include <glib-object.h> -#include "purpleavatar.h" +#include "purpleimage.h" #include "purpletags.h" #include "purpleversion.h" @@ -124,7 +124,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -PurpleAvatar *purple_person_get_avatar_for_display(PurplePerson *person); +PurpleImage *purple_person_get_avatar_for_display(PurplePerson *person); /** * purple_person_get_avatar: @@ -137,7 +137,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -PurpleAvatar *purple_person_get_avatar(PurplePerson *person); +PurpleImage *purple_person_get_avatar(PurplePerson *person); /** * purple_person_set_avatar: @@ -154,7 +154,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -void purple_person_set_avatar(PurplePerson *person, PurpleAvatar *avatar); +void purple_person_set_avatar(PurplePerson *person, PurpleImage *avatar); /** * purple_person_get_color:
--- a/libpurple/purpleprotocolconversation.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purpleprotocolconversation.c Thu Aug 07 21:34:33 2025 -0500 @@ -456,7 +456,7 @@ void purple_protocol_conversation_set_avatar_async(PurpleProtocolConversation *protocol, PurpleConversation *conversation, - PurpleAvatar *avatar, + PurpleImage *avatar, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
--- a/libpurple/purpleprotocolconversation.h Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/purpleprotocolconversation.h Thu Aug 07 21:34:33 2025 -0500 @@ -31,10 +31,10 @@ #include <glib-object.h> #include "purpleaccount.h" -#include "purpleavatar.h" #include "purplechanneljoindetails.h" #include "purpleconversation.h" #include "purplecreateconversationdetails.h" +#include "purpleimage.h" #include "purplemessage.h" #include "purpleprotocol.h" #include "purpletyping.h" @@ -90,7 +90,7 @@ void (*join_channel_async)(PurpleProtocolConversation *protocol, PurpleAccount *account, PurpleChannelJoinDetails *details, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data); PurpleConversation *(*join_channel_finish)(PurpleProtocolConversation *protocol, GAsyncResult *result, GError **error); - void (*set_avatar_async)(PurpleProtocolConversation *protocol, PurpleConversation *conversation, PurpleAvatar *avatar, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data); + void (*set_avatar_async)(PurpleProtocolConversation *protocol, PurpleConversation *conversation, PurpleImage *avatar, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data); gboolean (*set_avatar_finish)(PurpleProtocolConversation *protocol, GAsyncResult *result, GError **error); void (*send_typing)(PurpleProtocolConversation *protocol, PurpleConversation *conversation, PurpleTypingState state); @@ -437,7 +437,7 @@ * Since: 3.0 */ PURPLE_AVAILABLE_IN_3_0 -void purple_protocol_conversation_set_avatar_async(PurpleProtocolConversation *protocol, PurpleConversation *conversation, PurpleAvatar *avatar, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data); +void purple_protocol_conversation_set_avatar_async(PurpleProtocolConversation *protocol, PurpleConversation *conversation, PurpleImage *avatar, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data); /** * purple_protocol_conversation_set_avatar_finish:
--- a/libpurple/tests/avatar/meson.build Thu Aug 07 21:32:18 2025 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -TEST_PURPLE_AVATAR_SOURCES = [ - 'test_purple_avatar.c' -] - -TEST_PURPLE_AVATAR_RESOURCES = gnome.compile_resources( - 'test_purple_avatar_resources', - 'test_purple_avatar.gresource.xml', - source_dir : '.', - c_name : 'test_purple_avatar') -TEST_PURPLE_AVATAR_SOURCES += TEST_PURPLE_AVATAR_RESOURCES - -test_purple_avatar = executable( - 'test_purple_avatar', - TEST_PURPLE_AVATAR_SOURCES, - dependencies : [libpurple_dep, glib, gdk_pixbuf]) - -test('avatar', test_purple_avatar)
--- a/libpurple/tests/avatar/test_purple_avatar.c Thu Aug 07 21:32:18 2025 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Purple - Internet Messaging Library - * Copyright (C) Pidgin Developers <devel@pidgin.im> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <https://www.gnu.org/licenses/>. - */ - -#include <glib.h> - -#include <purple.h> - -/****************************************************************************** - * Tests - *****************************************************************************/ -static void -test_purple_avatar_new_static(void) { - PurpleAvatar *avatar = NULL; - GdkPixbuf *pixbuf = NULL; - GError *error = NULL; - const char *resource = "/im/pidgin/libpurple/tests/avatar/static.png"; - - avatar = purple_avatar_new_from_resource(resource, &error); - g_assert_no_error(error); - g_assert_true(PURPLE_IS_AVATAR(avatar)); - - g_assert_null(purple_avatar_get_filename(avatar)); - g_assert_false(purple_avatar_get_animated(avatar)); - g_assert_null(purple_avatar_get_animation(avatar)); - - pixbuf = purple_avatar_get_pixbuf(avatar); - g_assert_true(GDK_IS_PIXBUF(pixbuf)); - - g_clear_object(&avatar); -} - -static void -test_purple_avatar_new_animated(void) { - PurpleAvatar *avatar = NULL; - GdkPixbuf *pixbuf = NULL; - GdkPixbufAnimation *animation = NULL; - GError *error = NULL; - const char *resource = "/im/pidgin/libpurple/tests/avatar/animated.gif"; - - avatar = purple_avatar_new_from_resource(resource, &error); - g_assert_no_error(error); - g_assert_true(PURPLE_IS_AVATAR(avatar)); - - g_assert_null(purple_avatar_get_filename(avatar)); - g_assert_true(purple_avatar_get_animated(avatar)); - - pixbuf = purple_avatar_get_pixbuf(avatar); - g_assert_true(GDK_IS_PIXBUF(pixbuf)); - - animation = purple_avatar_get_animation(avatar); - g_assert_true(GDK_IS_PIXBUF_ANIMATION(animation)); - - g_clear_object(&avatar); -} - -/****************************************************************************** - * Main - *****************************************************************************/ -gint -main(gint argc, gchar *argv[]) { - g_test_init(&argc, &argv, NULL); - - g_test_add_func("/avatar/new/static", - test_purple_avatar_new_static); - g_test_add_func("/avatar/new/animated", - test_purple_avatar_new_animated); - - return g_test_run(); -}
--- a/libpurple/tests/avatar/test_purple_avatar.gresource.xml Thu Aug 07 21:32:18 2025 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<gresources> - <gresource prefix="/im/pidgin/libpurple/tests/avatar/"> - <file>static.png</file> - <file>animated.gif</file> - </gresource> -</gresources>
--- a/libpurple/tests/meson.build Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/tests/meson.build Thu Aug 07 21:34:33 2025 -0500 @@ -88,5 +88,4 @@ ) endforeach -subdir('avatar') subdir('image')
--- a/libpurple/tests/test_contact_info.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/tests/test_contact_info.c Thu Aug 07 21:34:33 2025 -0500 @@ -38,10 +38,10 @@ static void test_purple_contact_info_properties(void) { - PurpleAvatar *avatar = NULL; - PurpleAvatar *avatar1 = NULL; PurpleContactInfo *info = NULL; PurpleContactInfoPermission permission; + PurpleImage *avatar = NULL; + PurpleImage *avatar1 = NULL; PurplePerson *person = NULL; PurplePerson *person1 = NULL; PurplePresence *presence1 = NULL; @@ -61,7 +61,7 @@ gboolean external = FALSE; gboolean favorite = FALSE; - avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL); + avatar = g_object_new(PURPLE_TYPE_IMAGE, NULL); person = purple_person_new(); time_zone = g_time_zone_new_utc();
--- a/libpurple/tests/test_conversation.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/tests/test_conversation.c Thu Aug 07 21:34:33 2025 -0500 @@ -44,14 +44,14 @@ test_purple_conversation_properties(void) { PurpleAccount *account = NULL; PurpleAccount *account1 = NULL; - PurpleAvatar *avatar = NULL; - PurpleAvatar *avatar1 = NULL; PurpleContactInfo *creator = NULL; PurpleContactInfo *creator1 = NULL; PurpleContactInfo *topic_author = NULL; PurpleContactInfo *topic_author1 = NULL; PurpleConversation *conversation = NULL; PurpleConversationType type = PURPLE_CONVERSATION_TYPE_UNSET; + PurpleImage *avatar = NULL; + PurpleImage *avatar1 = NULL; PurpleTags *tags = NULL; PurpleTypingState typing_state; GDateTime *created_on = NULL; @@ -86,7 +86,7 @@ "protocol-id", "test", NULL); - avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL); + avatar = g_object_new(PURPLE_TYPE_IMAGE, NULL); creator = purple_contact_info_new(NULL); created_on = g_date_time_new_now_utc(); error = g_error_new(g_quark_from_static_string("test-conversation"), 0,
--- a/libpurple/tests/test_person.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/tests/test_person.c Thu Aug 07 21:34:33 2025 -0500 @@ -38,9 +38,9 @@ static void test_purple_person_properties(void) { - PurpleAvatar *avatar = NULL; - PurpleAvatar *avatar1 = NULL; - PurpleAvatar *avatar_for_display = NULL; + PurpleImage *avatar = NULL; + PurpleImage *avatar1 = NULL; + PurpleImage *avatar_for_display = NULL; PurpleContact *person = NULL; PurpleTags *tags = NULL; char *id = NULL; @@ -50,7 +50,7 @@ char *name_for_display = NULL; /* Create our avatar for testing. */ - avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL); + avatar = g_object_new(PURPLE_TYPE_IMAGE, NULL); /* Use g_object_new so we can test setting properties by name. All of them * call the setter methods, so by doing it this way we exercise more of the @@ -107,7 +107,7 @@ static void test_purple_person_avatar_for_display_person(void) { - PurpleAvatar *avatar = NULL; + PurpleImage *avatar = NULL; PurpleContactInfo *info = NULL; PurplePerson *person = NULL; guint avatar_counter = 0; @@ -117,7 +117,7 @@ birb_count_property_changed(G_OBJECT(person), "avatar", &avatar_counter); birb_count_property_changed(G_OBJECT(person), "avatar-for-display", &avatar_for_display_counter); - avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL); + avatar = g_object_new(PURPLE_TYPE_IMAGE, NULL); purple_person_set_avatar(person, avatar); g_assert_cmpuint(avatar_counter, ==, 1); g_assert_cmpuint(avatar_for_display_counter, ==, 1); @@ -140,7 +140,7 @@ static void test_purple_person_avatar_for_display_contact(void) { - PurpleAvatar *avatar = NULL; + PurpleImage *avatar = NULL; PurpleContactInfo *info = NULL; PurplePerson *person = NULL; guint counter = 0; @@ -150,7 +150,7 @@ &counter); info = purple_contact_info_new("id"); - avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL); + avatar = g_object_new(PURPLE_TYPE_IMAGE, NULL); purple_contact_info_set_avatar(info, avatar); purple_person_add_contact_info(person, info); @@ -164,7 +164,7 @@ * of the property changing. */ counter = 0; - avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL); + avatar = g_object_new(PURPLE_TYPE_IMAGE, NULL); purple_contact_info_set_avatar(info, avatar); g_assert_cmpuint(counter, ==, 1);
--- a/libpurple/tests/test_protocol_conversation.c Thu Aug 07 21:32:18 2025 -0500 +++ b/libpurple/tests/test_protocol_conversation.c Thu Aug 07 21:34:33 2025 -0500 @@ -929,7 +929,7 @@ static void test_purple_protocol_conversation_set_avatar_async(PurpleProtocolConversation *protocol, PurpleConversation *conversation, - G_GNUC_UNUSED PurpleAvatar *avatar, + G_GNUC_UNUSED PurpleImage *avatar, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data)
--- a/pidgin/pidginavatar.c Thu Aug 07 21:32:18 2025 -0500 +++ b/pidgin/pidginavatar.c Thu Aug 07 21:34:33 2025 -0500 @@ -53,9 +53,7 @@ *****************************************************************************/ static void pidgin_avatar_update(PidginAvatar *avatar) { - PurpleAvatar *purple_avatar = NULL; - GdkPixbufAnimation *animation = NULL; - GdkPixbuf *pixbuf = NULL; + PurpleImage *purple_avatar = NULL; GdkTexture *texture = NULL; if(PURPLE_IS_CONTACT_INFO(avatar->info)) { @@ -64,27 +62,24 @@ purple_avatar = purple_conversation_get_avatar(avatar->conversation); } - if(PURPLE_IS_AVATAR(purple_avatar)) { - animation = purple_avatar_get_animation(purple_avatar); - } - - g_set_object(&avatar->animation, animation); + if(PURPLE_IS_IMAGE(purple_avatar)) { + GBytes *contents = NULL; + GError *error = NULL; - if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) { - if(avatar->animate && - !gdk_pixbuf_animation_is_static_image(avatar->animation)) { - pixbuf = GDK_PIXBUF(avatar->animation); - } else { - pixbuf = gdk_pixbuf_animation_get_static_image(avatar->animation); + contents = purple_image_get_contents(purple_avatar); + texture = gdk_texture_new_from_bytes(contents, &error); + if(error != NULL) { + g_warning("failed to create texture from bytes: %s", + error->message); + g_clear_error(&error); + texture = NULL; } } - texture = gdk_texture_new_for_pixbuf(pixbuf); gtk_picture_set_paintable(GTK_PICTURE(avatar->icon), GDK_PAINTABLE(texture)); g_clear_object(&texture); - g_clear_object(&animation); } /******************************************************************************
--- a/pidgin/pidginavatar.h Thu Aug 07 21:32:18 2025 -0500 +++ b/pidgin/pidginavatar.h Thu Aug 07 21:34:33 2025 -0500 @@ -122,7 +122,7 @@ * @conversation: (nullable): The conversation to set or %NULL to unset. * * Sets or unsets the conversation that @avatar uses to find the - * [class@Purple.Avatar] to display. + * [class@Purple.Image] to display. * * Since: 3.0 */ @@ -136,7 +136,7 @@ * Gets the #PurpleConversation that @avatar is using for display. * * Returns: (transfer none): The conversation that @avatar is using to - * find the [class@Purple.Avatar] to display. + * find the [class@Purple.Image] to display. * * Since: 3.0 */
--- a/pidgin/pidgincontactlist.c Thu Aug 07 21:32:18 2025 -0500 +++ b/pidgin/pidgincontactlist.c Thu Aug 07 21:34:33 2025 -0500 @@ -169,7 +169,7 @@ PurplePerson *person, G_GNUC_UNUSED gpointer data) { - PurpleAvatar *avatar = NULL; + PurpleImage *avatar = NULL; PurpleContactInfo *info = NULL; /* When filtering we get called for rows that have been filtered out. We @@ -186,11 +186,22 @@ } avatar = purple_person_get_avatar_for_display(person); - if(PURPLE_IS_AVATAR(avatar)) { - GdkPixbuf *pixbuf = purple_avatar_get_pixbuf(avatar); + if(PURPLE_IS_IMAGE(avatar)) { + GBytes *contents = purple_image_get_contents(avatar); + + if(contents != NULL) { + GdkTexture *texture = NULL; + GError *error = NULL; - if(GDK_IS_PIXBUF(pixbuf)) { - return gdk_texture_new_for_pixbuf(pixbuf); + texture = gdk_texture_new_from_bytes(contents, &error); + if(error != NULL) { + g_warning("failed to create texture: %s", error->message); + g_clear_error(&error); + + return NULL; + } + + return texture; } }
--- a/po/POTFILES.in Thu Aug 07 21:32:18 2025 -0500 +++ b/po/POTFILES.in Thu Aug 07 21:34:33 2025 -0500 @@ -36,7 +36,6 @@ libpurple/purpleaddcontactrequest.c libpurple/purpleattachment.c libpurple/purpleauthorizationrequest.c -libpurple/purpleavatar.c libpurple/purplebadge.c libpurple/purplebadgemanager.c libpurple/purplebadges.c
--- a/protocols/demo/purpledemocontacts.c Thu Aug 07 21:32:18 2025 -0500 +++ b/protocols/demo/purpledemocontacts.c Thu Aug 07 21:34:33 2025 -0500 @@ -29,13 +29,13 @@ purple_demo_contacts_load_contact_icon(PurpleContactInfo *info, const char *name) { - PurpleAvatar *avatar = NULL; + PurpleImage *avatar = NULL; GError *error = NULL; char *path = NULL; path = g_strdup_printf("/im/pidgin/libpurple/protocols/demo/buddy_icons/%s.png", name); - avatar = purple_avatar_new_from_resource(path, &error); + avatar = purple_image_new_from_resource(path, &error); if(error != NULL) { g_message("Failed to load find an icon for %s: %s", path, @@ -49,7 +49,7 @@ g_free(path); - if(PURPLE_IS_AVATAR(avatar)) { + if(PURPLE_IS_IMAGE(avatar)) { purple_contact_info_set_avatar(info, avatar); g_clear_object(&avatar);