| 1 /* |
|
| 2 * Purple - Internet Messaging Library |
|
| 3 * Copyright (C) Pidgin Developers <devel@pidgin.im> |
|
| 4 * |
|
| 5 * Purple is the legal property of its developers, whose names are too numerous |
|
| 6 * to list here. Please refer to the COPYRIGHT file distributed with this |
|
| 7 * source distribution. |
|
| 8 * |
|
| 9 * This library is free software; you can redistribute it and/or modify it |
|
| 10 * under the terms of the GNU General Public License as published by the Free |
|
| 11 * Software Foundation; either version 2 of the License, or (at your option) |
|
| 12 * any later version. |
|
| 13 * |
|
| 14 * This library is distributed in the hope that it will be useful, but WITHOUT |
|
| 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
| 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|
| 17 * more details. |
|
| 18 * |
|
| 19 * You should have received a copy of the GNU General Public License along with |
|
| 20 * this library; if not, see <https://www.gnu.org/licenses/>. |
|
| 21 */ |
|
| 22 |
|
| 23 #include "purpleavatar.h" |
|
| 24 |
|
| 25 struct _PurpleAvatar { |
|
| 26 GObject parent; |
|
| 27 |
|
| 28 char *filename; |
|
| 29 |
|
| 30 GdkPixbuf *pixbuf; |
|
| 31 |
|
| 32 gboolean animated; |
|
| 33 GdkPixbufAnimation *animation; |
|
| 34 |
|
| 35 PurpleTags *tags; |
|
| 36 }; |
|
| 37 |
|
| 38 enum { |
|
| 39 PROP_0, |
|
| 40 PROP_FILENAME, |
|
| 41 PROP_PIXBUF, |
|
| 42 PROP_ANIMATED, |
|
| 43 PROP_ANIMATION, |
|
| 44 PROP_TAGS, |
|
| 45 N_PROPERTIES, |
|
| 46 }; |
|
| 47 static GParamSpec *properties[N_PROPERTIES] = {NULL, }; |
|
| 48 |
|
| 49 /****************************************************************************** |
|
| 50 * Helpers |
|
| 51 *****************************************************************************/ |
|
| 52 static void |
|
| 53 purple_avatar_set_filename(PurpleAvatar *avatar, const char *filename) { |
|
| 54 g_return_if_fail(PURPLE_IS_AVATAR(avatar)); |
|
| 55 |
|
| 56 if(g_set_str(&avatar->filename, filename)) { |
|
| 57 g_object_notify_by_pspec(G_OBJECT(avatar), properties[PROP_FILENAME]); |
|
| 58 } |
|
| 59 } |
|
| 60 |
|
| 61 static PurpleAvatar * |
|
| 62 purple_avatar_new_common(const char *filename, GdkPixbufAnimation *animation) { |
|
| 63 PurpleAvatar *avatar = NULL; |
|
| 64 |
|
| 65 avatar = g_object_new(PURPLE_TYPE_AVATAR, "filename", filename, NULL); |
|
| 66 |
|
| 67 if(gdk_pixbuf_animation_is_static_image(animation)) { |
|
| 68 /* If we loaded a static image, grab the static image and set it to our |
|
| 69 * pixbuf member, clear the animation, and return the new avatar. |
|
| 70 */ |
|
| 71 |
|
| 72 avatar->pixbuf = gdk_pixbuf_animation_get_static_image(animation); |
|
| 73 g_object_ref(avatar->pixbuf); |
|
| 74 |
|
| 75 g_clear_object(&animation); |
|
| 76 } else { |
|
| 77 /* If we did load an animation, set the appropriate properties and |
|
| 78 * return the avatar. |
|
| 79 */ |
|
| 80 avatar->animated = TRUE; |
|
| 81 avatar->animation = animation; |
|
| 82 } |
|
| 83 |
|
| 84 return avatar; |
|
| 85 } |
|
| 86 |
|
| 87 /****************************************************************************** |
|
| 88 * GObject Implementation |
|
| 89 *****************************************************************************/ |
|
| 90 G_DEFINE_FINAL_TYPE(PurpleAvatar, purple_avatar, G_TYPE_OBJECT) |
|
| 91 |
|
| 92 static void |
|
| 93 purple_avatar_get_property(GObject *obj, guint param_id, GValue *value, |
|
| 94 GParamSpec *pspec) |
|
| 95 { |
|
| 96 PurpleAvatar *avatar = PURPLE_AVATAR(obj); |
|
| 97 |
|
| 98 switch(param_id) { |
|
| 99 case PROP_FILENAME: |
|
| 100 g_value_set_string(value, purple_avatar_get_filename(avatar)); |
|
| 101 break; |
|
| 102 case PROP_PIXBUF: |
|
| 103 g_value_set_object(value, purple_avatar_get_pixbuf(avatar)); |
|
| 104 break; |
|
| 105 case PROP_ANIMATED: |
|
| 106 g_value_set_boolean(value, purple_avatar_get_animated(avatar)); |
|
| 107 break; |
|
| 108 case PROP_ANIMATION: |
|
| 109 g_value_set_object(value, purple_avatar_get_animation(avatar)); |
|
| 110 break; |
|
| 111 case PROP_TAGS: |
|
| 112 g_value_set_object(value, purple_avatar_get_tags(avatar)); |
|
| 113 break; |
|
| 114 default: |
|
| 115 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); |
|
| 116 break; |
|
| 117 } |
|
| 118 } |
|
| 119 |
|
| 120 static void |
|
| 121 purple_avatar_set_property(GObject *obj, guint param_id, const GValue *value, |
|
| 122 GParamSpec *pspec) |
|
| 123 { |
|
| 124 PurpleAvatar *avatar = PURPLE_AVATAR(obj); |
|
| 125 |
|
| 126 switch(param_id) { |
|
| 127 case PROP_FILENAME: |
|
| 128 purple_avatar_set_filename(avatar, g_value_get_string(value)); |
|
| 129 break; |
|
| 130 default: |
|
| 131 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); |
|
| 132 break; |
|
| 133 } |
|
| 134 } |
|
| 135 |
|
| 136 static void |
|
| 137 purple_avatar_finalize(GObject *obj) { |
|
| 138 PurpleAvatar *avatar = PURPLE_AVATAR(obj); |
|
| 139 |
|
| 140 g_clear_pointer(&avatar->filename, g_free); |
|
| 141 g_clear_object(&avatar->pixbuf); |
|
| 142 g_clear_object(&avatar->animation); |
|
| 143 g_clear_object(&avatar->tags); |
|
| 144 |
|
| 145 G_OBJECT_CLASS(purple_avatar_parent_class)->finalize(obj); |
|
| 146 } |
|
| 147 |
|
| 148 static void |
|
| 149 purple_avatar_init(PurpleAvatar *avatar) { |
|
| 150 avatar->tags = purple_tags_new(); |
|
| 151 } |
|
| 152 |
|
| 153 static void |
|
| 154 purple_avatar_class_init(PurpleAvatarClass *klass) { |
|
| 155 GObjectClass *obj_class = G_OBJECT_CLASS(klass); |
|
| 156 |
|
| 157 obj_class->finalize = purple_avatar_finalize; |
|
| 158 obj_class->get_property = purple_avatar_get_property; |
|
| 159 obj_class->set_property = purple_avatar_set_property; |
|
| 160 |
|
| 161 /** |
|
| 162 * PurpleAvatar:filename: |
|
| 163 * |
|
| 164 * The filename that this avatar was created from. |
|
| 165 * |
|
| 166 * Since: 3.0 |
|
| 167 */ |
|
| 168 properties[PROP_FILENAME] = g_param_spec_string( |
|
| 169 "filename", NULL, NULL, |
|
| 170 NULL, |
|
| 171 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); |
|
| 172 |
|
| 173 /** |
|
| 174 * PurpleAvatar:pixbuf: |
|
| 175 * |
|
| 176 * The [class@GdkPixbuf.Pixbuf] of the avatar. If |
|
| 177 * [property@Purple.Avatar:animated] is %TRUE, this will be a static frame |
|
| 178 * from the animation. |
|
| 179 * |
|
| 180 * Since: 3.0 |
|
| 181 */ |
|
| 182 properties[PROP_PIXBUF] = g_param_spec_object( |
|
| 183 "pixbuf", NULL, NULL, |
|
| 184 GDK_TYPE_PIXBUF, |
|
| 185 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
| 186 |
|
| 187 /** |
|
| 188 * PurpleAvatar:animated: |
|
| 189 * |
|
| 190 * Whether or not this avatar is animated. |
|
| 191 * |
|
| 192 * Since: 3.0 |
|
| 193 */ |
|
| 194 properties[PROP_ANIMATED] = g_param_spec_boolean( |
|
| 195 "animated", NULL, NULL, |
|
| 196 FALSE, |
|
| 197 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
| 198 |
|
| 199 /** |
|
| 200 * PurpleAvatar:animation: |
|
| 201 * |
|
| 202 * The [class@GdkPixbuf.PixbufAnimation] if |
|
| 203 * [property@Purple.Avatar:animated] is %TRUE. |
|
| 204 * |
|
| 205 * Since: 3.0 |
|
| 206 */ |
|
| 207 properties[PROP_ANIMATION] = g_param_spec_object( |
|
| 208 "animation", NULL, NULL, |
|
| 209 GDK_TYPE_PIXBUF_ANIMATION, |
|
| 210 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
| 211 |
|
| 212 /** |
|
| 213 * PurpleAvatar:tags: |
|
| 214 * |
|
| 215 * The [class@Purple.Tags] for the avatar. |
|
| 216 * |
|
| 217 * Since: 3.0 |
|
| 218 */ |
|
| 219 properties[PROP_TAGS] = g_param_spec_object( |
|
| 220 "tags", NULL, NULL, |
|
| 221 PURPLE_TYPE_TAGS, |
|
| 222 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); |
|
| 223 |
|
| 224 g_object_class_install_properties(obj_class, N_PROPERTIES, properties); |
|
| 225 } |
|
| 226 |
|
| 227 /****************************************************************************** |
|
| 228 * Public API |
|
| 229 *****************************************************************************/ |
|
| 230 PurpleAvatar * |
|
| 231 purple_avatar_new_from_filename(const char *filename, GError **error) { |
|
| 232 GdkPixbufAnimation *animation = NULL; |
|
| 233 GError *local_error = NULL; |
|
| 234 |
|
| 235 g_return_val_if_fail(filename != NULL, NULL); |
|
| 236 |
|
| 237 animation = gdk_pixbuf_animation_new_from_file(filename, &local_error); |
|
| 238 if(!GDK_IS_PIXBUF_ANIMATION(animation) || local_error != NULL) { |
|
| 239 g_clear_object(&animation); |
|
| 240 |
|
| 241 g_propagate_error(error, local_error); |
|
| 242 |
|
| 243 return NULL; |
|
| 244 } |
|
| 245 |
|
| 246 return purple_avatar_new_common(filename, animation); |
|
| 247 } |
|
| 248 |
|
| 249 PurpleAvatar * |
|
| 250 purple_avatar_new_from_resource(const char *resource_path, GError **error) { |
|
| 251 GdkPixbufAnimation *animation = NULL; |
|
| 252 GError *local_error = NULL; |
|
| 253 |
|
| 254 g_return_val_if_fail(resource_path != NULL, NULL); |
|
| 255 |
|
| 256 animation = gdk_pixbuf_animation_new_from_resource(resource_path, |
|
| 257 &local_error); |
|
| 258 if(!GDK_IS_PIXBUF_ANIMATION(animation) || local_error != NULL) { |
|
| 259 g_clear_object(&animation); |
|
| 260 |
|
| 261 g_propagate_error(error, local_error); |
|
| 262 |
|
| 263 return NULL; |
|
| 264 } |
|
| 265 |
|
| 266 return purple_avatar_new_common(NULL, animation); |
|
| 267 } |
|
| 268 |
|
| 269 const char * |
|
| 270 purple_avatar_get_filename(PurpleAvatar *avatar) { |
|
| 271 g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); |
|
| 272 |
|
| 273 return avatar->filename; |
|
| 274 } |
|
| 275 |
|
| 276 GdkPixbuf * |
|
| 277 purple_avatar_get_pixbuf(PurpleAvatar *avatar) { |
|
| 278 g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); |
|
| 279 |
|
| 280 if(avatar->animated) { |
|
| 281 return gdk_pixbuf_animation_get_static_image(avatar->animation); |
|
| 282 } |
|
| 283 |
|
| 284 return avatar->pixbuf; |
|
| 285 } |
|
| 286 |
|
| 287 gboolean |
|
| 288 purple_avatar_get_animated(PurpleAvatar *avatar) { |
|
| 289 g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), FALSE); |
|
| 290 |
|
| 291 return avatar->animated; |
|
| 292 } |
|
| 293 |
|
| 294 GdkPixbufAnimation * |
|
| 295 purple_avatar_get_animation(PurpleAvatar *avatar) { |
|
| 296 g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); |
|
| 297 |
|
| 298 return avatar->animation; |
|
| 299 } |
|
| 300 |
|
| 301 PurpleTags * |
|
| 302 purple_avatar_get_tags(PurpleAvatar *avatar) { |
|
| 303 g_return_val_if_fail(PURPLE_IS_AVATAR(avatar), NULL); |
|
| 304 |
|
| 305 return avatar->tags; |
|
| 306 } |
|