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;