| 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." |