# HG changeset patch # User Elliott Sales de Andrade # Date 1308898473 0 # Node ID 6e5d46ea82f9a124bae92e85a73562de8f52dc14 # Parent 3e98b34853ee372ec3ebedc0370924be2998ab6a# Parent 8c027bc27073c1781c066e7eb88bfc3e665fa601 merge of '8512af37c7822c68f1cf46a02cbca592f6c79468' and 'dc05140f38c2811411a326665b3a2ebb1abeb51a' diff -r 3e98b34853ee -r 6e5d46ea82f9 ChangeLog --- a/ChangeLog Wed Jun 22 22:10:37 2011 +0000 +++ b/ChangeLog Fri Jun 24 06:54:33 2011 +0000 @@ -1,25 +1,35 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul -version 2.8.1 (MM/DD/YYYY): +version 2.9.1 (MM/DD/YYYY): + Gadu-Gadu: + * Fixed searching for buddies in public directory. (Tomasz Wasilczyk) + (#5242) + * Better status message handling. (Tomasz Wasilczyk) (#14314) + +version 2.9.0 (06/23/2011): Pidgin: + * Fix a potential remote denial-of-service bug related to displaying + buddy icons. + * Significantly improved performance of larger IRC channels (regression + introduced in 2.8.0). * Fix Conversation->Add on AIM and MSN. - * Entries in the chat user list are sorted properly again. + * Entries in the chat user list are sorted properly again. This was + inadvertenly broken in 2.8.0. Finch: - * Fixed logging in to ICQ. + * Fix logging in to ICQ. libpurple: * media: Actually use the specified TCP port from the TURN configuration to create a TCP relay candidate. + AIM and ICQ: + * Fix crashes on some non-mainstream OSes when attempting to + printf("%s", NULL). (Clemens Huebner) (#14297) + Plugins: * The Evolution Integration plugin compiles again. - Gadu-Gadu: - * Fixed searching for buddies in public directory. (Tomasz Wasilczyk) - (#5242) - * Better status message handling. (Tomasz Wasilczyk) (#14314) - version 2.8.0 (06/07/2011): General: * Implement simple silence suppression for voice calls, preventing diff -r 3e98b34853ee -r 6e5d46ea82f9 ChangeLog.API --- a/ChangeLog.API Wed Jun 22 22:10:37 2011 +0000 +++ b/ChangeLog.API Fri Jun 24 06:54:33 2011 +0000 @@ -1,5 +1,22 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.9.0: + libpurple: + Added: + * Hash table to PurpleConvChat struct, used to make + purple_conv_chat_cb_find O(1). + * ui_data pointer to PurpleConvChatBuddy struct. + * deleting-chat-buddy signal (conversation signals) + * pidgin_pixbuf_from_data + * pidgin_pixbuf_anim_from_data + * pidgin_pixbuf_new_from_file + * pidgin_pixbuf_new_from_file_at_size + * pidgin_pixbuf_new_from_file_at_scale + + Deprecated: + * purple_conv_chat_set_users + * PurpleConvChat in_room list + version 2.8.0 (06/07/2011): libpurple: Added: diff -r 3e98b34853ee -r 6e5d46ea82f9 configure.ac --- a/configure.ac Wed Jun 22 22:10:37 2011 +0000 +++ b/configure.ac Fri Jun 24 06:54:33 2011 +0000 @@ -43,9 +43,9 @@ # # Make sure to update finch/libgnt/configure.ac with libgnt version changes. # -m4_define([purple_lt_current], [8]) +m4_define([purple_lt_current], [9]) m4_define([purple_major_version], [2]) -m4_define([purple_minor_version], [8]) +m4_define([purple_minor_version], [9]) m4_define([purple_micro_version], [1]) m4_define([purple_version_suffix], [devel]) m4_define([purple_version], diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkaccount.c --- a/pidgin/gtkaccount.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkaccount.c Fri Jun 24 06:54:33 2011 +0000 @@ -2135,7 +2135,7 @@ gtk_list_store_clear(dialog->model); if ((path = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon")) != NULL) { - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, NULL); + GdkPixbuf *pixbuf = pidgin_pixbuf_new_from_file(path); if (pixbuf != NULL) { global_buddyicon = gdk_pixbuf_scale_simple(pixbuf, 22, 22, GDK_INTERP_HYPER); g_object_unref(G_OBJECT(pixbuf)); diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkblist.c --- a/pidgin/gtkblist.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkblist.c Fri Jun 24 06:54:33 2011 +0000 @@ -2643,7 +2643,6 @@ gboolean scaled, gboolean greyed) { gsize len; - GdkPixbufLoader *loader; PurpleBuddy *buddy = NULL; PurpleGroup *group = NULL; const guchar *data = NULL; @@ -2710,21 +2709,20 @@ return NULL; } - loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, data, len, NULL); - gdk_pixbuf_loader_close(loader, NULL); - - purple_imgstore_unref(custom_img); + buf = pidgin_pixbuf_from_data(data, len); purple_buddy_icon_unref(icon); - - buf = gdk_pixbuf_loader_get_pixbuf(loader); - if (buf) - g_object_ref(G_OBJECT(buf)); - g_object_unref(G_OBJECT(loader)); - if (!buf) { + purple_debug_warning("gtkblist", "Couldn't load buddy icon " + "on account %s (%s) buddyname=%s " + "custom_img_data=%p\n", + account ? purple_account_get_username(account) : "(no account)", + account ? purple_account_get_protocol_id(account) : "(no account)", + buddy ? purple_buddy_get_name(buddy) : "(no buddy)", + custom_img ? purple_imgstore_get_data(custom_img) : NULL); + purple_imgstore_unref(custom_img); return NULL; } + purple_imgstore_unref(custom_img); if (greyed) { gboolean offline = FALSE, idle = FALSE; @@ -3952,7 +3950,7 @@ g_object_ref(pb); g_free(path); } else { - pb = gdk_pixbuf_new_from_file(path, NULL); + pb = pidgin_pixbuf_new_from_file(path); if (pb != NULL) { /* We don't want to own a ref to the pixbuf, but we need to keep clean up. */ /* I'm not sure if it would be better to just keep our ref and not let the emblem ever be destroyed */ diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkconv.c Fri Jun 24 06:54:33 2011 +0000 @@ -6392,8 +6392,8 @@ { PidginConversation *gtkconv; GtkIMHtmlSmiley *smiley; - GdkPixbufLoader *loader; const char *sml; + GError *error = NULL; sml = purple_account_get_protocol_name(conv->account); gtkconv = PIDGIN_CONVERSATION(conv); @@ -6406,11 +6406,24 @@ g_memmove((guchar *)smiley->data + smiley->datasize, data, size); smiley->datasize += size; - loader = smiley->loader; - if (!loader) + if (!smiley->loader) return; - gdk_pixbuf_loader_write(loader, data, size, NULL); + if (!gdk_pixbuf_loader_write(smiley->loader, data, size, &error) || error) { + purple_debug_warning("gtkconv", "gdk_pixbuf_loader_write() " + "failed with size=%zu: %s\n", size, + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + /* We must stop using the GdkPixbufLoader because trying to load + certain invalid GIFs with at least gdk-pixbuf 2.23.3 can return + a GdkPixbuf that will cause some operations (like + gdk_pixbuf_scale_simple()) to consume memory in an infinite loop. + But we also don't want to set smiley->loader to NULL because our + code might expect it to be set. So create a new loader. */ + g_object_unref(G_OBJECT(smiley->loader)); + smiley->loader = gdk_pixbuf_loader_new(); + } } static void @@ -6418,8 +6431,8 @@ { PidginConversation *gtkconv; GtkIMHtmlSmiley *smiley; - GdkPixbufLoader *loader; const char *sml; + GError *error = NULL; g_return_if_fail(conv != NULL); g_return_if_fail(smile != NULL); @@ -6431,17 +6444,27 @@ if (!smiley) return; - loader = smiley->loader; - - if (!loader) + if (!smiley->loader) return; - - purple_debug_info("gtkconv", "About to close the smiley pixbuf\n"); - gdk_pixbuf_loader_close(loader, NULL); - + if (!gdk_pixbuf_loader_close(smiley->loader, &error) || error) { + purple_debug_warning("gtkconv", "gdk_pixbuf_loader_close() " + "failed: %s\n", + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + /* We must stop using the GdkPixbufLoader because if we tried to + load certain invalid GIFs with all current versions of GDK (as + of 2011-06-15) then it's possible the loader will contain data + that could cause some operations (like gdk_pixbuf_scale_simple()) + to consume memory in an infinite loop. But we also don't want + to set smiley->loader to NULL because our code might expect it + to be set. So create a new loader. */ + g_object_unref(G_OBJECT(smiley->loader)); + smiley->loader = gdk_pixbuf_loader_new(); + } } static void @@ -6941,10 +6964,6 @@ PurpleBuddy *buddy; - GdkPixbufLoader *loader; - GdkPixbufAnimation *anim; - GError *err = NULL; - PurpleStoredImage *custom_img = NULL; gconstpointer data = NULL; size_t len; @@ -7022,7 +7041,6 @@ if (data == NULL) { icon = purple_conv_im_get_icon(PURPLE_CONV_IM(conv)); - if (icon == NULL) { gtk_widget_set_size_request(gtkconv->u.im->icon_container, @@ -7031,7 +7049,6 @@ } data = purple_buddy_icon_get_data(icon, &len); - if (data == NULL) { gtk_widget_set_size_request(gtkconv->u.im->icon_container, @@ -7040,25 +7057,13 @@ } } - loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, data, len, NULL); - gdk_pixbuf_loader_close(loader, &err); - + gtkconv->u.im->anim = pidgin_pixbuf_anim_from_data(data, len); purple_imgstore_unref(custom_img); - anim = gdk_pixbuf_loader_get_animation(loader); - if (anim) - g_object_ref(G_OBJECT(anim)); - g_object_unref(loader); - - if (!anim) + if (!gtkconv->u.im->anim) { + purple_debug_error("gtkconv", "Couldn't load icon for conv %s\n", + purple_conversation_get_name(conv)); return; - gtkconv->u.im->anim = anim; - - if (err) { - purple_debug(PURPLE_DEBUG_ERROR, "gtkconv", - "Buddy icon error: %s\n", err->message); - g_error_free(err); } if (gdk_pixbuf_animation_is_static_image(gtkconv->u.im->anim)) { diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkdialogs.c --- a/pidgin/gtkdialogs.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkdialogs.c Fri Jun 24 06:54:33 2011 +0000 @@ -433,7 +433,7 @@ /* Generate a logo with a version number */ filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "logo.png", NULL); - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + pixbuf = pidgin_pixbuf_new_from_file(filename); g_free(filename); #if 0 /* Don't versionize the logo when the logo has the version in it */ diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkft.c --- a/pidgin/gtkft.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkft.c Fri Jun 24 06:54:33 2011 +0000 @@ -1149,8 +1149,8 @@ if (purple_xfer_get_size(xfer) <= PIDGIN_XFER_MAX_SIZE_IMAGE_THUMBNAIL) { GdkPixbuf *thumbnail = - gdk_pixbuf_new_from_file_at_size( - purple_xfer_get_local_filename(xfer), 128, 128, NULL); + pidgin_pixbuf_new_from_file_at_size( + purple_xfer_get_local_filename(xfer), 128, 128); if (thumbnail) { gchar **formats_split = g_strsplit(formats, ",", 0); diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkimhtml.c --- a/pidgin/gtkimhtml.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkimhtml.c Fri Jun 24 06:54:33 2011 +0000 @@ -5057,16 +5057,8 @@ data = imhtml->funcs->image_get_data(image); len = imhtml->funcs->image_get_size(image); - - if (data && len) { - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, data, len, NULL); - gdk_pixbuf_loader_close(loader, NULL); - anim = gdk_pixbuf_loader_get_animation(loader); - if (anim) - g_object_ref(G_OBJECT(anim)); - g_object_unref(G_OBJECT(loader)); - } + if (data && len) + anim = pidgin_pixbuf_anim_from_data(data, len); } diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkmain.c --- a/pidgin/gtkmain.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkmain.c Fri Jun 24 06:54:33 2011 +0000 @@ -270,7 +270,7 @@ /* use the nice PNG icon for all the windows */ for(i=0; iicon ? gdk_pixbuf_new_from_file(theme->icon, NULL) : NULL); + pixbuf = (theme->icon ? pidgin_pixbuf_new_from_file(theme->icon) : NULL); gtk_list_store_set(prefs_smiley_themes, &iter, 0, pixbuf, @@ -452,7 +452,7 @@ image_full = purple_theme_get_image_full(theme); if (image_full != NULL){ - pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL); + pixbuf = pidgin_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE); g_free(image_full); } else pixbuf = NULL; @@ -473,7 +473,7 @@ image_full = purple_theme_get_image_full(theme); if (image_full != NULL){ - pixbuf = gdk_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL); + pixbuf = pidgin_pixbuf_new_from_file_at_scale(image_full, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE); g_free(image_full); } else pixbuf = NULL; @@ -529,7 +529,7 @@ purple_theme_manager_refresh(); tmp = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL); - pixbuf = gdk_pixbuf_new_from_file_at_scale(tmp, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL); + pixbuf = pidgin_pixbuf_new_from_file_at_scale(tmp, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE); g_free(tmp); /* sound themes */ diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkrequest.c --- a/pidgin/gtkrequest.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkrequest.c Fri Jun 24 06:54:33 2011 +0000 @@ -653,35 +653,30 @@ /* Dialog icon. */ if (icon_data) { - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - GdkPixbuf *pixbuf = NULL; - if (gdk_pixbuf_loader_write(loader, icon_data, icon_size, NULL)) { - pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); - if (pixbuf) { - /* scale the image if it is too large */ - int width = gdk_pixbuf_get_width(pixbuf); - int height = gdk_pixbuf_get_height(pixbuf); - if (width > 128 || height > 128) { - int scaled_width = width > height ? 128 : (128 * width) / height; - int scaled_height = height > width ? 128 : (128 * height) / width; - GdkPixbuf *scaled = - gdk_pixbuf_scale_simple(pixbuf, scaled_width, scaled_height, - GDK_INTERP_BILINEAR); + GdkPixbuf *pixbuf = pidgin_pixbuf_from_data(icon_data, icon_size); + if (pixbuf) { + /* scale the image if it is too large */ + int width = gdk_pixbuf_get_width(pixbuf); + int height = gdk_pixbuf_get_height(pixbuf); + if (width > 128 || height > 128) { + int scaled_width = width > height ? 128 : (128 * width) / height; + int scaled_height = height > width ? 128 : (128 * height) / width; + GdkPixbuf *scaled = + gdk_pixbuf_scale_simple(pixbuf, scaled_width, scaled_height, + GDK_INTERP_BILINEAR); - purple_debug_info("pidgin", - "dialog icon was too large, scale it down\n"); - if (scaled) { - g_object_unref(pixbuf); - pixbuf = scaled; - } + purple_debug_info("pidgin", + "dialog icon was too large, scaled it down\n"); + if (scaled) { + g_object_unref(pixbuf); + pixbuf = scaled; } - img = gtk_image_new_from_pixbuf(pixbuf); } + img = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); } else { purple_debug_info("pidgin", "failed to parse dialog icon\n"); } - gdk_pixbuf_loader_close(loader, NULL); - g_object_unref(loader); } if (!img) { @@ -1016,22 +1011,17 @@ { GtkWidget *widget; GdkPixbuf *buf, *scale; - GdkPixbufLoader *loader; - loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, - (const guchar *)purple_request_field_image_get_buffer(field), - purple_request_field_image_get_size(field), - NULL); - gdk_pixbuf_loader_close(loader, NULL); - buf = gdk_pixbuf_loader_get_pixbuf(loader); + buf = pidgin_pixbuf_from_data( + (const guchar *)purple_request_field_image_get_buffer(field), + purple_request_field_image_get_size(field)); scale = gdk_pixbuf_scale_simple(buf, purple_request_field_image_get_scale_x(field) * gdk_pixbuf_get_width(buf), purple_request_field_image_get_scale_y(field) * gdk_pixbuf_get_height(buf), GDK_INTERP_BILINEAR); widget = gtk_image_new_from_pixbuf(scale); - g_object_unref(G_OBJECT(loader)); + g_object_unref(G_OBJECT(buf)); g_object_unref(G_OBJECT(scale)); return widget; @@ -1132,7 +1122,7 @@ GdkPixbuf* pixbuf = NULL; if (icon_path) - pixbuf = gdk_pixbuf_new_from_file(icon_path, NULL); + pixbuf = pidgin_pixbuf_new_from_file(icon_path); gtk_list_store_set(store, &iter, 0, purple_request_field_list_get_data(field, text), diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtksmiley.c --- a/pidgin/gtksmiley.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtksmiley.c Fri Jun 24 06:54:33 2011 +0000 @@ -332,7 +332,7 @@ g_free(s->filename); s->filename = g_strdup(filename); - pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, 64, 64, FALSE, NULL); + pixbuf = pidgin_pixbuf_new_from_file_at_scale(filename, 64, 64, FALSE); gtk_image_set_from_pixbuf(GTK_IMAGE(s->smiley_image), pixbuf); if (pixbuf) g_object_unref(G_OBJECT(pixbuf)); @@ -690,7 +690,6 @@ FILE *f; gchar *path; size_t wc; - GError *err = NULL; PidginSmiley *ps; GdkPixbuf *image; @@ -709,13 +708,11 @@ } fclose(f); - image = gdk_pixbuf_new_from_file(path, &err); + image = pidgin_pixbuf_new_from_file(path); g_unlink(path); g_free(path); - if (err) { - g_error_free(err); + if (!image) return; - } ps = pidgin_smiley_edit(dialog->window, NULL); pidgin_smiley_editor_set_image(ps, image); diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkstatusbox.c --- a/pidgin/gtkstatusbox.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkstatusbox.c Fri Jun 24 06:54:33 2011 +0000 @@ -2225,22 +2225,45 @@ if (status_box->buddy_icon_img != NULL) { - GdkPixbuf *buf, *scale; - int scale_width, scale_height; - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + GdkPixbufLoader *loader; + GError *error = NULL; + + loader = gdk_pixbuf_loader_new(); + g_signal_connect(G_OBJECT(loader), "size-prepared", G_CALLBACK(pixbuf_size_prepared_cb), NULL); - gdk_pixbuf_loader_write(loader, purple_imgstore_get_data(status_box->buddy_icon_img), - purple_imgstore_get_size(status_box->buddy_icon_img), NULL); - gdk_pixbuf_loader_close(loader, NULL); - buf = gdk_pixbuf_loader_get_pixbuf(loader); - scale_width = gdk_pixbuf_get_width(buf); - scale_height = gdk_pixbuf_get_height(buf); - scale = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, scale_width, scale_height); - gdk_pixbuf_fill(scale, 0x00000000); - gdk_pixbuf_copy_area(buf, 0, 0, scale_width, scale_height, scale, 0, 0); - if (pidgin_gdk_pixbuf_is_opaque(scale)) - pidgin_gdk_pixbuf_make_round(scale); - status_box->buddy_icon = scale; + if (!gdk_pixbuf_loader_write(loader, + purple_imgstore_get_data(status_box->buddy_icon_img), + purple_imgstore_get_size(status_box->buddy_icon_img), + &error) || error) + { + purple_debug_warning("gtkstatusbox", "gdk_pixbuf_loader_write() " + "failed with size=%zu: %s\n", + purple_imgstore_get_size(status_box->buddy_icon_img), + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + } else if (!gdk_pixbuf_loader_close(loader, &error) || error) { + purple_debug_warning("gtkstatusbox", "gdk_pixbuf_loader_close() " + "failed for image of size %zu: %s\n", + purple_imgstore_get_size(status_box->buddy_icon_img), + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + } else { + GdkPixbuf *buf, *scale; + int scale_width, scale_height; + + buf = gdk_pixbuf_loader_get_pixbuf(loader); + scale_width = gdk_pixbuf_get_width(buf); + scale_height = gdk_pixbuf_get_height(buf); + scale = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, scale_width, scale_height); + gdk_pixbuf_fill(scale, 0x00000000); + gdk_pixbuf_copy_area(buf, 0, 0, scale_width, scale_height, scale, 0, 0); + if (pidgin_gdk_pixbuf_is_opaque(scale)) + pidgin_gdk_pixbuf_make_round(scale); + status_box->buddy_icon = scale; + } + g_object_unref(loader); } diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkutils.c --- a/pidgin/gtkutils.c Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkutils.c Fri Jun 24 06:54:33 2011 +0000 @@ -615,7 +615,7 @@ tmp, NULL); g_free(tmp); - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + pixbuf = pidgin_pixbuf_new_from_file(filename); g_free(filename); return pixbuf; @@ -704,7 +704,7 @@ "16", "google-talk.png", NULL); GtkWidget *item; - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + pixbuf = pidgin_pixbuf_new_from_file(filename); g_free(filename); gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), @@ -723,7 +723,7 @@ "16", "facebook.png", NULL); GtkWidget *item; - pixbuf = gdk_pixbuf_new_from_file(filename, NULL); + pixbuf = pidgin_pixbuf_new_from_file(filename); g_free(filename); gtk_menu_shell_append(GTK_MENU_SHELL(aop_menu->menu), @@ -1593,7 +1593,7 @@ } /* Are we dealing with an image? */ - pb = gdk_pixbuf_new_from_file(filename, NULL); + pb = pidgin_pixbuf_new_from_file(filename); if (pb) { _DndData *data = g_malloc(sizeof(_DndData)); gboolean ft = FALSE, im = FALSE; @@ -2265,7 +2265,7 @@ filename = gtk_file_chooser_get_preview_filename( GTK_FILE_CHOOSER(dialog->icon_filesel)); - if (!filename || g_stat(filename, &st) || !(pixbuf = gdk_pixbuf_new_from_file(filename, NULL))) + if (!filename || g_stat(filename, &st) || !(pixbuf = pidgin_pixbuf_new_from_file(filename))) { gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL); gtk_label_set_markup(GTK_LABEL(dialog->icon_text), ""); @@ -3086,17 +3086,134 @@ #endif } -GdkPixbuf * pidgin_pixbuf_from_imgstore(PurpleStoredImage *image) +static GObject *pidgin_pixbuf_from_data_helper(const guchar *buf, gsize count, gboolean animated) +{ + GObject *pixbuf; + GdkPixbufLoader *loader; + GError *error = NULL; + + loader = gdk_pixbuf_loader_new(); + + if (!gdk_pixbuf_loader_write(loader, buf, count, &error) || error) { + purple_debug_warning("gtkutils", "gdk_pixbuf_loader_write() " + "failed with size=%zu: %s\n", count, + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + g_object_unref(G_OBJECT(loader)); + return NULL; + } + + if (!gdk_pixbuf_loader_close(loader, &error) || error) { + purple_debug_warning("gtkutils", "gdk_pixbuf_loader_close() " + "failed for image of size %zu: %s\n", count, + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + g_object_unref(G_OBJECT(loader)); + return NULL; + } + + if (animated) + pixbuf = G_OBJECT(gdk_pixbuf_loader_get_animation(loader)); + else + pixbuf = G_OBJECT(gdk_pixbuf_loader_get_pixbuf(loader)); + if (!pixbuf) { + purple_debug_warning("gtkutils", "%s() returned NULL for image " + "of size %zu\n", + animated ? "gdk_pixbuf_loader_get_animation" + : "gdk_pixbuf_loader_get_pixbuf", count); + g_object_unref(G_OBJECT(loader)); + return NULL; + } + + g_object_ref(pixbuf); + g_object_unref(G_OBJECT(loader)); + + return pixbuf; +} + +GdkPixbuf *pidgin_pixbuf_from_data(const guchar *buf, gsize count) +{ + return GDK_PIXBUF(pidgin_pixbuf_from_data_helper(buf, count, FALSE)); +} + +GdkPixbufAnimation *pidgin_pixbuf_anim_from_data(const guchar *buf, gsize count) +{ + return GDK_PIXBUF_ANIMATION(pidgin_pixbuf_from_data_helper(buf, count, TRUE)); +} + +GdkPixbuf *pidgin_pixbuf_from_imgstore(PurpleStoredImage *image) +{ + return pidgin_pixbuf_from_data(purple_imgstore_get_data(image), + purple_imgstore_get_size(image)); +} + +GdkPixbuf *pidgin_pixbuf_new_from_file(const gchar *filename) { GdkPixbuf *pixbuf; - GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); - gdk_pixbuf_loader_write(loader, purple_imgstore_get_data(image), - purple_imgstore_get_size(image), NULL); - gdk_pixbuf_loader_close(loader, NULL); - pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); - if (pixbuf) - g_object_ref(pixbuf); - g_object_unref(loader); + GError *error = NULL; + + pixbuf = gdk_pixbuf_new_from_file(filename, &error); + if (!pixbuf || error) { + purple_debug_warning("gtkutils", "gdk_pixbuf_new_from_file() " + "returned %s for file %s: %s\n", + pixbuf ? "something" : "nothing", + filename, + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + if (pixbuf) + g_object_unref(G_OBJECT(pixbuf)); + return NULL; + } + + return pixbuf; +} + +GdkPixbuf *pidgin_pixbuf_new_from_file_at_size(const char *filename, int width, int height) +{ + GdkPixbuf *pixbuf; + GError *error = NULL; + + pixbuf = gdk_pixbuf_new_from_file_at_size(filename, + width, height, &error); + if (!pixbuf || error) { + purple_debug_warning("gtkutils", "gdk_pixbuf_new_from_file_at_size() " + "returned %s for file %s: %s\n", + pixbuf ? "something" : "nothing", + filename, + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + if (pixbuf) + g_object_unref(G_OBJECT(pixbuf)); + return NULL; + } + + return pixbuf; +} + +GdkPixbuf *pidgin_pixbuf_new_from_file_at_scale(const char *filename, int width, int height, gboolean preserve_aspect_ratio) +{ + GdkPixbuf *pixbuf; + GError *error = NULL; + + pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, + width, height, preserve_aspect_ratio, &error); + if (!pixbuf || error) { + purple_debug_warning("gtkutils", "gdk_pixbuf_new_from_file_at_scale() " + "returned %s for file %s: %s\n", + pixbuf ? "something" : "nothing", + filename, + error ? error->message : "(no error message)"); + if (error) + g_error_free(error); + if (pixbuf) + g_object_unref(G_OBJECT(pixbuf)); + return NULL; + } + return pixbuf; } diff -r 3e98b34853ee -r 6e5d46ea82f9 pidgin/gtkutils.h --- a/pidgin/gtkutils.h Wed Jun 22 22:10:37 2011 +0000 +++ b/pidgin/gtkutils.h Fri Jun 24 06:54:33 2011 +0000 @@ -834,6 +834,32 @@ GtkWidget *pidgin_add_widget_to_vbox(GtkBox *vbox, const char *widget_label, GtkSizeGroup *sg, GtkWidget *widget, gboolean expand, GtkWidget **p_label); /** + * Create a GdkPixbuf from a chunk of image data. + * + * @param buf The raw binary image data. + * @param count The length of buf in bytes. + * + * @return A GdkPixbuf created from the image data, or NULL if + * there was an error parsing the data. + * + * @since 2.9.0 + */ +GdkPixbuf *pidgin_pixbuf_from_data(const guchar *buf, gsize count); + +/** + * Create a GdkPixbufAnimation from a chunk of image data. + * + * @param buf The raw binary image data. + * @param count The length of buf in bytes. + * + * @return A GdkPixbufAnimation created from the image data, or NULL if + * there was an error parsing the data. + * + * @since 2.9.0 + */ +GdkPixbufAnimation *pidgin_pixbuf_anim_from_data(const guchar *buf, gsize count); + +/** * Create a GdkPixbuf from a PurpleStoredImage. * * @param image A PurpleStoredImage. @@ -845,6 +871,86 @@ GdkPixbuf *pidgin_pixbuf_from_imgstore(PurpleStoredImage *image); /** + * Helper function that calls gdk_pixbuf_new_from_file() and checks both + * the return code and the GError and returns NULL if either one failed. + * + * The gdk-pixbuf documentation implies that it is sufficient to check + * the return value of gdk_pixbuf_new_from_file() to determine + * whether the image was able to be loaded. However, this is not the case + * with gdk-pixbuf 2.23.3 and probably many earlier versions. In some + * cases a GdkPixbuf object is returned that will cause some operations + * (like gdk_pixbuf_scale_simple()) to rapidly consume memory in an + * infinite loop. + * + * This function shouldn't be necessary once Pidgin requires a version of + * gdk-pixbuf where the aforementioned bug is fixed. However, it might be + * nice to keep this function around for the debug message that it logs. + * + * @param filename Name of file to load, in the GLib file name encoding + * + * @return The GdkPixbuf if successful. Otherwise NULL is returned and + * a warning is logged. + * + * @since 2.9.0 + */ +GdkPixbuf *pidgin_pixbuf_new_from_file(const char *filename); + +/** + * Helper function that calls gdk_pixbuf_new_from_file_at_size() and checks + * both the return code and the GError and returns NULL if either one failed. + * + * The gdk-pixbuf documentation implies that it is sufficient to check + * the return value of gdk_pixbuf_new_from_file_at_size() to determine + * whether the image was able to be loaded. However, this is not the case + * with gdk-pixbuf 2.23.3 and probably many earlier versions. In some + * cases a GdkPixbuf object is returned that will cause some operations + * (like gdk_pixbuf_scale_simple()) to rapidly consume memory in an + * infinite loop. + * + * This function shouldn't be necessary once Pidgin requires a version of + * gdk-pixbuf where the aforementioned bug is fixed. However, it might be + * nice to keep this function around for the debug message that it logs. + * + * @param filename Name of file to load, in the GLib file name encoding + * @param width The width the image should have or -1 to not constrain the width + * @param height The height the image should have or -1 to not constrain the height + * + * @return The GdkPixbuf if successful. Otherwise NULL is returned and + * a warning is logged. + * + * @since 2.9.0 + */ +GdkPixbuf *pidgin_pixbuf_new_from_file_at_size(const char *filename, int width, int height); + +/** + * Helper function that calls gdk_pixbuf_new_from_file_at_scale() and checks + * both the return code and the GError and returns NULL if either one failed. + * + * The gdk-pixbuf documentation implies that it is sufficient to check + * the return value of gdk_pixbuf_new_from_file_at_scale() to determine + * whether the image was able to be loaded. However, this is not the case + * with gdk-pixbuf 2.23.3 and probably many earlier versions. In some + * cases a GdkPixbuf object is returned that will cause some operations + * (like gdk_pixbuf_scale_simple()) to rapidly consume memory in an + * infinite loop. + * + * This function shouldn't be necessary once Pidgin requires a version of + * gdk-pixbuf where the aforementioned bug is fixed. However, it might be + * nice to keep this function around for the debug message that it logs. + * + * @param filename Name of file to load, in the GLib file name encoding + * @param width The width the image should have or -1 to not constrain the width + * @param height The height the image should have or -1 to not constrain the height + * @param preserve_aspect_ratio TRUE to preserve the image's aspect ratio + * + * @return The GdkPixbuf if successful. Otherwise NULL is returned and + * a warning is logged. + * + * @since 2.9.0 + */ +GdkPixbuf *pidgin_pixbuf_new_from_file_at_scale(const char *filename, int width, int height, gboolean preserve_aspect_ratio); + +/** * Add scrollbars to a widget * @param widget The child widget * @hscrollbar_policy Horizontal scrolling policy diff -r 3e98b34853ee -r 6e5d46ea82f9 po/ChangeLog --- a/po/ChangeLog Wed Jun 22 22:10:37 2011 +0000 +++ b/po/ChangeLog Fri Jun 24 06:54:33 2011 +0000 @@ -1,5 +1,11 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.9.1 + * German translation updated (Björn Voigt, Jochen Kemnade) + +version 2.9.0 + * No changes + version 2.8.0 * Albanian translation updated (Besnik Bleta) * Bengali translation updated (Jamil Ahmed)