pidgin/pidginavatar.c

changeset 41628
90f3621f94a5
parent 41600
5fbe92363b76
child 41733
a9085b52de8b
equal deleted inserted replaced
41627:7d9b4a9d5c3e 41628:90f3621f94a5
46 static GParamSpec *properties[N_PROPERTIES] = {NULL, }; 46 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
47 47
48 G_DEFINE_TYPE(PidginAvatar, pidgin_avatar, GTK_TYPE_BOX) 48 G_DEFINE_TYPE(PidginAvatar, pidgin_avatar, GTK_TYPE_BOX)
49 49
50 /****************************************************************************** 50 /******************************************************************************
51 * Helpers
52 *****************************************************************************/
53 static PurpleBuddy *
54 pidgin_avatar_get_effective_buddy(PidginAvatar *avatar) {
55 PurpleBuddy *buddy = NULL;
56
57 if(PURPLE_IS_BUDDY(avatar->buddy)) {
58 buddy = PURPLE_BUDDY(avatar->buddy);
59
60 } else if(PURPLE_IS_IM_CONVERSATION(avatar->conversation)) {
61 PurpleAccount *account = NULL;
62 const gchar *name = NULL;
63
64 account = purple_conversation_get_account(avatar->conversation);
65
66 name = purple_conversation_get_name(avatar->conversation);
67 buddy = purple_blist_find_buddy(account, name);
68 }
69
70 return buddy;
71 }
72
73 static GdkPixbufAnimation *
74 pidgin_avatar_find_buddy_icon(PurpleBuddy *buddy,
75 PurpleConversation *conversation)
76 {
77 GdkPixbufAnimation *ret = NULL;
78 GInputStream *stream = NULL;
79 PurpleContact *contact = NULL;
80
81 g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
82
83 /* First check if our user has set a custom icon for this buddy. */
84 contact = purple_buddy_get_contact(buddy);
85 if(PURPLE_IS_CONTACT(contact)) {
86 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact);
87 PurpleImage *custom_image = NULL;
88
89 custom_image = purple_buddy_icons_node_find_custom_icon(node);
90 if(PURPLE_IS_IMAGE(custom_image)) {
91 gconstpointer data = purple_image_get_data(custom_image);
92 gsize length = purple_image_get_data_size(custom_image);
93
94 stream = g_memory_input_stream_new_from_data(data, (gssize)length,
95 NULL);
96 }
97 }
98
99 /* If there is no custom icon, fall back to checking if the buddy has an
100 * icon set.
101 */
102 if(!G_IS_INPUT_STREAM(stream)) {
103 PurpleBuddyIcon *icon = purple_buddy_get_icon(buddy);
104
105 if(icon != NULL) {
106 stream = purple_buddy_icon_get_stream(icon);
107 }
108 }
109
110 /* Finally if we still don't have icon, we fallback to asking the
111 * conversation for one.
112 */
113 if(!G_IS_INPUT_STREAM(stream) && PURPLE_IS_IM_CONVERSATION(conversation)) {
114 PurpleBuddyIcon *icon = purple_im_conversation_get_icon(PURPLE_IM_CONVERSATION(conversation));
115
116 if(icon != NULL) {
117 stream = purple_buddy_icon_get_stream(icon);
118 }
119 }
120
121 if(G_IS_INPUT_STREAM(stream)) {
122 ret = gdk_pixbuf_animation_new_from_stream(stream, NULL, NULL);
123 g_clear_object(&stream);
124 }
125
126 return ret;
127 }
128
129 static void
130 pidgin_avatar_update(PidginAvatar *avatar) {
131 PurpleBuddy *buddy = NULL;
132 GdkPixbufAnimation *animation = NULL;
133 GdkPixbuf *pixbuf = NULL;
134
135 buddy = pidgin_avatar_get_effective_buddy(avatar);
136 if(PURPLE_IS_BUDDY(buddy)) {
137 animation = pidgin_avatar_find_buddy_icon(buddy,
138 avatar->conversation);
139 }
140
141 g_set_object(&avatar->animation, animation);
142
143 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) {
144 if(avatar->animate &&
145 !gdk_pixbuf_animation_is_static_image(avatar->animation)) {
146 pixbuf = GDK_PIXBUF(avatar->animation);
147 } else {
148 pixbuf = gdk_pixbuf_animation_get_static_image(avatar->animation);
149 }
150 }
151
152 gtk_picture_set_pixbuf(GTK_PICTURE(avatar->icon), pixbuf);
153
154 g_clear_object(&animation);
155 }
156
157 /******************************************************************************
51 * Actions 158 * Actions
52 *****************************************************************************/ 159 *****************************************************************************/
53 static void 160 static void
54 pidgin_avatar_save_response_cb(GtkNativeDialog *native, gint response, 161 pidgin_avatar_save_response_cb(GtkNativeDialog *native, gint response,
55 gpointer data) 162 gpointer data)
56 { 163 {
57 PidginAvatar *avatar = PIDGIN_AVATAR(data); 164 PidginAvatar *avatar = PIDGIN_AVATAR(data);
165 PurpleBuddy *buddy = NULL;
58 PurpleBuddyIcon *icon = NULL; 166 PurpleBuddyIcon *icon = NULL;
59 167
60 if(response != GTK_RESPONSE_ACCEPT || !PURPLE_IS_BUDDY(avatar->buddy)) { 168 if(response != GTK_RESPONSE_ACCEPT) {
61 gtk_native_dialog_destroy(native); 169 gtk_native_dialog_destroy(native);
62 170
63 return; 171 return;
64 } 172 }
65 173
66 icon = purple_buddy_get_icon(avatar->buddy); 174 buddy = pidgin_avatar_get_effective_buddy(avatar);
175 if(!PURPLE_IS_BUDDY(buddy)) {
176 gtk_native_dialog_destroy(native);
177
178 return;
179 }
180
181 icon = purple_buddy_get_icon(buddy);
67 182
68 if(icon != NULL) { 183 if(icon != NULL) {
69 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native); 184 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
70 GFile *file = NULL; 185 GFile *file = NULL;
71 gchar *filename = NULL; 186 gchar *filename = NULL;
85 static void 200 static void
86 pidgin_avatar_save_cb(GSimpleAction *action, GVariant *parameter, 201 pidgin_avatar_save_cb(GSimpleAction *action, GVariant *parameter,
87 gpointer data) 202 gpointer data)
88 { 203 {
89 PidginAvatar *avatar = PIDGIN_AVATAR(data); 204 PidginAvatar *avatar = PIDGIN_AVATAR(data);
205 PurpleBuddy *buddy = NULL;
90 PurpleAccount *account = NULL; 206 PurpleAccount *account = NULL;
91 GtkFileChooserNative *native = NULL; 207 GtkFileChooserNative *native = NULL;
92 GtkFileChooser *chooser = NULL; 208 GtkFileChooser *chooser = NULL;
93 GtkWindow *window = NULL; 209 GtkWindow *window = NULL;
94 const gchar *ext = NULL, *name = NULL; 210 const gchar *ext = NULL, *name = NULL;
95 gchar *filename = NULL; 211 gchar *filename = NULL;
96 212
97 g_return_if_fail(PURPLE_IS_BUDDY(avatar->buddy)); 213 buddy = pidgin_avatar_get_effective_buddy(avatar);
98 214 if(buddy == NULL) {
99 ext = purple_buddy_icon_get_extension(purple_buddy_get_icon(avatar->buddy)); 215 g_return_if_reached();
100 216 }
101 account = purple_buddy_get_account(avatar->buddy); 217
102 name = purple_buddy_get_name(avatar->buddy); 218 ext = purple_buddy_icon_get_extension(purple_buddy_get_icon(buddy));
219
220 account = purple_buddy_get_account(buddy);
221 name = purple_buddy_get_name(buddy);
103 filename = g_strdup_printf("%s.%s", purple_normalize(account, name), ext); 222 filename = g_strdup_printf("%s.%s", purple_normalize(account, name), ext);
104 223
105 window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(avatar))); 224 window = GTK_WINDOW(gtk_widget_get_root(GTK_WIDGET(avatar)));
106 native = gtk_file_chooser_native_new(_("Save Avatar"), 225 native = gtk_file_chooser_native_new(_("Save Avatar"),
107 window, 226 window,
122 static void 241 static void
123 pidgin_avatar_set_custom_response_cb(GtkNativeDialog *native, gint response, 242 pidgin_avatar_set_custom_response_cb(GtkNativeDialog *native, gint response,
124 gpointer data) 243 gpointer data)
125 { 244 {
126 PidginAvatar *avatar = PIDGIN_AVATAR(data); 245 PidginAvatar *avatar = PIDGIN_AVATAR(data);
246 PurpleBuddy *buddy = NULL;
127 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native); 247 GtkFileChooser *chooser = GTK_FILE_CHOOSER(native);
128 GFile *file = NULL; 248 GFile *file = NULL;
129 gchar *filename = NULL; 249 gchar *filename = NULL;
130 250
131 if(response != GTK_RESPONSE_ACCEPT || !PURPLE_IS_BUDDY(avatar->buddy)) { 251 if(response != GTK_RESPONSE_ACCEPT) {
252 gtk_native_dialog_destroy(native);
253
254 return;
255 }
256
257 buddy = pidgin_avatar_get_effective_buddy(avatar);
258 if(!PURPLE_IS_BUDDY(buddy)) {
132 gtk_native_dialog_destroy(native); 259 gtk_native_dialog_destroy(native);
133 260
134 return; 261 return;
135 } 262 }
136 263
137 file = gtk_file_chooser_get_file(chooser); 264 file = gtk_file_chooser_get_file(chooser);
138 filename = g_file_get_path(file); 265 filename = g_file_get_path(file);
139 if(filename != NULL) { 266 if(filename != NULL) {
140 PurpleContact *contact = purple_buddy_get_contact(avatar->buddy); 267 PurpleContact *contact = purple_buddy_get_contact(buddy);
141 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact); 268 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact);
142 269
143 purple_buddy_icons_node_set_custom_icon_from_file(node, filename); 270 purple_buddy_icons_node_set_custom_icon_from_file(node, filename);
271
272 pidgin_avatar_update(avatar);
144 } 273 }
145 274
146 g_free(filename); 275 g_free(filename);
147 g_object_unref(file); 276 g_object_unref(file);
148 277
173 static void 302 static void
174 pidgin_avatar_clear_custom_cb(GSimpleAction *action, GVariant *parameter, 303 pidgin_avatar_clear_custom_cb(GSimpleAction *action, GVariant *parameter,
175 gpointer data) 304 gpointer data)
176 { 305 {
177 PidginAvatar *avatar = PIDGIN_AVATAR(data); 306 PidginAvatar *avatar = PIDGIN_AVATAR(data);
178 307 PurpleBuddy *buddy = NULL;
179 if(PURPLE_IS_BUDDY(avatar->buddy)) { 308
180 PurpleContact *contact = purple_buddy_get_contact(avatar->buddy); 309 buddy = pidgin_avatar_get_effective_buddy(avatar);
310 if(PURPLE_IS_BUDDY(buddy)) {
311 PurpleContact *contact = purple_buddy_get_contact(buddy);
181 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact); 312 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact);
182 313
183 purple_buddy_icons_node_set_custom_icon_from_file(node, NULL); 314 purple_buddy_icons_node_set_custom_icon_from_file(node, NULL);
315
316 pidgin_avatar_update(avatar);
184 } 317 }
185 } 318 }
186 319
187 static GActionEntry actions[] = { 320 static GActionEntry actions[] = {
188 { 321 {
196 .activate = pidgin_avatar_clear_custom_cb, 329 .activate = pidgin_avatar_clear_custom_cb,
197 }, 330 },
198 }; 331 };
199 332
200 /****************************************************************************** 333 /******************************************************************************
201 * Helpers
202 *****************************************************************************/
203 static GdkPixbufAnimation *
204 pidgin_avatar_find_buddy_icon(PurpleBuddy *buddy,
205 PurpleIMConversation *conversation)
206 {
207 GdkPixbufAnimation *ret = NULL;
208 GInputStream *stream = NULL;
209 PurpleContact *contact = NULL;
210
211 g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
212
213 /* First check if our user has set a custom icon for this buddy. */
214 contact = purple_buddy_get_contact(buddy);
215 if(PURPLE_IS_CONTACT(contact)) {
216 PurpleBlistNode *node = PURPLE_BLIST_NODE(contact);
217 PurpleImage *custom_image = NULL;
218
219 custom_image = purple_buddy_icons_node_find_custom_icon(node);
220 if(PURPLE_IS_IMAGE(custom_image)) {
221 gconstpointer data = purple_image_get_data(custom_image);
222 gsize length = purple_image_get_data_size(custom_image);
223
224 stream = g_memory_input_stream_new_from_data(data, (gssize)length,
225 NULL);
226 }
227 }
228
229 /* If there is no custom icon, fall back to checking if the buddy has an
230 * icon set.
231 */
232 if(!G_IS_INPUT_STREAM(stream)) {
233 PurpleBuddyIcon *icon = purple_buddy_get_icon(buddy);
234
235 if(icon != NULL) {
236 stream = purple_buddy_icon_get_stream(icon);
237 }
238 }
239
240 /* Finally if we still don't have icon, we fallback to asking the
241 * conversation for one.
242 */
243 if(!G_IS_INPUT_STREAM(stream) && PURPLE_IS_IM_CONVERSATION(conversation)) {
244 PurpleBuddyIcon *icon = purple_im_conversation_get_icon(PURPLE_IM_CONVERSATION(conversation));
245
246 if(icon != NULL) {
247 stream = purple_buddy_icon_get_stream(icon);
248 }
249 }
250
251 if(G_IS_INPUT_STREAM(stream)) {
252 ret = gdk_pixbuf_animation_new_from_stream(stream, NULL, NULL);
253 g_clear_object(&stream);
254 }
255
256 return ret;
257 }
258
259 static void
260 pidgin_avatar_update(PidginAvatar *avatar) {
261 PurpleAccount *account = NULL;
262 GdkPixbufAnimation *animation = NULL;
263 GdkPixbuf *pixbuf = NULL;
264
265 if(PURPLE_IS_BUDDY(avatar->buddy)) {
266 animation = pidgin_avatar_find_buddy_icon(avatar->buddy, NULL);
267 } else if(PURPLE_IS_IM_CONVERSATION(avatar->conversation)) {
268 PurpleBuddy *buddy = NULL;
269 const gchar *name = NULL;
270
271 account = purple_conversation_get_account(avatar->conversation);
272
273 name = purple_conversation_get_name(avatar->conversation);
274 buddy = purple_blist_find_buddy(account, name);
275
276 if(PURPLE_IS_BUDDY(buddy)) {
277 animation = pidgin_avatar_find_buddy_icon(buddy,
278 PURPLE_IM_CONVERSATION(avatar->conversation));
279 }
280 }
281
282 g_set_object(&avatar->animation, animation);
283
284 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) {
285 if(avatar->animate) {
286 pixbuf = GDK_PIXBUF(avatar->animation);
287 } else {
288 pixbuf = gdk_pixbuf_animation_get_static_image(avatar->animation);
289 }
290 }
291
292 gtk_picture_set_pixbuf(GTK_PICTURE(avatar->icon), pixbuf);
293
294 g_clear_object(&animation);
295 }
296
297 /******************************************************************************
298 * Callbacks 334 * Callbacks
299 *****************************************************************************/ 335 *****************************************************************************/
300 static gboolean 336 static gboolean
301 pidgin_avatar_button_press_handler(G_GNUC_UNUSED GtkGestureClick *event, 337 pidgin_avatar_button_press_handler(G_GNUC_UNUSED GtkGestureClick *event,
302 G_GNUC_UNUSED gint n_press, 338 G_GNUC_UNUSED gint n_press,
438 pidgin_avatar_init(PidginAvatar *avatar) { 474 pidgin_avatar_init(PidginAvatar *avatar) {
439 GSimpleActionGroup *group = NULL; 475 GSimpleActionGroup *group = NULL;
440 476
441 gtk_widget_init_template(GTK_WIDGET(avatar)); 477 gtk_widget_init_template(GTK_WIDGET(avatar));
442 478
479 #if GTK_CHECK_VERSION(4,8,0)
480 gtk_picture_set_content_fit(GTK_PICTURE(avatar->icon),
481 GTK_CONTENT_FIT_SCALE_DOWN);
482 #endif
443 /* Now setup our actions. */ 483 /* Now setup our actions. */
444 group = g_simple_action_group_new(); 484 group = g_simple_action_group_new();
445 g_action_map_add_action_entries(G_ACTION_MAP(group), actions, 485 g_action_map_add_action_entries(G_ACTION_MAP(group), actions,
446 G_N_ELEMENTS(actions), avatar); 486 G_N_ELEMENTS(actions), avatar);
447 487
521 g_return_if_fail(PIDGIN_IS_AVATAR(avatar)); 561 g_return_if_fail(PIDGIN_IS_AVATAR(avatar));
522 562
523 avatar->animate = animate; 563 avatar->animate = animate;
524 564
525 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) { 565 if(GDK_IS_PIXBUF_ANIMATION(avatar->animation)) {
526 if(avatar->animate) { 566 if(avatar->animate &&
527 gtk_image_set_from_pixbuf(GTK_IMAGE(avatar->icon), 567 !gdk_pixbuf_animation_is_static_image(avatar->animation)) {
528 GDK_PIXBUF(avatar->animation)); 568 gtk_picture_set_pixbuf(GTK_PICTURE(avatar->icon),
569 GDK_PIXBUF(avatar->animation));
529 } else { 570 } else {
530 GdkPixbuf *frame = NULL; 571 GdkPixbuf *frame = NULL;
531 572
532 frame = gdk_pixbuf_animation_get_static_image(avatar->animation); 573 frame = gdk_pixbuf_animation_get_static_image(avatar->animation);
533 574
534 gtk_image_set_from_pixbuf(GTK_IMAGE(avatar->icon), frame); 575 gtk_picture_set_pixbuf(GTK_PICTURE(avatar->icon), frame);
535 } 576 }
536 } 577 }
537 } 578 }
538 579
539 gboolean 580 gboolean

mercurial