pidgin/gtkutils.c

changeset 41766
78a984e17548
parent 41733
a9085b52de8b
child 41797
3bc9948e9f3c
equal deleted inserted replaced
41765:6b1dc67b861d 41766:78a984e17548
173 } 173 }
174 174
175 void 175 void
176 pidgin_set_accessible_label(GtkWidget *w, GtkLabel *l) 176 pidgin_set_accessible_label(GtkWidget *w, GtkLabel *l)
177 { 177 {
178 pidgin_set_accessible_relations(w, l);
179 }
180
181 void
182 pidgin_set_accessible_relations (GtkWidget *w, GtkLabel *l)
183 {
184 GtkAccessible *acc, *label; 178 GtkAccessible *acc, *label;
185 179
186 acc = GTK_ACCESSIBLE(w); 180 acc = GTK_ACCESSIBLE(w);
187 label = GTK_ACCESSIBLE(l); 181 label = GTK_ACCESSIBLE(l);
188 182
190 gtk_label_set_mnemonic_widget(l, w); 184 gtk_label_set_mnemonic_widget(l, w);
191 185
192 /* Create the labeled-by relation */ 186 /* Create the labeled-by relation */
193 gtk_accessible_update_relation(acc, GTK_ACCESSIBLE_RELATION_LABELLED_BY, 187 gtk_accessible_update_relation(acc, GTK_ACCESSIBLE_RELATION_LABELLED_BY,
194 label, NULL, -1); 188 label, NULL, -1);
195 }
196
197 void pidgin_buddy_icon_get_scale_size(GdkPixbuf *buf, PurpleBuddyIconSpec *spec, PurpleBuddyIconScaleFlags rules, int *width, int *height)
198 {
199 *width = gdk_pixbuf_get_width(buf);
200 *height = gdk_pixbuf_get_height(buf);
201
202 if ((spec == NULL) || !(spec->scale_rules & rules))
203 return;
204
205 purple_buddy_icon_spec_get_scaled_size(spec, width, height);
206
207 /* and now for some arbitrary sanity checks */
208 if(*width > 100)
209 *width = 100;
210 if(*height > 100)
211 *height = 100;
212 } 189 }
213 190
214 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion, 191 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion,
215 const gchar *key, GtkTreeIter *iter, gpointer user_data) 192 const gchar *key, GtkTreeIter *iter, gpointer user_data)
216 { 193 {
468 gboolean 445 gboolean
469 pidgin_screenname_autocomplete_default_filter(const PidginBuddyCompletionEntry *completion_entry, gpointer all_accounts) { 446 pidgin_screenname_autocomplete_default_filter(const PidginBuddyCompletionEntry *completion_entry, gpointer all_accounts) {
470 gboolean all = GPOINTER_TO_INT(all_accounts); 447 gboolean all = GPOINTER_TO_INT(all_accounts);
471 448
472 return all || purple_account_is_connected(purple_buddy_get_account(completion_entry->buddy)); 449 return all || purple_account_is_connected(purple_buddy_get_account(completion_entry->buddy));
473 }
474
475 /*
476 * str_array_match:
477 *
478 * Returns: %TRUE if any string from array @a exists in array @b.
479 */
480 static gboolean
481 str_array_match(char **a, char **b)
482 {
483 int i, j;
484
485 if (!a || !b)
486 return FALSE;
487 for (i = 0; a[i] != NULL; i++)
488 for (j = 0; b[j] != NULL; j++)
489 if (!g_ascii_strcasecmp(a[i], b[j]))
490 return TRUE;
491 return FALSE;
492 }
493
494 gpointer
495 pidgin_convert_buddy_icon(PurpleProtocol *protocol, const char *path, size_t *len)
496 {
497 PurpleBuddyIconSpec *spec;
498 int orig_width, orig_height, new_width, new_height;
499 GdkPixbufFormat *format;
500 char **pixbuf_formats;
501 char **protocol_formats;
502 GError *error = NULL;
503 gchar *contents;
504 gsize length;
505 GdkPixbuf *pixbuf, *original;
506 float scale_factor;
507 int i;
508 gchar *tmp;
509
510 spec = purple_protocol_get_icon_spec(protocol);
511 if(spec->format == NULL) {
512 purple_buddy_icon_spec_free(spec);
513
514 return NULL;
515 }
516
517 format = gdk_pixbuf_get_file_info(path, &orig_width, &orig_height);
518 if (format == NULL) {
519 purple_debug_warning("buddyicon", "Could not get file info of %s\n", path);
520
521 purple_buddy_icon_spec_free(spec);
522
523 return NULL;
524 }
525
526 pixbuf_formats = gdk_pixbuf_format_get_extensions(format);
527 protocol_formats = g_strsplit(spec->format, ",", 0);
528
529 if (str_array_match(pixbuf_formats, protocol_formats) && /* This is an acceptable format AND */
530 (!(spec->scale_rules & PURPLE_ICON_SCALE_SEND) || /* The protocol doesn't scale before it sends OR */
531 (spec->min_width <= orig_width && spec->max_width >= orig_width &&
532 spec->min_height <= orig_height && spec->max_height >= orig_height))) /* The icon is the correct size */
533 {
534 g_strfreev(pixbuf_formats);
535
536 if (!g_file_get_contents(path, &contents, &length, &error)) {
537 purple_debug_warning("buddyicon", "Could not get file contents "
538 "of %s: %s\n", path, error->message);
539 g_strfreev(protocol_formats);
540 purple_buddy_icon_spec_free(spec);
541 return NULL;
542 }
543
544 if (spec->max_filesize == 0 || length < spec->max_filesize) {
545 /* The supplied image fits the file size, dimensions and type
546 constraints. Great! Return it without making any changes. */
547 if (len)
548 *len = length;
549 g_strfreev(protocol_formats);
550 purple_buddy_icon_spec_free(spec);
551 return contents;
552 }
553
554 /* The image was too big. Fall-through and try scaling it down. */
555 g_free(contents);
556 } else {
557 g_strfreev(pixbuf_formats);
558 }
559
560 /* The original image wasn't compatible. Scale it or convert file type. */
561 pixbuf = gdk_pixbuf_new_from_file(path, &error);
562 if (error) {
563 purple_debug_warning("buddyicon", "Could not open icon '%s' for "
564 "conversion: %s\n", path, error->message);
565 g_error_free(error);
566 g_strfreev(protocol_formats);
567 purple_buddy_icon_spec_free(spec);
568 return NULL;
569 }
570 original = g_object_ref(pixbuf);
571
572 new_width = orig_width;
573 new_height = orig_height;
574
575 /* Make sure the image is the correct dimensions */
576 if (spec->scale_rules & PURPLE_ICON_SCALE_SEND &&
577 (orig_width < spec->min_width || orig_width > spec->max_width ||
578 orig_height < spec->min_height || orig_height > spec->max_height))
579 {
580 purple_buddy_icon_spec_get_scaled_size(spec, &new_width, &new_height);
581
582 g_object_unref(G_OBJECT(pixbuf));
583 pixbuf = gdk_pixbuf_scale_simple(original, new_width, new_height, GDK_INTERP_HYPER);
584 }
585
586 scale_factor = 1;
587 do {
588 for (i = 0; protocol_formats[i]; i++) {
589 int quality = 100;
590 do {
591 const char *key = NULL;
592 const char *value = NULL;
593 gchar tmp_buf[4];
594
595 purple_debug_info("buddyicon", "Converting buddy icon to %s\n", protocol_formats[i]);
596
597 if (purple_strequal(protocol_formats[i], "png")) {
598 key = "compression";
599 value = "9";
600 } else if (purple_strequal(protocol_formats[i], "jpeg")) {
601 sprintf(tmp_buf, "%u", quality);
602 key = "quality";
603 value = tmp_buf;
604 }
605
606 if (!gdk_pixbuf_save_to_buffer(pixbuf, &contents, &length,
607 protocol_formats[i], &error, key, value, NULL))
608 {
609 /* The NULL checking of error is necessary due to this bug:
610 * http://bugzilla.gnome.org/show_bug.cgi?id=405539 */
611 purple_debug_warning("buddyicon",
612 "Could not convert to %s: %s\n", protocol_formats[i],
613 (error && error->message) ? error->message : "Unknown error");
614 g_error_free(error);
615 error = NULL;
616
617 /* We couldn't convert to this image type. Try the next
618 image type. */
619 break;
620 }
621
622 if (spec->max_filesize == 0 || length <= spec->max_filesize) {
623 /* We were able to save the image as this image type and
624 have it be within the size constraints. Great! Return
625 the image. */
626 purple_debug_info("buddyicon", "Converted image from "
627 "%dx%d to %dx%d, format=%s, quality=%u, "
628 "filesize=%" G_GSIZE_FORMAT "\n",
629 orig_width, orig_height, new_width, new_height,
630 protocol_formats[i], quality, length);
631 if (len)
632 *len = length;
633 g_strfreev(protocol_formats);
634 g_object_unref(G_OBJECT(pixbuf));
635 g_object_unref(G_OBJECT(original));
636 purple_buddy_icon_spec_free(spec);
637 return contents;
638 }
639
640 g_free(contents);
641
642 if (!purple_strequal(protocol_formats[i], "jpeg")) {
643 /* File size was too big and we can't lower the quality,
644 so skip to the next image type. */
645 break;
646 }
647
648 /* File size was too big, but we're dealing with jpeg so try
649 lowering the quality. */
650 quality -= 5;
651 } while (quality >= 70);
652 }
653
654 /* We couldn't save the image in any format that was below the max
655 file size. Maybe we can reduce the image dimensions? */
656 scale_factor *= 0.8;
657 new_width = orig_width * scale_factor;
658 new_height = orig_height * scale_factor;
659 g_object_unref(G_OBJECT(pixbuf));
660 pixbuf = gdk_pixbuf_scale_simple(original, new_width, new_height, GDK_INTERP_HYPER);
661 } while ((new_width > 10 || new_height > 10) && new_width > spec->min_width && new_height > spec->min_height);
662 g_strfreev(protocol_formats);
663 g_object_unref(G_OBJECT(pixbuf));
664 g_object_unref(G_OBJECT(original));
665
666 tmp = g_strdup_printf(_("The file '%s' is too large for %s. Please try a smaller image.\n"),
667 path, purple_protocol_get_name(protocol));
668 purple_notify_error(NULL, _("Icon Error"), _("Could not set icon"), tmp, NULL);
669 g_free(tmp);
670
671 purple_buddy_icon_spec_free(spec);
672
673 return NULL;
674 } 450 }
675 451
676 /* 452 /*
677 * "This is so dead sexy." 453 * "This is so dead sexy."
678 * "Two thumbs up." 454 * "Two thumbs up."

mercurial