pidgin.2.9.0: 1b3d9b3d: applied changes from 6cf1aee8ac5e3c836af...

markdoliner at pidgin.im markdoliner at pidgin.im
Fri Jun 24 01:09:16 EDT 2011


----------------------------------------------------------------------
Revision: 1b3d9b3df8497b2273716e872abfc59b48a567d4
Parent:   b5dacc3619f2b5f5cc81e8d2869682d9446252b8
Author:   markdoliner at pidgin.im
Date:     06/22/11 03:09:42
Branch:   im.pidgin.pidgin.2.9.0
URL: http://d.pidgin.im/viewmtn/revision/info/1b3d9b3df8497b2273716e872abfc59b48a567d4

Changelog: 

applied changes from 6cf1aee8ac5e3c836af832eaf26ccedd611dc70b
             through e802003adbf0be4496de3de8ac03b47c1e471d00

Original commit message:
Start looking at the GError parameter every time we call these functions:
- gdk_pixbuf_loader_write
- gdk_pixbuf_loader_close
- gdk_pixbuf_new_from_file
- gdk_pixbuf_new_from_file_at_size
- gdk_pixbuf_new_from_file_at_scale

There are times when gdkpixbuf returns a semi-invalid GdkPixbuf object and
also sets the GError.  If this happens we want to discard and ignore the
GdkPixbuf object because it can cause problems.  For example, calling
gdk_pixbuf_scale_simple() causes gdkpixbuf to rapidly consume memory in
an infinite loop.  And that's bad.

This commit adds some helper functions to gtkutils.[c|h] that make it a
little easier to check the GError value.  We should use them everywhere
we call any of the above functions.

Changes against parent b5dacc3619f2b5f5cc81e8d2869682d9446252b8

  patched  pidgin/gtkaccount.c
  patched  pidgin/gtkblist.c
  patched  pidgin/gtkconv.c
  patched  pidgin/gtkdialogs.c
  patched  pidgin/gtkft.c
  patched  pidgin/gtkimhtml.c
  patched  pidgin/gtkmain.c
  patched  pidgin/gtkprefs.c
  patched  pidgin/gtkrequest.c
  patched  pidgin/gtksmiley.c
  patched  pidgin/gtkstatusbox.c
  patched  pidgin/gtkutils.c
  patched  pidgin/gtkutils.h

-------------- next part --------------
============================================================
--- pidgin/gtkimhtml.c	3f067cd89bd1a5435ea299fb9df1269b3d6f24cf
+++ pidgin/gtkimhtml.c	940a06658b489086b8aacb8da8bfd651912f5584
@@ -5057,17 +5057,9 @@ void gtk_imhtml_insert_image_at_iter(Gtk
 
 		data = imhtml->funcs->image_get_data(image);
 		len = imhtml->funcs->image_get_size(image);
+		if (data && len)
+			anim = pidgin_pixbuf_anim_from_data(data, len);
 
-		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 (anim) {
============================================================
--- pidgin/gtkconv.c	8f0665ce1cf62aa0886e99d5c403e7462104b42a
+++ pidgin/gtkconv.c	1100c8ea5ae0a3c2b2ad8f0b1fe26b8bfb1b8dfd
@@ -6408,8 +6408,8 @@ pidgin_conv_custom_smiley_write(PurpleCo
 {
 	PidginConversation *gtkconv;
 	GtkIMHtmlSmiley *smiley;
-	GdkPixbufLoader *loader;
 	const char *sml;
+	GError *error = NULL;
 
 	sml = purple_account_get_protocol_name(conv->account);
 	gtkconv = PIDGIN_CONVERSATION(conv);
@@ -6422,11 +6422,24 @@ pidgin_conv_custom_smiley_write(PurpleCo
 	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
@@ -6434,8 +6447,8 @@ pidgin_conv_custom_smiley_close(PurpleCo
 {
 	PidginConversation *gtkconv;
 	GtkIMHtmlSmiley *smiley;
-	GdkPixbufLoader *loader;
 	const char *sml;
+	GError *error = NULL;
 
 	g_return_if_fail(conv  != NULL);
 	g_return_if_fail(smile != NULL);
@@ -6447,17 +6460,27 @@ pidgin_conv_custom_smiley_close(PurpleCo
 	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
@@ -6957,10 +6980,6 @@ pidgin_conv_update_buddy_icon(PurpleConv
 
 	PurpleBuddy *buddy;
 
-	GdkPixbufLoader *loader;
-	GdkPixbufAnimation *anim;
-	GError *err = NULL;
-
 	PurpleStoredImage *custom_img = NULL;
 	gconstpointer data = NULL;
 	size_t len;
@@ -7038,7 +7057,6 @@ pidgin_conv_update_buddy_icon(PurpleConv
 
 	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,
@@ -7047,7 +7065,6 @@ pidgin_conv_update_buddy_icon(PurpleConv
 		}
 
 		data = purple_buddy_icon_get_data(icon, &len);
-
 		if (data == NULL)
 		{
 			gtk_widget_set_size_request(gtkconv->u.im->icon_container,
@@ -7056,25 +7073,13 @@ pidgin_conv_update_buddy_icon(PurpleConv
 		}
 	}
 
-	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)) {
============================================================
--- pidgin/gtkutils.c	b95797e31c92492ca20a4c2d89261c7f3e17acf2
+++ pidgin/gtkutils.c	1786e81a63d0ab5a59a2b7549c3772f732c9fe73
@@ -615,7 +615,7 @@ pidgin_create_prpl_icon_from_prpl(Purple
 				    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 @@ create_protocols_menu(const char *defaul
 			                                  "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 @@ create_protocols_menu(const char *defaul
 			                                  "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 @@ pidgin_dnd_file_manage(GtkSelectionData 
 		}
 
 		/* 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 @@ icon_preview_change_cb(GtkFileChooser *w
 	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,20 +3086,137 @@ gboolean pidgin_auto_parent_window(GtkWi
 #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;
+}
+
 static void url_copy(GtkWidget *w, gchar *url)
 {
 	GtkClipboard *clipboard;
============================================================
--- pidgin/gtkutils.h	676ca68e2078a0cf9352151d511d3bc023119e7d
+++ pidgin/gtkutils.h	cb65c2c7e5eeb58198d24149c9155f84bf919208
@@ -834,6 +834,32 @@ GtkWidget *pidgin_add_widget_to_vbox(Gtk
 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(P
 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
============================================================
--- pidgin/gtkft.c	8018e061cb4b35cd24f81afd64aaebd60dac6e34
+++ pidgin/gtkft.c	61e433c5220b64ab25711815465a05575338bb8d
@@ -1149,8 +1149,8 @@ pidgin_xfer_add_thumbnail(PurpleXfer *xf
 
 	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);
============================================================
--- pidgin/gtkblist.c	1801513e52b71a71fc44a78f78581f06b30e43b5
+++ pidgin/gtkblist.c	fddddc1983ab6d2762f5d04c0f29055e413838f2
@@ -2643,7 +2643,6 @@ static GdkPixbuf *pidgin_blist_get_buddy
                                               gboolean scaled, gboolean greyed)
 {
 	gsize len;
-	GdkPixbufLoader *loader;
 	PurpleBuddy *buddy = NULL;
 	PurpleGroup *group = NULL;
 	const guchar *data = NULL;
@@ -2710,21 +2709,20 @@ static GdkPixbuf *pidgin_blist_get_buddy
 			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 @@ static GdkPixbuf * _pidgin_blist_get_cac
 		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 */
============================================================
--- pidgin/gtkprefs.c	fdaaf5541043689510936f07247c23cb61547170
+++ pidgin/gtkprefs.c	32709c4a648bcdbb3bd5027f40cc1853091b7218
@@ -382,7 +382,7 @@ smileys_refresh_theme_list(void)
 		 * LEAK - Gentoo memprof thinks pixbuf is leaking here... but it
 		 * looks like it should be ok to me.  Anyone know what's up?  --Mark
 		 */
-		pixbuf = (theme->icon ? 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 @@ prefs_themes_sort(PurpleTheme *theme)
 
 		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 @@ prefs_themes_sort(PurpleTheme *theme)
 
 		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 @@ prefs_themes_refresh(void)
 	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 */
============================================================
--- pidgin/gtkrequest.c	c13851355e046995c5e133960c40c9e4c2fe48cd
+++ pidgin/gtkrequest.c	34975d99212a717c71be3397cadac524c9aaf4cb
@@ -653,35 +653,30 @@ pidgin_request_action_with_icon(const ch
 
 	/* 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 @@ create_image_field(PurpleRequestField *f
 {
 	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 @@ create_list_field(PurpleRequestField *fi
 			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),
============================================================
--- pidgin/gtkaccount.c	8a277ae15f51ce1ed181564712529bde952d4c83
+++ pidgin/gtkaccount.c	bf12dbbb67c479c9fe78946059f476220a450657
@@ -2135,7 +2135,7 @@ populate_accounts_list(AccountsWindow *d
 	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));
============================================================
--- pidgin/gtkdialogs.c	24b4069907ed369364f737bdea18ad35e5c535fd
+++ pidgin/gtkdialogs.c	3d75956b21e4f633caad5d2b0286cfe3fcbc4363
@@ -433,7 +433,7 @@ pidgin_build_help_dialog(const char *tit
 
 	/* 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 */
============================================================
--- pidgin/gtkmain.c	a1f2225d089236b67598eec6d9e3f851ae52d772
+++ pidgin/gtkmain.c	69d42840b836ea2694aece86bda10a75609c675b
@@ -270,7 +270,7 @@ ui_main(void)
 	/* use the nice PNG icon for all the windows */
 	for(i=0; i<G_N_ELEMENTS(icon_sizes); i++) {
 		icon_path = g_build_filename(DATADIR, "icons", "hicolor", icon_sizes[i].dir, "apps", icon_sizes[i].filename, NULL);
-		icon = gdk_pixbuf_new_from_file(icon_path, NULL);
+		icon = pidgin_pixbuf_new_from_file(icon_path);
 		g_free(icon_path);
 		if (icon) {
 			icons = g_list_append(icons,icon);
============================================================
--- pidgin/gtkstatusbox.c	72c8d57eae71c4a0660bab63eee2cf76f71e30fc
+++ pidgin/gtkstatusbox.c	fcf329296a14acb9aa85d435f345980deb121d73
@@ -2225,22 +2225,45 @@ pidgin_status_box_redisplay_buddy_icon(P
 
 	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);
 	}
 
============================================================
--- pidgin/gtksmiley.c	6d46183c5d632080616458ba17af366c8c7947e6
+++ pidgin/gtksmiley.c	4f3b709d3423b5230eb2b738a9da8c858a10b79f
@@ -332,7 +332,7 @@ static void do_add_file_cb(const char *f
 
 	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 @@ smiley_got_url(PurpleUtilFetchUrlData *u
 	FILE *f;
 	gchar *path;
 	size_t wc;
-	GError *err = NULL;
 	PidginSmiley *ps;
 	GdkPixbuf *image;
 
@@ -709,13 +708,11 @@ smiley_got_url(PurpleUtilFetchUrlData *u
 	}
 	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);


More information about the Commits mailing list