Mercurial > pidgin.yaz
comparison pidgin/gtkutils.c @ 16381:72dc611f3257
Fix the custom icon stuff, and various memory leaks. At this point, custom
icons work properly, EXCEPT FOR A SERIOUS LEAK which I haven't fixed yet
because I'm seeing weird memory allocation issues. Once I deal with that, it's
just the account icon stuff that's left.
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Tue, 24 Apr 2007 17:00:22 +0000 |
parents | 391a79778f89 |
children | 24bbd7e46bfe |
comparison
equal
deleted
inserted
replaced
16380:6c97924af83b | 16381:72dc611f3257 |
---|---|
2407 return TRUE; | 2407 return TRUE; |
2408 return FALSE; | 2408 return FALSE; |
2409 } | 2409 } |
2410 #endif | 2410 #endif |
2411 | 2411 |
2412 char * | 2412 gpointer |
2413 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path) | 2413 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len) |
2414 { | 2414 { |
2415 PurplePluginProtocolInfo *prpl_info; | 2415 PurplePluginProtocolInfo *prpl_info; |
2416 #if GTK_CHECK_VERSION(2,2,0) | 2416 #if GTK_CHECK_VERSION(2,2,0) |
2417 char **prpl_formats; | 2417 char **prpl_formats; |
2418 int width, height; | 2418 int width, height; |
2419 char **pixbuf_formats = NULL; | 2419 char **pixbuf_formats = NULL; |
2420 struct stat st; | |
2421 GdkPixbufFormat *format; | 2420 GdkPixbufFormat *format; |
2422 GdkPixbuf *pixbuf; | 2421 GdkPixbuf *pixbuf; |
2423 #if !GTK_CHECK_VERSION(2,4,0) | 2422 #if !GTK_CHECK_VERSION(2,4,0) |
2424 GdkPixbufLoader *loader; | 2423 GdkPixbufLoader *loader; |
2425 #endif | 2424 #endif |
2426 #endif | 2425 #endif |
2427 gchar *contents; | 2426 gchar *contents; |
2428 gsize length; | 2427 gsize length; |
2429 const char *dirname; | |
2430 char *random; | |
2431 char *filename; | |
2432 | 2428 |
2433 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); | 2429 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); |
2434 | 2430 |
2435 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); | 2431 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); |
2436 | 2432 |
2437 dirname = purple_buddy_icons_get_cache_dir(); | |
2438 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) { | |
2439 purple_debug_info("buddyicon", "Creating icon cache directory.\n"); | |
2440 | |
2441 if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) { | |
2442 purple_debug_error("buddyicon", | |
2443 "Unable to create directory %s: %s\n", | |
2444 dirname, strerror(errno)); | |
2445 return NULL; | |
2446 } | |
2447 } | |
2448 | |
2449 random = g_strdup_printf("%x", g_random_int()); | |
2450 filename = g_build_filename(dirname, random, NULL); | |
2451 | 2433 |
2452 #if GTK_CHECK_VERSION(2,2,0) | 2434 #if GTK_CHECK_VERSION(2,2,0) |
2453 #if GTK_CHECK_VERSION(2,4,0) | 2435 #if GTK_CHECK_VERSION(2,4,0) |
2454 format = gdk_pixbuf_get_file_info(path, &width, &height); | 2436 format = gdk_pixbuf_get_file_info(path, &width, &height); |
2455 #else | 2437 #else |
2476 prpl_info->icon_spec.max_width >= width && | 2458 prpl_info->icon_spec.max_width >= width && |
2477 prpl_info->icon_spec.min_height <= height && | 2459 prpl_info->icon_spec.min_height <= height && |
2478 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ | 2460 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ |
2479 #endif | 2461 #endif |
2480 { | 2462 { |
2481 FILE *image; | |
2482 | |
2483 #if GTK_CHECK_VERSION(2,2,0) | 2463 #if GTK_CHECK_VERSION(2,2,0) |
2484 g_strfreev(prpl_formats); | 2464 g_strfreev(prpl_formats); |
2485 g_strfreev(pixbuf_formats); | 2465 g_strfreev(pixbuf_formats); |
2486 #endif | 2466 #endif |
2487 | 2467 /* We don't need to scale the image. */ |
2488 /* We don't need to scale the image, so copy it to the cache folder verbatim */ | |
2489 | 2468 |
2490 contents = NULL; | 2469 contents = NULL; |
2491 if (!g_file_get_contents(path, &contents, &length, NULL) || | 2470 if (!g_file_get_contents(path, &contents, &length, NULL)) |
2492 (image = g_fopen(filename, "wb")) == NULL) | |
2493 { | 2471 { |
2494 g_free(random); | |
2495 g_free(filename); | |
2496 g_free(contents); | 2472 g_free(contents); |
2497 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) | |
2498 g_object_unref(G_OBJECT(pixbuf)); | |
2499 #endif | |
2500 return NULL; | |
2501 } | |
2502 | |
2503 if (fwrite(contents, 1, length, image) != length) | |
2504 { | |
2505 fclose(image); | |
2506 g_unlink(filename); | |
2507 | |
2508 g_free(random); | |
2509 g_free(filename); | |
2510 g_free(contents); | |
2511 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) | |
2512 g_object_unref(G_OBJECT(pixbuf)); | |
2513 #endif | |
2514 return NULL; | |
2515 } | |
2516 fclose(image); | |
2517 g_free(contents); | |
2518 | |
2519 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) | 2473 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
2520 g_object_unref(G_OBJECT(pixbuf)); | 2474 g_object_unref(G_OBJECT(pixbuf)); |
2521 #endif | 2475 #endif |
2476 return NULL; | |
2477 } | |
2522 } | 2478 } |
2523 #if GTK_CHECK_VERSION(2,2,0) | 2479 #if GTK_CHECK_VERSION(2,2,0) |
2524 else | 2480 else |
2525 { | 2481 { |
2526 int i; | 2482 int i; |
2527 GError *error = NULL; | 2483 GError *error = NULL; |
2528 GdkPixbuf *scale; | 2484 GdkPixbuf *scale; |
2529 gboolean success = FALSE; | 2485 gboolean success = FALSE; |
2486 char *filename = NULL; | |
2530 | 2487 |
2531 g_strfreev(pixbuf_formats); | 2488 g_strfreev(pixbuf_formats); |
2532 | 2489 |
2533 pixbuf = gdk_pixbuf_new_from_file(path, &error); | 2490 pixbuf = gdk_pixbuf_new_from_file(path, &error); |
2534 if (error) { | 2491 if (error) { |
2535 purple_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); | 2492 purple_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); |
2536 g_error_free(error); | 2493 g_error_free(error); |
2537 g_free(random); | |
2538 g_free(filename); | |
2539 g_strfreev(prpl_formats); | 2494 g_strfreev(prpl_formats); |
2540 return NULL; | 2495 return NULL; |
2541 } | 2496 } |
2542 | 2497 |
2543 if ((prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) && | 2498 if ((prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) && |
2556 g_object_unref(G_OBJECT(pixbuf)); | 2511 g_object_unref(G_OBJECT(pixbuf)); |
2557 pixbuf = scale; | 2512 pixbuf = scale; |
2558 } | 2513 } |
2559 | 2514 |
2560 for (i = 0; prpl_formats[i]; i++) { | 2515 for (i = 0; prpl_formats[i]; i++) { |
2516 FILE *fp; | |
2517 | |
2518 g_free(filename); | |
2519 fp = purple_mkstemp(&filename, TRUE); | |
2520 if (!fp) | |
2521 { | |
2522 g_free(filename); | |
2523 return NULL; | |
2524 } | |
2525 fclose(fp); | |
2526 | |
2561 purple_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename); | 2527 purple_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename); |
2562 /* The "compression" param wasn't supported until gdk-pixbuf 2.8. | 2528 /* The "compression" param wasn't supported until gdk-pixbuf 2.8. |
2563 * Using it in previous versions causes the save to fail (and an assert message). */ | 2529 * Using it in previous versions causes the save to fail (and an assert message). */ |
2564 if ((gdk_pixbuf_major_version > 2 || (gdk_pixbuf_major_version == 2 | 2530 if ((gdk_pixbuf_major_version > 2 || (gdk_pixbuf_major_version == 2 |
2565 && gdk_pixbuf_minor_version >= 8)) | 2531 && gdk_pixbuf_minor_version >= 8)) |
2584 } | 2550 } |
2585 g_strfreev(prpl_formats); | 2551 g_strfreev(prpl_formats); |
2586 g_object_unref(G_OBJECT(pixbuf)); | 2552 g_object_unref(G_OBJECT(pixbuf)); |
2587 if (!success) { | 2553 if (!success) { |
2588 purple_debug_error("buddyicon", "Could not convert icon to usable format.\n"); | 2554 purple_debug_error("buddyicon", "Could not convert icon to usable format.\n"); |
2589 g_free(random); | 2555 return NULL; |
2556 } | |
2557 | |
2558 contents = NULL; | |
2559 if (!g_file_get_contents(filename, &contents, &length, NULL)) | |
2560 { | |
2561 purple_debug_error("buddyicon", | |
2562 "Could not read '%s', which we just wrote to disk.\n", | |
2563 filename); | |
2564 | |
2565 g_free(contents); | |
2590 g_free(filename); | 2566 g_free(filename); |
2591 return NULL; | 2567 return NULL; |
2592 } | 2568 } |
2593 } | 2569 |
2594 | 2570 g_unlink(filename); |
2595 if (g_stat(filename, &st) != 0) { | |
2596 purple_debug_error("buddyicon", | |
2597 "Could not stat '%s', which we just wrote to disk: %s\n", | |
2598 filename, strerror(errno)); | |
2599 g_free(random); | |
2600 g_free(filename); | 2571 g_free(filename); |
2601 return NULL; | 2572 } |
2602 } | 2573 |
2603 | 2574 /* Check the image size */ |
2604 /* Check the file size */ | |
2605 /* | 2575 /* |
2606 * TODO: If the file is too big, it would be cool if we checked if | 2576 * TODO: If the file is too big, it would be cool if we checked if |
2607 * the prpl supported jpeg, and then we could convert to that | 2577 * the prpl supported jpeg, and then we could convert to that |
2608 * and use a lower quality setting. | 2578 * and use a lower quality setting. |
2609 */ | 2579 */ |
2610 if ((prpl_info->icon_spec.max_filesize != 0) && | 2580 if ((prpl_info->icon_spec.max_filesize != 0) && |
2611 (st.st_size > prpl_info->icon_spec.max_filesize)) | 2581 (length > prpl_info->icon_spec.max_filesize)) |
2612 { | 2582 { |
2613 gchar *tmp; | 2583 gchar *tmp; |
2614 tmp = g_strdup_printf(_("The file '%s' is too large for %s. Please try a smaller image.\n"), | 2584 tmp = g_strdup_printf(_("The file '%s' is too large for %s. Please try a smaller image.\n"), |
2615 path, plugin->info->name); | 2585 path, plugin->info->name); |
2616 purple_notify_error(NULL, _("Icon Error"), | 2586 purple_notify_error(NULL, _("Icon Error"), |
2617 _("Could not set icon"), tmp); | 2587 _("Could not set icon"), tmp); |
2618 purple_debug_info("buddyicon", | 2588 purple_debug_info("buddyicon", |
2619 "'%s' was converted to an image which is %" G_GSIZE_FORMAT | 2589 "'%s' was converted to an image which is %" G_GSIZE_FORMAT |
2620 " bytes, but the maximum icon size for %s is %" G_GSIZE_FORMAT | 2590 " bytes, but the maximum icon size for %s is %" G_GSIZE_FORMAT |
2621 " bytes\n", path, st.st_size, plugin->info->name, | 2591 " bytes\n", path, length, plugin->info->name, |
2622 prpl_info->icon_spec.max_filesize); | 2592 prpl_info->icon_spec.max_filesize); |
2623 g_free(tmp); | 2593 g_free(tmp); |
2624 g_free(random); | |
2625 g_free(filename); | |
2626 return NULL; | 2594 return NULL; |
2627 } | 2595 } |
2628 | 2596 |
2629 g_free(filename); | 2597 if (len) |
2630 return random; | 2598 *len = length; |
2599 return contents; | |
2631 #else | 2600 #else |
2632 /* | 2601 /* |
2633 * The chosen icon wasn't the right size, and we're using | 2602 * The chosen icon wasn't the right size, and we're using |
2634 * GTK+ 2.0 so we can't scale it. | 2603 * GTK+ 2.0 so we can't scale it. |
2635 */ | 2604 */ |
2778 } | 2747 } |
2779 #endif /* ! Gtk 2.6.0 */ | 2748 #endif /* ! Gtk 2.6.0 */ |
2780 | 2749 |
2781 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) | 2750 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) |
2782 { | 2751 { |
2783 PurpleConversation *conv; | |
2784 PurpleBuddy *buddy; | 2752 PurpleBuddy *buddy; |
2785 PurpleBlistNode *node; | 2753 PurpleContact *contact; |
2786 char *path = NULL; | 2754 gpointer data = NULL; |
2755 size_t len = 0; | |
2787 | 2756 |
2788 buddy = purple_find_buddy(account, who); | 2757 buddy = purple_find_buddy(account, who); |
2789 if (!buddy) { | 2758 if (!buddy) { |
2790 purple_debug_info("custom-icon", "You can only set custom icon for someone in your buddylist.\n"); | 2759 purple_debug_info("custom-icon", "You can only set custom icon for someone in your buddylist.\n"); |
2791 return; | 2760 return; |
2792 } | 2761 } |
2793 | 2762 |
2794 node = (PurpleBlistNode*)purple_buddy_get_contact(buddy); | 2763 contact = purple_buddy_get_contact(buddy); |
2795 path = (char*)purple_blist_node_get_string(node, "custom_buddy_icon"); | |
2796 if (path) { | |
2797 struct stat st; | |
2798 if (g_stat(path, &st) == 0) | |
2799 g_unlink(path); | |
2800 path = NULL; | |
2801 } | |
2802 | 2764 |
2803 if (filename) { | 2765 if (filename) { |
2804 char *newfile; | 2766 const char *prpl_id = purple_account_get_protocol_id(account); |
2805 | 2767 PurplePlugin *prpl = purple_find_prpl(prpl_id); |
2806 newfile = pidgin_convert_buddy_icon(purple_find_prpl(purple_account_get_protocol_id(account)), | 2768 |
2807 filename); | 2769 data = pidgin_convert_buddy_icon(prpl, filename, &len); |
2808 path = purple_buddy_icons_get_full_path(newfile); | 2770 |
2809 g_free(newfile); | 2771 /* We don't want to delete the old icon if the new one didn't load. */ |
2810 } | 2772 if (data == NULL) |
2811 | 2773 return; |
2812 purple_blist_node_set_string(node, "custom_buddy_icon", path); | 2774 } |
2813 g_free(path); | 2775 |
2814 | 2776 purple_buddy_icons_set_custom_icon(contact, data, len); |
2815 /* Update the conversation */ | |
2816 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, account); | |
2817 if (conv) | |
2818 purple_conversation_update(conv, PURPLE_CONV_UPDATE_ICON); | |
2819 | |
2820 /* Update the buddylist */ | |
2821 if (buddy) | |
2822 purple_blist_update_buddy_icon(buddy); | |
2823 } | 2777 } |
2824 | 2778 |
2825 char *pidgin_make_pretty_arrows(const char *str) | 2779 char *pidgin_make_pretty_arrows(const char *str) |
2826 { | 2780 { |
2827 char *ret; | 2781 char *ret; |