gdk-pixbuf error reporting



Hi,

This patch adds error reporting to the gdk-pixbuf loaders.
Some loaders kind of suck in this respect; namely the code that seems
to have been cut-and-pasted around for ico, bmp, and wbmp appears to
simply dump core if it receives bad data, which isn't so good given
possible security considerations in Evolution, etc. This patch doesn't
try to rewrite loaders, just adds GError where loaders already had
error handling.

The main API decision here was whether to add new API
new_from_file_with_error() or break the old API; I broke the old
API. Stuff using the old API will fail to compile, and can be fixed by
adding the characters ", NULL", so there shouldn't be too much pain.

Will commit this shortly if there are no objections (to HEAD only,
obviously the API breakage can't go in gdk-pixbuf stable).

Havoc

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.1427
diff -u -u -r1.1427 ChangeLog
--- ChangeLog	2000/10/16 17:50:13	1.1427
+++ ChangeLog	2000/10/16 18:00:16
@@ -1,5 +1,19 @@
 2000-10-16  Havoc Pennington  <hp redhat com>
 
+	* demos/*.c: Add error handling
+
+	* gtk/gtktextbuffer.c: don't modify const iterators
+
+	* gtk/gdk-pixbuf-loader.c: Add full error handling here
+
+	* gtk/gtkimage.c (gtk_image_set_from_file): ignore errors
+	on file load
+
+	* gtk/gtkiconfactory.c: Update to reflect addition of error
+	handling to gdk-pixbuf loaders
+
+2000-10-16  Havoc Pennington  <hp redhat com>
+
 	* gtk/gtktreeviewcolumn.c: #include gtklabel.h, fixing 
 	compilation
 
Index: demos/pixbuf-demo.c
===================================================================
RCS file: /cvs/gnome/gtk+/demos/pixbuf-demo.c,v
retrieving revision 1.4
diff -u -u -r1.4 pixbuf-demo.c
--- demos/pixbuf-demo.c	2000/07/26 11:32:24	1.4
+++ demos/pixbuf-demo.c	2000/10/16 18:00:16
@@ -65,7 +65,11 @@
 {
 	int i;
 
-	background = gdk_pixbuf_new_from_file (BACKGROUND_NAME);
+        /* We pass NULL for the error return location, we don't care
+         * about the error message.
+         */
+        
+	background = gdk_pixbuf_new_from_file (BACKGROUND_NAME, NULL);
 	if (!background)
 		return FALSE;
 
@@ -73,7 +77,7 @@
 	back_height = gdk_pixbuf_get_height (background);
 
 	for (i = 0; i < N_IMAGES; i++) {
-		images[i] = gdk_pixbuf_new_from_file (image_names[i]);
+		images[i] = gdk_pixbuf_new_from_file (image_names[i], NULL);
 		if (!images[i])
 			return FALSE;
 	}
Index: demos/testanimation.c
===================================================================
RCS file: /cvs/gnome/gtk+/demos/testanimation.c,v
retrieving revision 1.7
diff -u -u -r1.7 testanimation.c
--- demos/testanimation.c	2000/07/26 11:32:24	1.7
+++ demos/testanimation.c	2000/10/16 18:00:16
@@ -408,8 +408,18 @@
 		return 0;
 	} else {
 		for (i = 1; i < argc; i++) {
-			animation = gdk_pixbuf_animation_new_from_file (argv[i]);
+                        GError *error;
 
+                        error = NULL;
+			animation = gdk_pixbuf_animation_new_from_file (argv[i],
+                                                                        &error);
+
+                        if (animation == NULL) {
+                                g_warning ("Failed to load animation: %s",
+                                           error->message);
+                                g_error_free (error);
+                        }
+                        
 			if (animation) {
 				gint i = 0;
 				GList *listptr;
Index: demos/testpixbuf-scale.c
===================================================================
RCS file: /cvs/gnome/gtk+/demos/testpixbuf-scale.c,v
retrieving revision 1.8
diff -u -u -r1.8 testpixbuf-scale.c
--- demos/testpixbuf-scale.c	2000/06/22 00:05:44	1.8
+++ demos/testpixbuf-scale.c	2000/10/16 18:00:16
@@ -62,7 +62,8 @@
 	GtkWidget *hbox, *label, *hscale;
 	GtkAdjustment *adjustment;
 	GtkRequisition scratch_requisition;
-
+        GError *error;
+        
 	pixbuf_init ();
 
 	gtk_init (&argc, &argv);
@@ -73,9 +74,12 @@
 		exit (1);
 	}
 
-	pixbuf = gdk_pixbuf_new_from_file (argv[1]);
+        error = NULL;
+	pixbuf = gdk_pixbuf_new_from_file (argv[1], &error);
 	if (!pixbuf) {
-		fprintf (stderr, "Cannot load %s\n", argv[1]);
+		fprintf (stderr, "Cannot load image: %s\n",
+                         error->message);
+                g_error_free (error);
 		exit(1);
 	}
 
Index: demos/testpixbuf.c
===================================================================
RCS file: /cvs/gnome/gtk+/demos/testpixbuf.c,v
retrieving revision 1.40
diff -u -u -r1.40 testpixbuf.c
--- demos/testpixbuf.c	2000/10/09 17:22:15	1.40
+++ demos/testpixbuf.c	2000/10/16 18:00:16
@@ -428,22 +428,27 @@
 update_timeout(gpointer data)
 {
         ProgressFileStatus *status = data;
-	gboolean done, error;
+	gboolean done;
+        GError *error;
         
 	done = FALSE;
         error = FALSE;
 	if (!feof(status->imagefile)) {
 		gint nbytes;
-
+                
 		nbytes = fread(status->buf, 1, status->readlen, 
 			       status->imagefile);
 
 
-                error = !gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (status->loader), status->buf, nbytes);
-                if (error) {
-                        G_BREAKPOINT();
+                error = NULL;
+                if (!gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (status->loader), status->buf, nbytes, &error)) {
+                        g_warning ("Error writing to loader: %s",
+                                   error->message);
+                        g_error_free (error);
+                        done = TRUE;
                 }
-
+                        
+                        
         } else { /* Really done */ 
 
                 GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (status->loader); 
@@ -452,11 +457,6 @@
 
         }
 
-        if (error) { 
-                g_warning ("Serious error writing to loader"); 
-                done = TRUE; 
-        } 
-
 	if (done) {
                 gtk_widget_queue_draw(*status->rgbwin);
 		gdk_pixbuf_loader_close (GDK_PIXBUF_LOADER (status->loader));
@@ -556,17 +556,26 @@
                 }
 
                 /* Test loading from inline data. */
-                pixbuf = gdk_pixbuf_new_from_inline (apple_red, FALSE, -1);
+                pixbuf = gdk_pixbuf_new_from_inline (apple_red, FALSE, -1, NULL);
                 new_testrgb_window (pixbuf, "Red apple from inline data");
 
-                pixbuf = gdk_pixbuf_new_from_inline (gnome_foot, TRUE, sizeof (gnome_foot));
+                pixbuf = gdk_pixbuf_new_from_inline (gnome_foot, TRUE, sizeof (gnome_foot), NULL);
                 new_testrgb_window (pixbuf, "Foot from inline data");
                 
 		found_valid = TRUE;
 	} else {
 		for (i = 1; i < argc; i++) {
+                        GError *error;
+
+                        error = NULL;
+			pixbuf = gdk_pixbuf_new_from_file (argv[i], &error);
 
-			pixbuf = gdk_pixbuf_new_from_file (argv[i]);
+                        if (pixbuf == NULL) {
+                                g_warning ("Error loading image: %s",
+                                           error->message);
+                                g_error_free (error);
+                        }
+                        
 #if 0
 			pixbuf = gdk_pixbuf_rotate(pixbuf, 10.0);
 #endif
Index: gdk/gdkpixmap.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkpixmap.c,v
retrieving revision 1.33
diff -u -u -r1.33 gdkpixmap.c
--- gdk/gdkpixmap.c	2000/07/26 11:32:26	1.33
+++ gdk/gdkpixmap.c	2000/10/16 18:00:16
@@ -473,7 +473,7 @@
   if (colormap == NULL)
     colormap = gdk_drawable_get_colormap (window);
   
-  pixbuf = gdk_pixbuf_new_from_file (filename);
+  pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
   if (!pixbuf)
     return NULL;
 
Index: gdk-pixbuf/ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/ChangeLog,v
retrieving revision 1.255
diff -u -u -r1.255 ChangeLog
--- gdk-pixbuf/ChangeLog	2000/10/09 17:22:20	1.255
+++ gdk-pixbuf/ChangeLog	2000/10/16 18:00:16
@@ -1,3 +1,32 @@
+2000-10-16  Havoc Pennington  <hp redhat com>
+
+	* gdk-pixbuf-io.c (gdk_pixbuf_get_module)
+	(gdk_pixbuf_get_named_module) (gdk_pixbuf_load_module): 
+	add error reporting here also
+
+	* make-inline-pixbuf.c (main): use GError
+
+	* io-xpm.c: include unistd.h
+
+	* gdk-pixbuf-util.c: include string.h
+
+	* io-*.c: add error reporting
+	
+	* gdk-pixbuf-animation.c (gdk_pixbuf_animation_new_from_file): add
+	error reporting
+
+	* gdk-pixbuf-io.c (gdk_pixbuf_new_from_file): Add error reporting
+
+	* gdk-pixbuf-io.h: Add GError** to load_increment and load 
+	methods
+
+	* gdk-pixbuf-io.c (gdk_pixbuf_save) (gdk_pixbuf_savev): return 
+	a G_FILE_ERROR if we fail to write or close the file.
+
+	* gdk-pixbuf.h: remove GDK_PIXBUF_ERROR_IO, instead we'll use
+	G_FILE_ERROR_*. Rename enum to GdkPixbufError, properly following
+	the GError naming rules. Add GError** to load functions.
+
 2000-10-06  Havoc Pennington  <hp redhat com>
 
 	* gdk-pixbuf.h: add GdkPixbufAlphaMode
Index: gdk-pixbuf/gdk-pixbuf-animation.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-animation.c,v
retrieving revision 1.11
diff -u -u -r1.11 gdk-pixbuf-animation.c
--- gdk-pixbuf/gdk-pixbuf-animation.c	2000/07/26 11:32:38	1.11
+++ gdk-pixbuf/gdk-pixbuf-animation.c	2000/10/16 18:00:16
@@ -22,6 +22,7 @@
  */
 
 #include <config.h>
+#include <errno.h>
 #include "gdk-pixbuf-io.h"
 #include "gdk-pixbuf-private.h"
 
@@ -92,10 +93,12 @@
 /**
  * gdk_pixbuf_animation_new_from_file:
  * @filename: Name of file to load.
+ * @error: return location for error
  *
  * Creates a new animation by loading it from a file.  The file format is
  * detected automatically.  If the file's format does not support multi-frame
- * images, then an animation with a single frame will be created.
+ * images, then an animation with a single frame will be created. Possible errors
+ * are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
  *
  * Return value: A newly created animation with a reference count of 1, or NULL
  * if any of several error conditions ocurred:  the file could not be opened,
@@ -103,7 +106,8 @@
  * allocate the image buffer, or the image file contained invalid data.
  **/
 GdkPixbufAnimation *
-gdk_pixbuf_animation_new_from_file (const char *filename)
+gdk_pixbuf_animation_new_from_file (const char *filename,
+                                    GError    **error)
 {
 	GdkPixbufAnimation *animation;
 	int size;
@@ -114,25 +118,39 @@
 	g_return_val_if_fail (filename != NULL, NULL);
 
 	f = fopen (filename, "rb");
-	if (!f)
+	if (!f) {
+                g_set_error (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (errno),
+                             _("Failed to open file '%s': %s"),
+                             filename, g_strerror (errno));
 		return NULL;
+        }
 
 	size = fread (&buffer, 1, sizeof (buffer), f);
 
 	if (size == 0) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image file '%s' contains no data"),
+                             filename);
+                
 		fclose (f);
 		return NULL;
 	}
 
-	image_module = gdk_pixbuf_get_module (buffer, size);
+	image_module = gdk_pixbuf_get_module (buffer, size, filename, error);
 	if (!image_module) {
-		g_warning ("Unable to find handler for file: %s", filename);
 		fclose (f);
 		return NULL;
 	}
 
 	if (image_module->module == NULL)
-		gdk_pixbuf_load_module (image_module);
+                if (!gdk_pixbuf_load_module (image_module, error)) {
+                        fclose (f);
+                        return NULL;
+                }
 
 	if (image_module->load_animation == NULL) {
 		GdkPixbuf *pixbuf;
@@ -141,14 +159,35 @@
 		/* Keep this logic in sync with gdk_pixbuf_new_from_file() */
 
 		if (image_module->load == NULL) {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+                                     _("Don't know how to load the animation in file '%s'"),
+                                     filename);                        
 			fclose (f);
 			return NULL;
 		}
 
 		fseek (f, 0, SEEK_SET);
-		pixbuf = (* image_module->load) (f);
+		pixbuf = (* image_module->load) (f, error);
 		fclose (f);
 
+                if (pixbuf == NULL && error != NULL && *error == NULL) {
+                        /* I don't trust these crufty longjmp()'ing image libs
+                         * to maintain proper error invariants, and I don't
+                         * want user code to segfault as a result. We need to maintain
+                         * the invariant that error gets set if NULL is returned.
+                         */
+                        
+                        g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
+                                   image_module->module_name);
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Failed to load image '%s': reason not known, probably a corrupt image file"),
+                                     filename);
+                }
+                
 		if (pixbuf == NULL)
                         return NULL;
 
@@ -167,7 +206,26 @@
 		animation->height = gdk_pixbuf_get_height (pixbuf);
 	} else {
 		fseek (f, 0, SEEK_SET);
-		animation = (* image_module->load_animation) (f);
+		animation = (* image_module->load_animation) (f, error);
+
+                if (animation == NULL && error != NULL && *error == NULL) {
+                        /* I don't trust these crufty longjmp()'ing
+                         * image libs to maintain proper error
+                         * invariants, and I don't want user code to
+                         * segfault as a result. We need to maintain
+                         * the invariant that error gets set if NULL
+                         * is returned.
+                         */
+                        
+                        g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
+                                   image_module->module_name);
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Failed to load animation '%s': reason not known, probably a corrupt animation file"),
+                                     filename);
+                }
+                
 		fclose (f);
 	}
 
Index: gdk-pixbuf/gdk-pixbuf-data.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-data.c,v
retrieving revision 1.13
diff -u -u -r1.13 gdk-pixbuf-data.c
--- gdk-pixbuf/gdk-pixbuf-data.c	2000/09/26 20:22:17	1.13
+++ gdk-pixbuf/gdk-pixbuf-data.c	2000/10/16 18:00:16
@@ -23,6 +23,7 @@
 #include <config.h>
 #include "gdk-pixbuf.h"
 #include "gdk-pixbuf-private.h"
+#include "gdk-pixbuf-i18n.h"
 #include <stdlib.h>
 #include <string.h>
 
@@ -106,7 +107,10 @@
 }
 
 static GdkPixbuf*
-read_raw_inline (const guchar *data, gboolean copy_pixels, int length)
+read_raw_inline (const guchar *data,
+                 gboolean      copy_pixels,
+                 int           length,
+                 GError      **error)
 {
         GdkPixbuf *pixbuf;
         const guchar *p = data;
@@ -116,6 +120,11 @@
         
         if (length >= 0 && length < 12) {
                 /* Not enough buffer to hold the width/height/rowstride */
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image data is partially missing"));
+                
                 return NULL;
         }
 
@@ -123,9 +132,14 @@
         width = read_int (&p);
         height = read_int (&p);
 
-        if (rowstride < width)
+        if (rowstride < width) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image has an incorrect pixel rowstride, perhaps the data was corrupted somehow."));
                 return NULL; /* bad data from untrusted source. */
-
+        }
+        
         /* rowstride >= width, so we can trust width */
         
         length -= 12;
@@ -133,37 +147,71 @@
         /* There's some better way like G_MAXINT/height > rowstride
          * but I'm not sure it works, so stick to this for now.
          */
-        if (((double)height) * ((double)rowstride) > (double)G_MAXINT)
+        if (((double)height) * ((double)rowstride) > (double)G_MAXINT) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image size is impossibly large, perhaps the data was corrupted somehow"));
+                
                 return NULL; /* overflow */
-        
+        }
+
         if (length >= 0 &&
             length < (height * rowstride + 13)) {
                 /* Not enough buffer to hold the remaining header
                  * information plus the data.
                  */
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image data is partially missing, probably it was ocorrupted somehow."));
                 
                 return NULL;
         }
-        
+
         /* Read the remaining 13 bytes of header information */
             
         has_alpha = read_bool (&p) != FALSE;
         colorspace = read_int (&p);
         n_channels = read_int (&p);
         bits_per_sample = read_int (&p);
-
-        if (colorspace != GDK_COLORSPACE_RGB)
+        
+        if (colorspace != GDK_COLORSPACE_RGB) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image has an unknown colorspace code (%d), perhaps the image data was corrupted"),
+                             colorspace);
                 return NULL;
+        }
 
-        if (bits_per_sample != 8)
+        if (bits_per_sample != 8) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image has an improper number of bits per sample (%d), perhaps the image data was corrupted"),
+                             bits_per_sample);
                 return NULL;
-
-        if (has_alpha && n_channels != 4)
+        }
+        
+        if (has_alpha && n_channels != 4) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image has an improper number of channels (%d), perhaps the image data was corrupted"),
+                             n_channels);
                 return NULL;
-
-        if (!has_alpha && n_channels != 3)
+        }
+        
+        if (!has_alpha && n_channels != 3) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image has an improper number of channels (%d), perhaps the image data was corrupted"),
+                             n_channels);
                 return NULL;
-
+        }
+        
         if (copy_pixels) {
                 guchar *pixels;
                 gint dest_rowstride;
@@ -172,10 +220,19 @@
                 pixbuf = gdk_pixbuf_new (colorspace,
                                          has_alpha, bits_per_sample,
                                          width, height);
-
+                
+                if (pixbuf == NULL) {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to store a %d by %d image; try exiting some applications to free memory."),
+                                     width, height);
+                        return NULL;
+                }
+                
                 pixels = gdk_pixbuf_get_pixels (pixbuf);
                 dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
-	
+                
                 for (row = 0; row < height; row++) {
                         memcpy (pixels, p, rowstride);
                         pixels += dest_rowstride;
@@ -190,7 +247,7 @@
                                                    rowstride,
                                                    NULL, NULL);
         }
-
+        
         return pixbuf;
 }
 
@@ -198,24 +255,34 @@
  * gdk_pixbuf_new_from_inline:
  * @data: An inlined GdkPixbuf
  * @copy_pixels: whether to copy the pixels out of the inline data, or to use them in-place
+ * @length: length of the inline data
+ * @error: return location for error
  *
  * Create a #GdkPixbuf from a custom format invented to store pixbuf
- * data in C program code. This library comes with a program called "make-inline-pixbuf"
- * that can write out a variable definition containing an inlined pixbuf.
- * This is useful if you want to ship a program with images, but
- * don't want to depend on any external files.
+ * data in C program code. This library comes with a program called
+ * "make-inline-pixbuf" that can write out a variable definition
+ * containing an inlined pixbuf.  This is useful if you want to ship a
+ * program with images, but don't want to depend on any external
+ * files.
  * 
  * The inline data format contains the pixels in #GdkPixbuf's native
  * format.  Since the inline pixbuf is read-only static data, you
  * don't need to copy it unless you intend to write to it.
  * 
+ * If you create a pixbuf from const inline data compiled into your
+ * program, it's probably safe to ignore errors, since things will
+ * always succeed.  For non-const inline data, you could get out of
+ * memory. For untrusted inline data located at runtime, you could
+ * have corrupt inline data in addition.
+ * 
  * Return value: A newly-created #GdkPixbuf structure with a reference count of
- * 1.
+ * 1, or NULL If error is set.
  **/
 GdkPixbuf*
 gdk_pixbuf_new_from_inline   (const guchar *inline_pixbuf,
                               gboolean      copy_pixels,
-                              int           length)
+                              int           length,
+                              GError      **error)
 {
         const guchar *p;
         GdkPixbuf *pixbuf;
@@ -225,12 +292,20 @@
                 /* not enough bytes to contain even the magic number
                  * and format code.
                  */
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image contained no data."));
                 return NULL;
         }
         
         p = inline_pixbuf;
 
         if (read_int (&p) != GDK_PIXBUF_INLINE_MAGIC_NUMBER) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image isn't in the correct format (inline GdkPixbuf format)"));
                 return NULL;
         }
 
@@ -239,10 +314,15 @@
         switch (format)
         {
         case GDK_PIXBUF_INLINE_RAW:
-                pixbuf = read_raw_inline (p, copy_pixels, length - 8);
+                pixbuf = read_raw_inline (p, copy_pixels, length - 8, error);
                 break;
 
         default:
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                             _("This version of the software is unable to read images with type code %d"),
+                             format);
                 return NULL;
         }
 
Index: gdk-pixbuf/gdk-pixbuf-io.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-io.c,v
retrieving revision 1.46
diff -u -u -r1.46 gdk-pixbuf-io.c
--- gdk-pixbuf/gdk-pixbuf-io.c	2000/10/06 18:26:23	1.46
+++ gdk-pixbuf/gdk-pixbuf-io.c	2000/10/16 18:00:16
@@ -275,8 +275,9 @@
 /* actually load the image handler - gdk_pixbuf_get_module only get a */
 /* reference to the module to load, it doesn't actually load it       */
 /* perhaps these actions should be combined in one function           */
-void
-gdk_pixbuf_load_module (GdkPixbufModule *image_module)
+gboolean
+gdk_pixbuf_load_module (GdkPixbufModule *image_module,
+                        GError         **error)
 {
 	char *module_name;
 	char *path;
@@ -285,7 +286,7 @@
         gpointer save_sym;
 	char *name;
 	
-        g_return_if_fail (image_module->module == NULL);
+        g_return_val_if_fail (image_module->module == NULL, FALSE);
 
 	name = image_module->module_name;
 	
@@ -304,10 +305,14 @@
                 module = g_module_open (path, G_MODULE_BIND_LAZY);
 
                 if (!module) {
-                        g_warning ("Unable to load module: %s: %s", path, g_module_error ());
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_FAILED,
+                                     _("Unable to load image-loading module: %s: %s"),
+                                     path, g_module_error ());
                         g_free (module_name);
                         g_free (path);
-                        return;
+                        return FALSE;
                 }
                 g_free (path);
 	} else {
@@ -337,7 +342,9 @@
 		image_module->load_animation = load_sym;
 
         if (pixbuf_module_symbol (module, name, "image_save", &save_sym))
-          image_module->save = save_sym;        
+          image_module->save = save_sym;
+
+        return TRUE;
 }
 #else
 
@@ -406,8 +413,9 @@
 m_load (xpm);
 m_load_xpm_data (xpm);
 
-void
-gdk_pixbuf_load_module (GdkPixbufModule *image_module)
+gboolean
+gdk_pixbuf_load_module (GdkPixbufModule *image_module,
+                        GError         **error)
 {
 	image_module->module = (void *) 1;
 	
@@ -417,7 +425,7 @@
 		image_module->load_increment = mname (png,load_increment);
 		image_module->stop_load      = mname (png,stop_load);
                 image_module->save           = mname (png,save);
-		return;
+		return TRUE;
 	}
 
 	if (strcmp (image_module->module_name, "bmp") == 0){
@@ -425,7 +433,7 @@
 		image_module->begin_load     = mname (bmp,begin_load);
 		image_module->load_increment = mname (bmp,load_increment);
 		image_module->stop_load      = mname (bmp,stop_load);
-		return;
+		return TRUE;
 	}
 
 	if (strcmp (image_module->module_name, "wbmp") == 0){
@@ -433,7 +441,7 @@
 		image_module->begin_load     = mname (wbmp,begin_load);
 		image_module->load_increment = mname (wbmp,load_increment);
 		image_module->stop_load      = mname (wbmp,stop_load);
-		return;
+		return TRUE;
 	}
 
 	if (strcmp (image_module->module_name, "gif") == 0){
@@ -442,7 +450,7 @@
 		image_module->load_increment = mname (gif,load_increment);
 		image_module->stop_load      = mname (gif,stop_load);
 		image_module->load_animation = mname (gif,load_animation);
-		return;
+		return TRUE;
 	}
 
 	if (strcmp (image_module->module_name, "ico") == 0){
@@ -450,7 +458,7 @@
 		image_module->begin_load     = mname (ico,begin_load);
 		image_module->load_increment = mname (ico,load_increment);
 		image_module->stop_load      = mname (ico,stop_load);
-		return;
+		return TRUE;
 	}
 
 	if (strcmp (image_module->module_name, "jpeg") == 0){
@@ -459,34 +467,42 @@
 		image_module->load_increment = mname (jpeg,load_increment);
 		image_module->stop_load      = mname (jpeg,stop_load);
                 image_module->save           = mname (jpeg,save);
-		return;
+		return TRUE;
 	}
 	if (strcmp (image_module->module_name, "pnm") == 0){
 		image_module->load           = mname (pnm,load);
 		image_module->begin_load     = mname (pnm,begin_load);
 		image_module->load_increment = mname (pnm,load_increment);
 		image_module->stop_load      = mname (pnm,stop_load);
-		return;
+		return TRUE;
 	}
 	if (strcmp (image_module->module_name, "ras") == 0){
 		image_module->load           = mname (ras,load);
 		image_module->begin_load     = mname (ras,begin_load);
 		image_module->load_increment = mname (ras,load_increment);
 		image_module->stop_load      = mname (ras,stop_load);
-		return;
+		return TRUE;
 	}
 	if (strcmp (image_module->module_name, "tiff") == 0){
 		image_module->load           = mname (tiff,load);
 		image_module->begin_load     = mname (tiff,begin_load);
 		image_module->load_increment = mname (tiff,load_increment);
 		image_module->stop_load      = mname (tiff,stop_load);
-		return;
+		return TRUE;
 	}
 	if (strcmp (image_module->module_name, "xpm") == 0){
 		image_module->load           = mname (xpm,load);
 		image_module->load_xpm_data  = mname (xpm,load_xpm_data);
-		return;
+		return TRUE;
 	}
+
+        g_set_error (error,
+                     GDK_PIXBUF_ERROR,
+                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                     _("Image type '%s' is not supported"),
+                     image_module->module_name);
+
+        return FALSE;
 }
 
 
@@ -495,7 +511,8 @@
 
 
 GdkPixbufModule *
-gdk_pixbuf_get_named_module (const char *name)
+gdk_pixbuf_get_named_module (const char *name,
+                             GError **error)
 {
 	int i;
 
@@ -504,11 +521,19 @@
 			return &(file_formats[i]);
 	}
 
+        g_set_error (error,
+                     GDK_PIXBUF_ERROR,
+                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                     _("Image type '%s' is not supported"),
+                     name);
+        
 	return NULL;
 }
 
 GdkPixbufModule *
-gdk_pixbuf_get_module (guchar *buffer, guint size)
+gdk_pixbuf_get_module (guchar *buffer, guint size,
+                       const gchar *filename,
+                       GError **error)
 {
 	int i;
 
@@ -517,15 +542,30 @@
 			return &(file_formats[i]);
 	}
 
+        if (filename)
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                             _("Couldn't recognize the image file format for file '%s'"),
+                             filename);        
+        else
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+                             _("Unrecognized image file format"));
+
+        
 	return NULL;
 }
 
 /**
  * gdk_pixbuf_new_from_file:
  * @filename: Name of file to load.
+ * @error: Return location for an error
  *
  * Creates a new pixbuf by loading an image from a file.  The file format is
- * detected automatically.
+ * detected automatically. If NULL is returned, then @error will be set.
+ * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
  *
  * Return value: A newly-created pixbuf with a reference count of 1, or NULL if
  * any of several error conditions occurred:  the file could not be opened,
@@ -533,7 +573,8 @@
  * allocate the image buffer, or the image file contained invalid data.
  **/
 GdkPixbuf *
-gdk_pixbuf_new_from_file (const char *filename)
+gdk_pixbuf_new_from_file (const char *filename,
+                          GError    **error)
 {
 	GdkPixbuf *pixbuf;
 	int size;
@@ -544,34 +585,82 @@
 	g_return_val_if_fail (filename != NULL, NULL);
 
 	f = fopen (filename, "rb");
-	if (!f)
+	if (!f) {
+                g_set_error (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (errno),
+                             _("Failed to open file '%s': %s"),
+                             filename, g_strerror (errno));
 		return NULL;
+        }
 
 	size = fread (&buffer, 1, sizeof (buffer), f);
 	if (size == 0) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Image file '%s' contains no data"),
+                             filename);
+                
 		fclose (f);
 		return NULL;
 	}
 
-	image_module = gdk_pixbuf_get_module (buffer, size);
-	if (!image_module) {
-		g_warning ("Unable to find handler for file: %s", filename);
-		fclose (f);
-		return NULL;
-	}
+	image_module = gdk_pixbuf_get_module (buffer, size, filename, error);
+        if (image_module == NULL) {
+                fclose (f);
+                return NULL;
+        }
 
 	if (image_module->module == NULL)
-		gdk_pixbuf_load_module (image_module);
+		if (!gdk_pixbuf_load_module (image_module, error)) {
+                        fclose (f);
+                        return NULL;
+                }
 
 	if (image_module->load == NULL) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+                             _("Don't know how to load the image in file '%s'"),
+                             filename);
+                
 		fclose (f);
 		return NULL;
 	}
 
 	fseek (f, 0, SEEK_SET);
-	pixbuf = (* image_module->load) (f);
+	pixbuf = (* image_module->load) (f, error);
 	fclose (f);
 
+        if (pixbuf == NULL && error != NULL && *error == NULL) {
+                /* I don't trust these crufty longjmp()'ing image libs
+                 * to maintain proper error invariants, and I don't
+                 * want user code to segfault as a result. We need to maintain
+                 * the invariant that error gets set if NULL is returned.
+                 */
+                
+                g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", image_module->module_name);
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Failed to load image '%s': reason not known, probably a corrupt image file"),
+                             filename);
+                
+        } else if (error != NULL && *error != NULL) {
+
+          /* Add the filename to the error message */
+          GError *e = *error;
+          gchar *old;
+          
+          old = e->message;
+
+          e->message = g_strdup_printf (_("Failed to load image '%s': %s"),
+                                        filename, old);
+
+          g_free (old);
+        }
+                
 	return pixbuf;
 }
 
@@ -591,7 +680,7 @@
 	GdkPixbuf *pixbuf;
 
 	if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL)
-		gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX]);
+		gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX], NULL);
 
 	if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL) {
 		g_warning ("Can't find gdk-pixbuf module for parsing inline XPM data");
@@ -650,31 +739,26 @@
                       gchar        **values,
                       GError       **error)
 {
-       int i;
        GdkPixbufModule *image_module = NULL;       
-       
-       for (i = 0; file_formats[i].module_name; i++) {
-               if (!strcmp (file_formats[i].module_name, type)) {
-                       image_module = &(file_formats[i]);
-                       break;
-               }
-       }
+
+       image_module = gdk_pixbuf_get_named_module (type, error);
+
+       if (image_module == NULL)
+               return FALSE;
        
-       if (!image_module) {
+       if (image_module->module == NULL)
+               if (!gdk_pixbuf_load_module (image_module, error))
+                       return FALSE;
+
+       if (image_module->save == NULL) {
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
-                            GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
-                            _("This build of gdk-pixbuf does not support saving the image format: %s"), type);
+                            GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+                            _("This build of gdk-pixbuf does not support saving the image format: %s"),
+                            type);
                return FALSE;
        }
-       
-       if (image_module->module == NULL)
-               gdk_pixbuf_load_module (image_module);
-       
-       g_return_val_if_fail (image_module->save != NULL, FALSE);
-
-       
-       
+               
        return (* image_module->save) (filehandle, pixbuf,
                                       keys, values,
                                       error);
@@ -691,7 +775,7 @@
  *
  * Saves pixbuf to a file in @type, which is currently "jpeg" or
  * "png".  If @error is set, FALSE will be returned. Possible errors include those
- * from #GdkPixbufErrorType and those from #GFileErrorType.
+ * in the #GDK_PIXBUF_ERROR domain and those in the #G_FILE_ERROR domain.
  *
  * The variable argument list should be NULL-terminated; if not empty,
  * it should contain pairs of strings that modify the save
@@ -747,8 +831,7 @@
  *
  * Saves pixbuf to a file in @type, which is currently "jpeg" or "png".
  * If @error is set, FALSE will be returned. See gdk_pixbuf_save () for more
- * details. Possible errors include those from #GdkPixbufErrorType and
- * those from #GFileErrorType.
+ * details.
  *
  * Return value: whether an error was set
  **/
@@ -772,8 +855,8 @@
         
         if (f == NULL) {
                 g_set_error (error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_IO,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (errno),
                              _("Failed to open '%s' for writing: %s"),
                              filename, g_strerror (errno));
                 return FALSE;
@@ -793,8 +876,8 @@
 
        if (fclose (f) < 0) {
                g_set_error (error,
-                            GDK_PIXBUF_ERROR,
-                            GDK_PIXBUF_ERROR_IO,
+                            G_FILE_ERROR,
+                            g_file_error_from_errno (errno),
                             _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
                             filename, g_strerror (errno));
                return FALSE;
Index: gdk-pixbuf/gdk-pixbuf-io.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-io.h,v
retrieving revision 1.21
diff -u -u -r1.21 gdk-pixbuf-io.h
--- gdk-pixbuf/gdk-pixbuf-io.h	2000/10/06 18:19:18	1.21
+++ gdk-pixbuf/gdk-pixbuf-io.h	2000/10/16 18:00:16
@@ -55,7 +55,8 @@
 	char *module_name;
 	gboolean (* format_check) (guchar *buffer, int size);
 	GModule *module;
-	GdkPixbuf *(* load) (FILE *f);
+        GdkPixbuf *(* load) (FILE    *f,
+                             GError **error);
         GdkPixbuf *(* load_xpm_data) (const char **data);
 
         /* Incremental loading */
@@ -64,26 +65,33 @@
 				 ModuleUpdatedNotifyFunc update_func,
 				 ModuleFrameDoneNotifyFunc frame_done_func,
 				 ModuleAnimationDoneNotifyFunc anim_done_func,
-				 gpointer user_data);
+				 gpointer user_data,
+                                 GError **error);
         void (* stop_load)          (gpointer context);
         gboolean (* load_increment) (gpointer      context,
                                      const guchar *buf,
-                                     guint         size);
+                                     guint         size,
+                                     GError      **error);
 
 	/* Animation loading */
-	GdkPixbufAnimation *(* load_animation) (FILE *f);
+	GdkPixbufAnimation *(* load_animation) (FILE    *f,
+                                                GError **error);
 
         gboolean (* save) (FILE      *f,
                            GdkPixbuf *pixbuf,
                            gchar    **param_keys,
                            gchar    **param_values,
-                           GError   **err);
+                           GError   **error);
 };
 
 
-GdkPixbufModule *gdk_pixbuf_get_module (guchar *buffer, guint size);
-GdkPixbufModule *gdk_pixbuf_get_named_module (const char *name);
-void gdk_pixbuf_load_module (GdkPixbufModule *image_module);
+GdkPixbufModule *gdk_pixbuf_get_module (guchar *buffer, guint size,
+                                        const gchar *filename,
+                                        GError **error);
+GdkPixbufModule *gdk_pixbuf_get_named_module (const char *name,
+                                              GError **error);
+gboolean gdk_pixbuf_load_module (GdkPixbufModule *image_module,
+                                 GError **error);
 
 
 
Index: gdk-pixbuf/gdk-pixbuf-util.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-util.c,v
retrieving revision 1.9
diff -u -u -r1.9 gdk-pixbuf-util.c
--- gdk-pixbuf/gdk-pixbuf-util.c	2000/10/09 17:22:20	1.9
+++ gdk-pixbuf/gdk-pixbuf-util.c	2000/10/16 18:00:16
@@ -23,6 +23,7 @@
 
 #include <config.h>
 #include "gdk-pixbuf-private.h"
+#include <string.h>
 
 
 
Index: gdk-pixbuf/gdk-pixbuf.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf.h,v
retrieving revision 1.49
diff -u -u -r1.49 gdk-pixbuf.h
--- gdk-pixbuf/gdk-pixbuf.h	2000/10/09 17:22:20	1.49
+++ gdk-pixbuf/gdk-pixbuf.h	2000/10/16 18:00:16
@@ -39,8 +39,8 @@
 /* Alpha compositing mode */
 typedef enum
 {
-  GDK_PIXBUF_ALPHA_BILEVEL,
-  GDK_PIXBUF_ALPHA_FULL
+        GDK_PIXBUF_ALPHA_BILEVEL,
+        GDK_PIXBUF_ALPHA_FULL
 } GdkPixbufAlphaMode;
 
 /* Color spaces; right now only RGB is supported.
@@ -71,14 +71,18 @@
 #define GDK_PIXBUF_ERROR gdk_pixbuf_error_quark ()
 
 typedef enum {
-        /* some kind of failure reading or writing files */
-        GDK_PIXBUF_ERROR_IO,
+        /* image data hosed */
+        GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+        /* no mem to load image */
+        GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
         /* bad option value passed to save routine */
         GDK_PIXBUF_ERROR_BAD_OPTION_VALUE,
         /* unsupported image type (sort of an ENOSYS) */
         GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+        /* unsupported operation (load, save) for image type */
+        GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
         GDK_PIXBUF_ERROR_FAILED
-} GdkPixbufErrorType;
+} GdkPixbufError;
 
 GQuark gdk_pixbuf_error_quark () G_GNUC_CONST;
 
@@ -114,7 +118,8 @@
 
 /* Simple loading */
 
-GdkPixbuf *gdk_pixbuf_new_from_file (const char *filename);
+GdkPixbuf *gdk_pixbuf_new_from_file (const char *filename,
+                                     GError    **error);
 
 GdkPixbuf *gdk_pixbuf_new_from_data (const guchar *data,
 				     GdkColorspace colorspace,
@@ -130,7 +135,8 @@
 /* Read an inline pixbuf */
 GdkPixbuf *gdk_pixbuf_new_from_inline   (const guchar *inline_pixbuf,
                                          gboolean      copy_pixels,
-                                         int           length);
+                                         int           length,
+                                         GError      **error);
 
 
 /* Saving */
@@ -248,7 +254,8 @@
 
 GType               gdk_pixbuf_animation_get_type        (void) G_GNUC_CONST;
 
-GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file   (const char         *filename);
+GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file   (const char         *filename,
+                                                          GError            **error);
 
 GdkPixbufAnimation *gdk_pixbuf_animation_ref             (GdkPixbufAnimation *animation);
 void                gdk_pixbuf_animation_unref           (GdkPixbufAnimation *animation);
Index: gdk-pixbuf/io-bmp.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-bmp.c,v
retrieving revision 1.18
diff -u -u -r1.18 io-bmp.c
--- gdk-pixbuf/io-bmp.c	2000/08/01 21:43:56	1.18
+++ gdk-pixbuf/io-bmp.c	2000/10/16 18:00:16
@@ -176,17 +176,19 @@
 				 ModuleUpdatedNotifyFunc updated_func,
 				 ModuleFrameDoneNotifyFunc frame_done_func,
 				 ModuleAnimationDoneNotifyFunc
-				 anim_done_func, gpointer user_data);
+				 anim_done_func, gpointer user_data,
+                                 GError **error);
 
 void gdk_pixbuf__bmp_image_stop_load(gpointer data);
 gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data, guchar * buf,
-					      guint size);
+					      guint size,
+                                              GError **error);
 
 
 
 /* Shared library entry point --> This should be removed when
    generic_image_load enters gdk-pixbuf-io. */
-GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f)
+GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f, GError **error)
 {
 	guchar membuf[4096];
 	size_t length;
@@ -195,15 +197,22 @@
 	GdkPixbuf *pb;
 
 	State =
-	    gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL);
+	    gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+                                             error);
 
+        if (State == NULL)
+          return NULL;
+        
 	while (feof(f) == 0) {
 		length = fread(membuf, 1, 4096, f);
 		if (length > 0)
-			(void)
-			    gdk_pixbuf__bmp_image_load_increment(State,
-								 membuf,
-								 length);
+                  if (!gdk_pixbuf__bmp_image_load_increment(State,
+                                                            membuf,
+                                                            length,
+                                                            error)) {
+                          gdk_pixbuf__bmp_image_stop_load (State);
+                          return NULL;
+                  }
 
 	}
 	if (State->pixbuf != NULL)
@@ -309,7 +318,8 @@
 				 ModuleUpdatedNotifyFunc updated_func,
 				 ModuleFrameDoneNotifyFunc frame_done_func,
 				 ModuleAnimationDoneNotifyFunc
-				 anim_done_func, gpointer user_data)
+				 anim_done_func, gpointer user_data,
+                                 GError **error)
 {
 	struct bmp_progressive_state *context;
 
@@ -695,8 +705,10 @@
  *
  * append image data onto inrecrementally built output image
  */
-gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data, guchar * buf,
-					      guint size)
+gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data,
+                                              guchar * buf,
+					      guint size,
+                                              GError **error)
 {
 	struct bmp_progressive_state *context =
 	    (struct bmp_progressive_state *) data;
Index: gdk-pixbuf/io-gif.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-gif.c,v
retrieving revision 1.52
diff -u -u -r1.52 io-gif.c
--- gdk-pixbuf/io-gif.c	2000/10/09 17:22:20	1.52
+++ gdk-pixbuf/io-gif.c	2000/10/16 18:00:16
@@ -180,6 +180,9 @@
 	gint draw_xpos;
 	gint draw_ypos;
 	gint draw_pass;
+
+        /* error pointer */
+        GError **error;
 };
 
 static int GetDataBlock (GifContext *, unsigned char *);
@@ -204,7 +207,7 @@
 		count += len;
 		g_print ("Fsize :%d\tcount :%d\t", len, count);
 #endif
-		retval = (fread(buffer, len, 1, context->file) != 0);
+		retval = (fread(buffer, len, 1, context->file) != 0);                
 #ifdef IO_GIFDEBUG
 		if (len < 100) {
 			for (i = 0; i < len; i++)
@@ -212,6 +215,7 @@
 		}
 		g_print ("\n");
 #endif
+                
 		return retval;
 	} else {
 #ifdef IO_GIFDEBUG
@@ -416,10 +420,21 @@
 
 	if (context->code_done) {
 		if (context->code_curbit >= context->code_lastbit) {
-				g_message ("GIF: ran off the end of by bits\n");
+                        g_set_error (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+
 			return -2;
 		}
-		g_message ("trying to read more data after we've done stuff\n");
+                /* Is this supposed to be an error or what? */
+		/* g_message ("trying to read more data after we've done stuff\n"); */
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Internal error in the GIF loader (%s)"),
+                             G_STRLOC);
+                
 		return -2;
 	}
 
@@ -563,8 +578,10 @@
 			*(context->lzw_sp)++ = context->lzw_table[1][code];
 
 			if (code == context->lzw_table[0][code]) {
-				/*g_message (_("GIF: circular table entry BIG ERROR\n"));*/
-				/*gimp_quit ();*/
+                                g_set_error (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("Circular table entry in GIF file"));
 				return -2;
 			}
 			code = context->lzw_table[0][code];
@@ -890,12 +907,18 @@
 	char version[4];
 
 	if (!gif_read (context, buf, 6)) {
-		/* Unable to read magic number */
+		/* Unable to read magic number,
+                 * gif_read() should have set error
+                 */
 		return -1;
 	}
 
 	if (strncmp ((char *) buf, "GIF", 3) != 0) {
 		/* Not a GIF file */
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("File does not appear to be a GIF file"));
 		return -1;
 	}
 
@@ -904,12 +927,17 @@
 
 	if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0)) {
 		/* bad version number, not '87a' or '89a' */
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Version %s of the GIF file format is not supported"),
+                             version);
 		return -1;
 	}
 
 	/* read the screen descriptor */
 	if (!gif_read (context, buf, 7)) {
-		/* Failed to read screen descriptor */
+		/* Failed to read screen descriptor, error set */
 		return -1;
 	}
 
@@ -950,6 +978,12 @@
 	if (context->frame_height > context->height) {
 		/* we don't want to resize things.  So we exit */
 		context->state = GIF_DONE;
+
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("GIF animation contained a frame with an incorrect size"));
+                
 		return -2;
 	}
 
@@ -1092,7 +1126,7 @@
 }
 /* Shared library entry point */
 GdkPixbuf *
-gdk_pixbuf__gif_image_load (FILE *file)
+gdk_pixbuf__gif_image_load (FILE *file, GError **error)
 {
 	GifContext *context;
 	GdkPixbuf *pixbuf;
@@ -1101,7 +1135,8 @@
 
 	context = new_context ();
 	context->file = file;
-
+        context->error = error;
+        
 	gif_main_loop (context);
 
 	pixbuf = context->pixbuf;
@@ -1115,7 +1150,8 @@
 				  ModuleUpdatedNotifyFunc update_func,
 				  ModuleFrameDoneNotifyFunc frame_done_func,
 				  ModuleAnimationDoneNotifyFunc anim_done_func,
-				  gpointer user_data)
+				  gpointer user_data,
+                                  GError **error)
 {
 	GifContext *context;
 
@@ -1123,6 +1159,7 @@
 	count = 0;
 #endif
 	context = new_context ();
+        context->error = error;
 	context->prepare_func = prepare_func;
 	context->update_func = update_func;
 	context->frame_done_func = frame_done_func;
@@ -1148,11 +1185,14 @@
 }
 
 gboolean
-gdk_pixbuf__gif_image_load_increment (gpointer data, guchar *buf, guint size)
+gdk_pixbuf__gif_image_load_increment (gpointer data, guchar *buf, guint size,
+                                      GError **error)
 {
 	gint retval;
 	GifContext *context = (GifContext *) data;
 
+        context->error = error;
+        
 	if (context->amount_needed == 0) {
 		/* we aren't looking for some bytes. */
 		/* we can use buf now, but we don't want to keep it around at all.
@@ -1206,7 +1246,8 @@
 }
 
 GdkPixbufAnimation *
-gdk_pixbuf__gif_image_load_animation (FILE *file)
+gdk_pixbuf__gif_image_load_animation (FILE *file,
+                                      GError **error)
 {
 	GifContext *context;
 	GdkPixbufAnimation *animation;
@@ -1214,6 +1255,9 @@
 	g_return_val_if_fail (file != NULL, NULL);
 
 	context = new_context ();
+
+        context->error = error;
+        
 	context->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
 
 	context->animation->n_frames = 0;
Index: gdk-pixbuf/io-ico.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-ico.c,v
retrieving revision 1.11
diff -u -u -r1.11 io-ico.c
--- gdk-pixbuf/io-ico.c	2000/08/01 21:43:56	1.11
+++ gdk-pixbuf/io-ico.c	2000/10/16 18:00:16
@@ -158,16 +158,18 @@
 				 ModuleUpdatedNotifyFunc updated_func,
 				 ModuleFrameDoneNotifyFunc frame_done_func,
 				 ModuleAnimationDoneNotifyFunc anim_done_func,
-				 gpointer user_data);
+				 gpointer user_data,
+                                 GError **error);
 void gdk_pixbuf__ico_image_stop_load(gpointer data);
-gboolean gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size);
+gboolean gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size,
+                                              GError **error);
 
 
 
 /* Shared library entry point --> Can go when generic_image_load
    enters gdk-pixbuf-io */
 GdkPixbuf *
-gdk_pixbuf__ico_image_load(FILE * f)
+gdk_pixbuf__ico_image_load(FILE * f, GError **error)
 {
 	guchar *membuf;
 	size_t length;
@@ -175,7 +177,11 @@
 
 	GdkPixbuf *pb;
 
-	State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, NULL, NULL);
+	State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL,
+                                                 NULL, NULL, error);
+        if (State == NULL)
+          return NULL;
+        
 	membuf = g_malloc(4096);
 
 	g_assert(membuf != NULL);
@@ -183,8 +189,11 @@
 	while (feof(f) == 0) {
 		length = fread(membuf, 1, 4096, f);
 		if (length > 0)
-			gdk_pixbuf__ico_image_load_increment(State, membuf, length);
-
+                        if (!gdk_pixbuf__ico_image_load_increment(State, membuf, length,
+                                                                  error)) {
+                                gdk_pixbuf__ico_image_stop_load (State);
+                                return NULL;
+                        }
 	}
 	g_free(membuf);
 	if (State->pixbuf != NULL)
@@ -370,7 +379,8 @@
 				 ModuleUpdatedNotifyFunc updated_func,
 				 ModuleFrameDoneNotifyFunc frame_done_func,
 				 ModuleAnimationDoneNotifyFunc anim_done_func,
-				 gpointer user_data)
+				 gpointer user_data,
+                                 GError **error)
 {
 	struct ico_progressive_state *context;
 
@@ -633,7 +643,8 @@
  * append image data onto inrecrementally built output image
  */
 gboolean
-gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size)
+gdk_pixbuf__ico_image_load_increment(gpointer data, guchar * buf, guint size,
+                                     GError **error)
 {
 	struct ico_progressive_state *context =
 	    (struct ico_progressive_state *) data;
Index: gdk-pixbuf/io-jpeg.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-jpeg.c,v
retrieving revision 1.33
diff -u -u -r1.33 io-jpeg.c
--- gdk-pixbuf/io-jpeg.c	2000/10/09 17:22:20	1.33
+++ gdk-pixbuf/io-jpeg.c	2000/10/16 18:00:16
@@ -74,6 +74,7 @@
 struct error_handler_data {
 	struct jpeg_error_mgr pub;
 	sigjmp_buf setjmp_buffer;
+        GError **error;
 };
 
 /* progressive loader context */
@@ -92,32 +93,53 @@
 	struct error_handler_data     jerr;
 } JpegProgContext;
 
-GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f);
+GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
 gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func, 
 					    ModuleUpdatedNotifyFunc func2,
 					    ModuleFrameDoneNotifyFunc func3,
 					    ModuleAnimationDoneNotifyFunc func4,
-					    gpointer user_data);
+					    gpointer user_data,
+                                            GError **error);
 void gdk_pixbuf__jpeg_image_stop_load (gpointer context);
-gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context, guchar *buf, guint size);
+gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context, guchar *buf, guint size,
+                                               GError **error);
 
 
 static void
 fatal_error_handler (j_common_ptr cinfo)
 {
-	/* FIXME:
-	 * We should somehow signal what error occurred to the caller so the
-	 * caller can handle the error message */
 	struct error_handler_data *errmgr;
-
+        char buffer[JMSG_LENGTH_MAX];
+        
 	errmgr = (struct error_handler_data *) cinfo->err;
-	cinfo->err->output_message (cinfo);
+        
+        /* Create the message */
+        (* cinfo->err->format_message) (cinfo, buffer);
+
+        /* broken check for *error == NULL for robustness against
+         * crappy JPEG library
+         */
+        if (errmgr->error && *errmgr->error == NULL) {
+                g_set_error (errmgr->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Error interpreting JPEG image file (%s)"),
+                             buffer);
+        }
+        
 	siglongjmp (errmgr->setjmp_buffer, 1);
 
-	/* incase the jmp buf isn't initted? */
-	exit(1);
+        g_assert_not_reached ();
 }
 
+static void
+output_message_handler (j_common_ptr cinfo)
+{
+  /* This method keeps libjpeg from dumping crap to stderr */
+
+  /* do nothing */
+}
+
 /* Destroy notification function for the pixbuf */
 static void
 free_buffer (guchar *pixels, gpointer data)
@@ -158,7 +180,7 @@
 
 /* Shared library entry point */
 GdkPixbuf *
-gdk_pixbuf__jpeg_image_load (FILE *f)
+gdk_pixbuf__jpeg_image_load (FILE *f, GError **error)
 {
 	gint w, h, i;
 	guchar *pixels = NULL;
@@ -175,7 +197,10 @@
 	/* setup error handler */
 	cinfo.err = jpeg_std_error (&jerr.pub);
 	jerr.pub.error_exit = fatal_error_handler;
+        jerr.pub.output_message = output_message_handler;
 
+        jerr.error = error;
+        
 	if (sigsetjmp (jerr.setjmp_buffer, 1)) {
 		/* Whoops there was a jpeg error */
 		if (pixels)
@@ -199,6 +224,17 @@
 	pixels = malloc (h * w * 3);
 	if (!pixels) {
 		jpeg_destroy_decompress (&cinfo);
+
+                /* broken check for *error == NULL for robustness against
+                 * crappy JPEG library
+                 */
+                if (error && *error == NULL) {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to load image, try exiting some applications to free memory"));
+                }
+                
 		return NULL;
 	}
 
@@ -286,7 +322,8 @@
 				   ModuleUpdatedNotifyFunc  updated_func,
 				   ModuleFrameDoneNotifyFunc frame_func,
 				   ModuleAnimationDoneNotifyFunc anim_done_func,
-				   gpointer user_data)
+				   gpointer user_data,
+                                   GError **error)
 {
 	JpegProgContext *context;
 	my_source_mgr   *src;
@@ -308,7 +345,9 @@
 
 	context->cinfo.err = jpeg_std_error (&context->jerr.pub);
 	context->jerr.pub.error_exit = fatal_error_handler;
-
+        context->jerr.pub.output_message = output_message_handler;
+        context->jerr.error = error;
+        
 	src = (my_src_ptr) context->cinfo.src;
 	src->pub.init_source = init_source;
 	src->pub.fill_input_buffer = fill_input_buffer;
@@ -318,6 +357,8 @@
 	src->pub.bytes_in_buffer = 0;
 	src->pub.next_input_byte = NULL;
 
+        context->jerr.error = NULL;
+        
 	return (gpointer) context;
 }
 
@@ -364,7 +405,8 @@
  * append image data onto inrecrementally built output image
  */
 gboolean
-gdk_pixbuf__jpeg_image_load_increment (gpointer data, guchar *buf, guint size)
+gdk_pixbuf__jpeg_image_load_increment (gpointer data, guchar *buf, guint size,
+                                       GError **error)
 {
 	JpegProgContext *context = (JpegProgContext *)data;
 	struct jpeg_decompress_struct *cinfo;
@@ -382,6 +424,8 @@
 
 	cinfo = &context->cinfo;
 
+        context->jerr.error = error;
+        
 	/* XXXXXXX (drmike) - loop(s) below need to be recoded now I
          *                    have a grasp of what the flow needs to be!
          */
@@ -641,12 +685,13 @@
        g_return_val_if_fail (pixels != NULL, FALSE);
 
        /* allocate a small buffer to convert image data */
-       buf = malloc (w * 3 * sizeof (guchar));
-       g_return_val_if_fail (buf != NULL, FALSE);
+       buf = g_malloc (w * 3 * sizeof (guchar));
 
        /* set up error handling */
        jerr.pub.error_exit = fatal_error_handler;
-
+       jerr.pub.output_message = output_message_handler;
+       jerr.error = error;
+       
        cinfo.err = jpeg_std_error (&(jerr.pub));
        if (sigsetjmp (jerr.setjmp_buffer, 1)) {
                jpeg_destroy_compress (&cinfo);
Index: gdk-pixbuf/io-png.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-png.c,v
retrieving revision 1.33
diff -u -u -r1.33 io-png.c
--- gdk-pixbuf/io-png.c	2000/10/06 18:19:18	1.33
+++ gdk-pixbuf/io-png.c	2000/10/16 18:00:16
@@ -140,6 +140,38 @@
 #endif
 }
 
+static void
+png_simple_error_callback(png_structp png_save_ptr,
+                          png_const_charp error_msg)
+{
+        GError **error;
+        
+        error = png_get_error_ptr(png_save_ptr);
+
+        /* I don't trust libpng to call the error callback only once,
+         * so check for already-set error
+         */
+        if (error && *error == NULL) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_FAILED,
+                             _("Fatal error saving PNG image file: %s"),
+                             error_msg);
+        }
+}
+
+static void
+png_simple_warning_callback(png_structp png_save_ptr,
+                            png_const_charp warning_msg)
+{
+        /* Don't print anything; we should not be dumping junk to
+         * stderr, since that may be bad for some apps. If it's
+         * important enough to display, we need to add a GError
+         * **warning return location wherever we have an error return
+         * location.
+         */
+}
+
 /* Destroy notification function for the pixbuf */
 static void
 free_buffer (guchar *pixels, gpointer data)
@@ -149,7 +181,7 @@
 
 /* Shared library entry point */
 GdkPixbuf *
-gdk_pixbuf__png_image_load (FILE *f)
+gdk_pixbuf__png_image_load (FILE *f, GError **error)
 {
 	png_structp png_ptr;
 	png_infop info_ptr, end_info;
@@ -159,7 +191,10 @@
 	png_bytepp rows;
 	guchar *pixels;
 
-	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
+                                          error,
+                                          png_simple_error_callback,
+                                          png_simple_warning_callback);
 	if (!png_ptr)
 		return NULL;
 
@@ -197,6 +232,16 @@
 
 	pixels = malloc (w * h * bpp);
 	if (!pixels) {
+                /* Check error NULL, normally this would be broken,
+                 * but libpng makes me want to code defensively.
+                 */
+                if (error && *error == NULL) {
+                        g_set_error (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to load PNG file"));
+                }
+                
 		png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
 		return NULL;
 	}
@@ -273,6 +318,7 @@
         
         guint fatal_error_occurred : 1;
 
+        GError **error;
 };
 
 gpointer
@@ -280,7 +326,8 @@
 				  ModuleUpdatedNotifyFunc update_func,
 				  ModuleFrameDoneNotifyFunc frame_done_func,
 				  ModuleAnimationDoneNotifyFunc anim_done_func,
-				  gpointer user_data)
+				  gpointer user_data,
+                                  GError **error)
 {
         LoadContext* lc;
         
@@ -297,6 +344,7 @@
         lc->first_pass_seen_in_chunk = -1;
         lc->last_pass_seen_in_chunk = -1;
         lc->max_row_seen_in_chunk = -1;
+        lc->error = error;
         
         /* Create the main PNG context struct */
 
@@ -308,13 +356,15 @@
 
         if (lc->png_read_ptr == NULL) {
                 g_free(lc);
+                /* error callback should have set the error */
                 return NULL;
         }
-
+        
 	if (setjmp (lc->png_read_ptr->jmpbuf)) {
 		if (lc->png_info_ptr)
 			png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL);
                 g_free(lc);
+                /* error callback should have set the error */
                 return NULL;
 	}
 
@@ -325,6 +375,7 @@
         if (lc->png_info_ptr == NULL) {
                 png_destroy_read_struct(&lc->png_read_ptr, NULL, NULL);
                 g_free(lc);
+                /* error callback should have set the error */
                 return NULL;
         }
 
@@ -335,6 +386,11 @@
                                     png_end_callback);
         
 
+        /* We don't want to keep modifying error after returning here,
+         * it may no longer be valid.
+         */
+        lc->error = NULL;
+        
         return lc;
 }
 
@@ -352,7 +408,8 @@
 }
 
 gboolean
-gdk_pixbuf__png_image_load_increment(gpointer context, guchar *buf, guint size)
+gdk_pixbuf__png_image_load_increment(gpointer context, guchar *buf, guint size,
+                                     GError **error)
 {
         LoadContext* lc = context;
 
@@ -364,17 +421,20 @@
         lc->first_pass_seen_in_chunk = -1;
         lc->last_pass_seen_in_chunk = -1;
         lc->max_row_seen_in_chunk = -1;
+        lc->error = error;
         
         /* Invokes our callbacks as needed */
 	if (setjmp (lc->png_read_ptr->jmpbuf)) {
+                lc->error = NULL;
 		return FALSE;
 	} else {
 		png_process_data(lc->png_read_ptr, lc->png_info_ptr, buf, size);
 	}
 
-        if (lc->fatal_error_occurred)
+        if (lc->fatal_error_occurred) {
+                lc->error = NULL;
                 return FALSE;
-        else {
+        } else {
                 if (lc->first_row_seen_in_chunk >= 0) {
                         /* We saw at least one row */
                         gint pass_diff = lc->last_pass_seen_in_chunk - lc->first_pass_seen_in_chunk;
@@ -417,6 +477,8 @@
 						  lc->notify_user_data);
                         }
                 }
+
+                lc->error = NULL;
                 
                 return TRUE;
         }
@@ -437,7 +499,6 @@
 
         if (lc->fatal_error_occurred)
                 return;
-        
 
         setup_png_transformations(lc->png_read_ptr,
                                   lc->png_info_ptr,
@@ -458,6 +519,13 @@
         if (lc->pixbuf == NULL) {
                 /* Failed to allocate memory */
                 lc->fatal_error_occurred = TRUE;
+                if (lc->error && *lc->error == NULL) {
+                        g_set_error (lc->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Insufficient memory to store a %ld by %ld image; try exiting some applications to reduce memory usage"),
+                                     width, height);
+                }
                 return;
         }
         
@@ -521,8 +589,17 @@
         lc = png_get_error_ptr(png_read_ptr);
         
         lc->fatal_error_occurred = TRUE;
-        
-        fprintf(stderr, "Fatal error loading PNG: %s\n", error_msg);
+
+        /* I don't trust libpng to call the error callback only once,
+         * so check for already-set error
+         */
+        if (lc->error && *lc->error == NULL) {
+                g_set_error (lc->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("Fatal error reading PNG image file: %s"),
+                             error_msg);
+        }
 }
 
 static void
@@ -532,12 +609,18 @@
         LoadContext* lc;
         
         lc = png_get_error_ptr(png_read_ptr);
-        
-        fprintf(stderr, "Warning loading PNG: %s\n", warning_msg);
+
+        /* Don't print anything; we should not be dumping junk to
+         * stderr, since that may be bad for some apps. If it's
+         * important enough to display, we need to add a GError
+         * **warning return location wherever we have an error return
+         * location.
+         */
 }
 
 
 /* Save */
+
 gboolean
 gdk_pixbuf__png_image_save (FILE          *f, 
                             GdkPixbuf     *pixbuf, 
@@ -545,8 +628,6 @@
                             gchar        **values,
                             GError       **error)
 {
-        /* FIXME error handling is broken */
-        
        png_structp png_ptr;
        png_infop info_ptr;
        guchar *ptr;
@@ -583,7 +664,9 @@
        pixels = gdk_pixbuf_get_pixels (pixbuf);
 
        png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
-                                          NULL, NULL, NULL);
+                                          error,
+                                          png_simple_error_callback,
+                                          png_simple_warning_callback);
 
        g_return_val_if_fail (png_ptr != NULL, FALSE);
 
@@ -599,8 +682,8 @@
        png_init_io (png_ptr, f);
        if (has_alpha) {
                png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
-                            PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
-                            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+                             PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 #ifdef WORDS_BIGENDIAN
                png_set_swap_alpha (png_ptr);
 #else
@@ -608,9 +691,23 @@
 #endif
        } else {
                png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
-                            PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
-                            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+                             PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+                             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
                data = malloc (w * 3 * sizeof (char));
+
+               if (data == NULL) {
+                       /* Check error NULL, normally this would be broken,
+                        * but libpng makes me want to code defensively.
+                        */
+                       if (error && *error == NULL) {
+                               g_set_error (error,
+                                            GDK_PIXBUF_ERROR,
+                                            GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                            _("Insufficient memory to save PNG file"));
+                       }
+                       png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+                       return FALSE;
+               }
        }
        sig_bit.red = bpc;
        sig_bit.green = bpc;
Index: gdk-pixbuf/io-pnm.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-pnm.c,v
retrieving revision 1.18
diff -u -u -r1.18 io-pnm.c
--- gdk-pixbuf/io-pnm.c	2000/10/09 17:22:20	1.18
+++ gdk-pixbuf/io-pnm.c	2000/10/16 18:00:16
@@ -76,17 +76,21 @@
 	gboolean got_header;   /* have we loaded pnm header? */
 	
 	guint scan_state;
+
+	GError **error;
 	
 } PnmLoaderContext;
 
-GdkPixbuf   *gdk_pixbuf__pnm_image_load          (FILE *f);
+GdkPixbuf   *gdk_pixbuf__pnm_image_load          (FILE *f, GError **error);
 gpointer    gdk_pixbuf__pnm_image_begin_load     (ModulePreparedNotifyFunc func, 
 						  ModuleUpdatedNotifyFunc func2,
 						  ModuleFrameDoneNotifyFunc frame_done_func,
 						  ModuleAnimationDoneNotifyFunc anim_done_func,
-						  gpointer user_data);
+						  gpointer user_data,
+						  GError **error);
 void        gdk_pixbuf__pnm_image_stop_load      (gpointer context);
-gboolean    gdk_pixbuf__pnm_image_load_increment (gpointer context, guchar *buf, guint size);
+gboolean    gdk_pixbuf__pnm_image_load_increment (gpointer context, guchar *buf, guint size,
+						  GError **error);
 
 static void explode_bitmap_into_buf              (PnmLoaderContext *context);
 static void explode_gray_into_buf                (PnmLoaderContext *context);
@@ -178,7 +182,7 @@
 
 /* skip over whitespace and comments in input buffer */
 static gint
-pnm_skip_whitespace (PnmIOBuffer *inbuf)
+pnm_skip_whitespace (PnmIOBuffer *inbuf, GError **error)
 {
 	register guchar *inptr;
 	guchar *inend;
@@ -208,7 +212,7 @@
 
 /* read next number from buffer */
 static gint
-pnm_read_next_value (PnmIOBuffer *inbuf, guint *value)
+pnm_read_next_value (PnmIOBuffer *inbuf, guint *value, GError **error)
 {
 	register guchar *inptr, *word, *p;
 	guchar *inend, buf[128];
@@ -220,7 +224,7 @@
 	g_return_val_if_fail (value != NULL, PNM_FATAL_ERR);
 	
 	/* skip white space */
-	if ((retval = pnm_skip_whitespace (inbuf)) != PNM_OK)
+	if ((retval = pnm_skip_whitespace (inbuf, error)) != PNM_OK)
 		return retval;
 	
 	inend = inbuf->byte + inbuf->nbytes;
@@ -237,8 +241,13 @@
 	
 	/* get the value */
 	*value = strtol (buf, &endptr, 10);
-	if (*endptr != '\0')
+	if (*endptr != '\0') {
+		g_set_error (error,
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+			     _("PNM loader expected to find an integer, but didn't"));
 		return PNM_FATAL_ERR;
+	}
 	
 	inbuf->byte = p;
 	inbuf->nbytes = (guint) (inend - p);
@@ -263,8 +272,13 @@
 		if (inbuf->nbytes < 2)
 			return PNM_SUSPEND;
 		
-		if (*inbuf->byte != 'P')
+		if (*inbuf->byte != 'P') {
+			g_set_error (context->error,
+				     GDK_PIXBUF_ERROR,
+				     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+				     _("PNM file has an incorrect initial byte"));
 			return PNM_FATAL_ERR;
+		}
 		
 		inbuf->byte++;
 		inbuf->nbytes--;
@@ -289,6 +303,10 @@
 			context->type = PNM_FORMAT_PPM_RAW;
 			break;
 		default:
+			g_set_error (context->error,
+				     GDK_PIXBUF_ERROR,
+				     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+				     _("PNM file is not in a recognized PNM subformat"));
 			return PNM_FATAL_ERR;
 		}
 		
@@ -303,13 +321,19 @@
 		/* read the pixmap width */
 		guint width = 0;
 		
-		retval = pnm_read_next_value (inbuf, &width);
+		retval = pnm_read_next_value (inbuf, &width,
+					      context->error);
 		
-		if (retval != PNM_OK)
+		if (retval != PNM_OK) 
 			return retval;
 		
-		if (!width)
+		if (!width) {
+			g_set_error (context->error,
+				     GDK_PIXBUF_ERROR,
+				     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+				     _("PNM file has an image width of 0"));
 			return PNM_FATAL_ERR;
+		}
 		
 		context->width = width;
 	}
@@ -318,13 +342,19 @@
 		/* read the pixmap height */
 		guint height = 0;
 		
-		retval = pnm_read_next_value (inbuf, &height);
+		retval = pnm_read_next_value (inbuf, &height,
+					      context->error);
 		
 		if (retval != PNM_OK)
 			return retval;
 		
-		if (!height)
+		if (!height) {
+			g_set_error (context->error,
+				     GDK_PIXBUF_ERROR,
+				     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+				     _("PNM file has an image height of 0"));
 			return PNM_FATAL_ERR;
+		}
 		
 		context->height = height;
 	}
@@ -335,13 +365,19 @@
 	case PNM_FORMAT_PGM:
 	case PNM_FORMAT_PGM_RAW:
 		if (!context->maxval) {
-			retval = pnm_read_next_value (inbuf, &context->maxval);
+			retval = pnm_read_next_value (inbuf, &context->maxval,
+						      context->error);
 			
 			if (retval != PNM_OK)
 				return retval;
 			
-			if (context->maxval == 0)
+			if (context->maxval == 0) {
+				g_set_error (context->error,
+					     GDK_PIXBUF_ERROR,
+					     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+					     _("Maximum color value in PNM file is 0"));
 				return PNM_FATAL_ERR;
+			}
 		}
 		break;
 	default:
@@ -375,7 +411,10 @@
 		numpix = inbuf->nbytes / 3;
 		break;
 	default:
-		g_warning ("io-pnm.c: Illegal raw pnm type!\n");
+		g_set_error (context->error,
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+			     _("Raw PNM image type is invalid"));
 		return PNM_FATAL_ERR;
 	}
 	
@@ -400,7 +439,10 @@
 		offset = context->output_col * 3;
 		break;
 	default:
-		g_warning ("io-pnm.c: Illegal raw pnm type!\n");
+		g_set_error (context->error,
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+			     _("Raw PNM image type is invalid"));
 		return PNM_FATAL_ERR;
 	}
 	
@@ -429,7 +471,11 @@
 		}
 		break;
 	default:
-		g_warning ("Invalid raw pnm format!");
+		g_set_error (context->error,
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+			     _("Raw PNM image type is invalid"));
+		return PNM_FATAL_ERR;
 	}
 	
 	inbuf->byte += numbytes;
@@ -485,7 +531,11 @@
 		break;
 		
 	default:
-		g_warning ("Can't happen\n");
+		g_set_error (context->error,
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+			     _("PNM image format is invalid"));
+
 		return PNM_FATAL_ERR;
 	}
 	
@@ -499,7 +549,8 @@
 		}
 		
 		for (i = context->scan_state; i < numval; i++) {
-			retval = pnm_read_next_value (inbuf, &value);
+			retval = pnm_read_next_value (inbuf, &value,
+						      context->error);
 			if (retval != PNM_OK) {
 				/* save state and return */
 				context->scan_state = i;
@@ -522,7 +573,11 @@
 					*dptr++ = (guchar)(255 * value / context->maxval);
 				break;
 			default:
-				g_warning ("io-pnm.c: Illegal ascii pnm type!\n");
+				g_set_error (context->error,
+					     GDK_PIXBUF_ERROR,
+					     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+					     _("PNM image format is invalid"));
+				return PNM_FATAL_ERR;
 				break;
 			}
 		}
@@ -577,7 +632,11 @@
 			return retval;
 		break;
 	default:
-		g_warning ("Cannot load these image types (yet)\n");
+		g_set_error (context->error,
+			     GDK_PIXBUF_ERROR,
+			     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
+			     _("PNM image loader does not support this PNM subformat"));
+
 		return PNM_FATAL_ERR;
 	}
 	
@@ -586,7 +645,7 @@
 
 /* Shared library entry point */
 GdkPixbuf *
-gdk_pixbuf__pnm_image_load (FILE *f)
+gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
 {
 	PnmLoaderContext context;
 	PnmIOBuffer *inbuf;
@@ -608,6 +667,7 @@
 	context.got_header = FALSE;
 	context.did_prescan = FALSE;
 	context.scan_state = 0;
+	context.error = error;
 	
 	inbuf = &context.inbuf;
 	
@@ -647,7 +707,8 @@
 		
 		/* scan until we hit image data */
 		if (!context.did_prescan) {
-			retval = pnm_skip_whitespace (inbuf);
+			retval = pnm_skip_whitespace (inbuf,
+						      context.error);
 			if (retval == PNM_FATAL_ERR)
 				return NULL;
 			else if (retval == PNM_SUSPEND)
@@ -675,7 +736,7 @@
 			} else if (retval == PNM_FATAL_ERR) {
 				if (context.pixbuf)
 					gdk_pixbuf_unref (context.pixbuf);
-				g_warning ("io-pnm.c: error reading rows..\n");
+
 				return NULL;
 			}
 		}
@@ -703,7 +764,8 @@
 				  ModuleUpdatedNotifyFunc  updated_func,
 				  ModuleFrameDoneNotifyFunc frame_done_func,
 				  ModuleAnimationDoneNotifyFunc anim_done_func,
-				  gpointer user_data)
+				  gpointer user_data,
+				  GError **error)
 {
 	PnmLoaderContext *context;
 	
@@ -722,6 +784,8 @@
 	
 	context->inbuf.nbytes = 0;
 	context->inbuf.byte  = NULL;
+
+	context->error = error;
 	
 	return (gpointer) context;
 }
@@ -752,7 +816,8 @@
  * append image data onto inrecrementally built output image
  */
 gboolean
-gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size)
+gdk_pixbuf__pnm_image_load_increment (gpointer data, guchar *buf, guint size,
+				      GError **error)
 {
 	PnmLoaderContext *context = (PnmLoaderContext *)data;
 	PnmIOBuffer *inbuf;
@@ -764,6 +829,8 @@
 	
 	g_return_val_if_fail (context != NULL, FALSE);
 	g_return_val_if_fail (buf != NULL, FALSE);
+
+	context->error = error;
 	
 	bufhd = buf;
 	inbuf = &context->inbuf;
@@ -811,7 +878,8 @@
 		
 		/* scan until we hit image data */
 		if (!context->did_prescan) {
-			retval = pnm_skip_whitespace (inbuf);
+			retval = pnm_skip_whitespace (inbuf,
+						      context->error);
 			
 			if (retval == PNM_FATAL_ERR)
 				return FALSE;
@@ -850,7 +918,6 @@
 			} else if (retval == PNM_FATAL_ERR) {
 				if (context->pixbuf)
 					gdk_pixbuf_unref (context->pixbuf);
-				g_warning ("io-pnm.c: error reading rows.\n");
 				return FALSE;
 			} else if (retval == PNM_OK) {	
 				/* send updated signal */
Index: gdk-pixbuf/io-ras.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-ras.c,v
retrieving revision 1.15
diff -u -u -r1.15 io-ras.c
--- gdk-pixbuf/io-ras.c	2000/08/01 21:43:56	1.15
+++ gdk-pixbuf/io-ras.c	2000/10/16 18:00:16
@@ -98,14 +98,16 @@
 				 ModuleUpdatedNotifyFunc updated_func,
 				 ModuleFrameDoneNotifyFunc frame_done_func,
 				 ModuleAnimationDoneNotifyFunc anim_done_func,
-				 gpointer user_data);
+				 gpointer user_data,
+                                 GError **error);
 void gdk_pixbuf__ras_image_stop_load(gpointer data);
-gboolean gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size);
+gboolean gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size,
+                                              GError **error);
 
 
 
 /* Shared library entry point */
-GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f)
+GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f, GError **error)
 {
 	guchar *membuf;
 	size_t length;
@@ -113,7 +115,8 @@
 	
 	GdkPixbuf *pb;
 	
-	State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, NULL, NULL);
+	State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL,
+                                                 NULL, NULL, error);
 	
 	membuf = g_malloc(4096);
 	
@@ -121,8 +124,12 @@
 	
 	while (feof(f) == 0) {
 		length = fread(membuf, 1, 4096, f);
-		(void)gdk_pixbuf__ras_image_load_increment(State, membuf, length);
-	} 
+                if (!gdk_pixbuf__ras_image_load_increment(State, membuf, length,
+                                                          error)) {
+                        gdk_pixbuf__ras_image_stop_load (State);
+                        return NULL;
+                }
+	}
 	g_free(membuf);
 	if (State->pixbuf != NULL)
 		gdk_pixbuf_ref(State->pixbuf);
@@ -213,7 +220,8 @@
 				 ModuleUpdatedNotifyFunc updated_func,
 				 ModuleFrameDoneNotifyFunc frame_done_func,
 				 ModuleAnimationDoneNotifyFunc anim_done_func,
-				 gpointer user_data)
+				 gpointer user_data,
+                                 GError **error)
 {
 	struct ras_progressive_state *context;
 
@@ -385,7 +393,8 @@
  * append image data onto inrecrementally built output image
  */
 gboolean
-gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size)
+gdk_pixbuf__ras_image_load_increment(gpointer data, guchar * buf, guint size,
+                                     GError **error)
 {
 	struct ras_progressive_state *context =
 	    (struct ras_progressive_state *) data;
Index: gdk-pixbuf/io-tiff.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-tiff.c,v
retrieving revision 1.21
diff -u -u -r1.21 io-tiff.c
--- gdk-pixbuf/io-tiff.c	2000/10/09 17:22:20	1.21
+++ gdk-pixbuf/io-tiff.c	2000/10/16 18:00:16
@@ -148,7 +148,8 @@
 				   ModuleUpdatedNotifyFunc update_func,
 				   ModuleFrameDoneNotifyFunc frame_done_func,
 				   ModuleAnimationDoneNotifyFunc anim_done_func,
-				   gpointer user_data)
+				   gpointer user_data,
+                                   GError **error)
 {
 	TiffData *context;
 	gint fd;
Index: gdk-pixbuf/io-wbmp.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-wbmp.c,v
retrieving revision 1.6
diff -u -u -r1.6 io-wbmp.c
--- gdk-pixbuf/io-wbmp.c	2000/08/09 02:56:13	1.6
+++ gdk-pixbuf/io-wbmp.c	2000/10/16 18:00:16
@@ -67,16 +67,18 @@
 				  ModuleUpdatedNotifyFunc updated_func,
 				  ModuleFrameDoneNotifyFunc frame_done_func,
 				  ModuleAnimationDoneNotifyFunc
-				  anim_done_func, gpointer user_data);
+				  anim_done_func, gpointer user_data,
+                                  GError **error);
 
 void gdk_pixbuf__wbmp_image_stop_load(gpointer data);
 gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data, guchar * buf,
-					       guint size);
+					       guint size,
+                                               GError **error);
 
 
 /* Shared library entry point --> This should be removed when
    generic_image_load enters gdk-pixbuf-io. */
-GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f)
+GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
 {
 	size_t length;
 	char membuf[4096];
@@ -84,14 +86,19 @@
 
 	GdkPixbuf *pb;
 
-	State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL);
+	State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+                                                  error);
 
+        if (State == NULL)
+          return NULL;
+        
 	while (feof(f) == 0) {
 		length = fread(membuf, 1, 4096, f);
 		if (length > 0)
 		  gdk_pixbuf__wbmp_image_load_increment(State,
 							membuf,
-							length);
+							length,
+                                                        error);
 
 	}
 	if (State->pixbuf != NULL)
@@ -111,10 +118,11 @@
 
 gpointer
 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
-				 ModuleUpdatedNotifyFunc updated_func,
-				 ModuleFrameDoneNotifyFunc frame_done_func,
-				 ModuleAnimationDoneNotifyFunc
-				 anim_done_func, gpointer user_data)
+                                  ModuleUpdatedNotifyFunc updated_func,
+                                  ModuleFrameDoneNotifyFunc frame_done_func,
+                                  ModuleAnimationDoneNotifyFunc
+                                  anim_done_func, gpointer user_data,
+                                  GError **error)
 {
 	struct wbmp_progressive_state *context;
 
@@ -221,7 +229,7 @@
  * append image data onto inrecrementally built output image
  */
 gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data, guchar * buf,
-					      guint size)
+                                               guint size, GError **error)
 {
 	struct wbmp_progressive_state *context =
 	    (struct wbmp_progressive_state *) data;
Index: gdk-pixbuf/io-xpm.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-xpm.c,v
retrieving revision 1.21
diff -u -u -r1.21 io-xpm.c
--- gdk-pixbuf/io-xpm.c	2000/10/09 17:22:20	1.21
+++ gdk-pixbuf/io-xpm.c	2000/10/16 18:00:16
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <glib.h>
+#include <unistd.h>
 #include "gdk-pixbuf-private.h"
 #include "gdk-pixbuf-io.h"
 
@@ -1400,7 +1401,8 @@
                                   ModuleUpdatedNotifyFunc update_func,
                                   ModuleFrameDoneNotifyFunc frame_done_func,
                                   ModuleAnimationDoneNotifyFunc anim_done_func,
-                                  gpointer user_data)
+                                  gpointer user_data,
+                                  GError **error)
 {
        XPMContext *context;
        gint fd;
Index: gdk-pixbuf/make-inline-pixbuf.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/make-inline-pixbuf.c,v
retrieving revision 1.2
diff -u -u -r1.2 make-inline-pixbuf.c
--- gdk-pixbuf/make-inline-pixbuf.c	2000/09/26 20:22:17	1.2
+++ gdk-pixbuf/make-inline-pixbuf.c	2000/10/16 18:00:16
@@ -187,15 +187,16 @@
   while (i < argc)
     {
       GdkPixbuf *pixbuf;
+      GError *error;
 
       g_assert ((i + 1) < argc);
-      
-      pixbuf = gdk_pixbuf_new_from_file (argv[i+1]);
 
+      error = NULL;
+      pixbuf = gdk_pixbuf_new_from_file (argv[i+1], &error);
+
       if (pixbuf == NULL)
         {
-          fprintf (stderr, "Failed to open image file `%s': %s\n",
-                   argv[i+1], strerror (errno));
+          fprintf (stderr, "%s\n", error->message);
 
           exit (1);
         }
Index: gtk/gdk-pixbuf-loader.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gdk-pixbuf-loader.c,v
retrieving revision 1.43
diff -u -u -r1.43 gdk-pixbuf-loader.c
--- gtk/gdk-pixbuf-loader.c	2000/10/09 17:22:20	1.43
+++ gtk/gdk-pixbuf-loader.c	2000/10/16 18:00:17
@@ -338,20 +338,32 @@
 }
 
 static gint
-gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader, const char *image_type)
+gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
+                               const char      *image_type,
+                               GError         **error)
 {
   GdkPixbufLoaderPrivate *priv = loader->private;
 
-  if(image_type)
-    priv->image_module = gdk_pixbuf_get_named_module (image_type);
+  if (image_type)
+    {
+      priv->image_module = gdk_pixbuf_get_named_module (image_type,
+                                                        error);
+    }
   else
-    priv->image_module = gdk_pixbuf_get_module (priv->header_buf, priv->header_buf_offset);
+    {
+      g_return_val_if_fail (priv->header_buf_offset > 0, 0);
+      priv->image_module = gdk_pixbuf_get_module (priv->header_buf,
+                                                  priv->header_buf_offset,
+                                                  NULL,
+                                                  error);
+    }
   
   if (priv->image_module == NULL)
     return 0;
   
   if (priv->image_module->module == NULL)
-    gdk_pixbuf_load_module (priv->image_module);
+    if (!gdk_pixbuf_load_module (priv->image_module, error))
+      return 0;
   
   if (priv->image_module->module == NULL)
     return 0;
@@ -360,8 +372,12 @@
       (priv->image_module->stop_load == NULL) ||
       (priv->image_module->load_increment == NULL))
     {
-      g_warning (G_STRLOC ": module %s does not support incremental loading.\n",
-		 priv->image_module->module_name);
+      g_set_error (error,
+                   GDK_PIXBUF_ERROR,
+                   GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+                   _("Incremental loading of image type '%s' is not supported"),
+                   image_type);
+
       return 0;
     }
   
@@ -369,16 +385,33 @@
 						  gdk_pixbuf_loader_update,
 						  gdk_pixbuf_loader_frame_done,
 						  gdk_pixbuf_loader_animation_done,
-						  loader);
+						  loader,
+                                                  error);
   
   if (priv->context == NULL)
     {
-      g_warning (G_STRLOC ": Failed to begin progressive load");
+      /* Defense against broken loaders; DO NOT take this as a GError
+       * example
+       */
+      if (error && *error == NULL)
+        {
+          g_warning ("Bug! loader '%s' didn't set an error on failure",
+                     priv->image_module->module_name);
+          g_set_error (error,
+                       GDK_PIXBUF_ERROR,
+                       GDK_PIXBUF_ERROR_FAILED,
+                       _("Internal error: Image loader module '%s'"
+                         " failed to begin loading an image, but didn't"
+                         " give a reason for the failure"),
+                       priv->image_module->module_name);
+
+        }
+      
       return 0;
     }
   
   if (priv->header_buf_offset
-      && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset))
+      && priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset, error))
     return priv->header_buf_offset;
   
   return 0;
@@ -387,7 +420,8 @@
 static int
 gdk_pixbuf_loader_eat_header_write (GdkPixbufLoader *loader,
 				    const guchar    *buf,
-				    gsize            count)
+				    gsize            count,
+                                    GError         **error)
 {
   gint n_bytes;
   GdkPixbufLoaderPrivate *priv = loader->private;
@@ -399,7 +433,7 @@
   
   if (priv->header_buf_offset >= LOADER_HEADER_SIZE)
     {
-      if (gdk_pixbuf_loader_load_module (loader, NULL) == 0)
+      if (gdk_pixbuf_loader_load_module (loader, NULL, error) == 0)
 	return 0;
     }
   
@@ -411,11 +445,14 @@
  * @loader: A pixbuf loader.
  * @buf: Pointer to image data.
  * @count: Length of the @buf buffer in bytes.
+ * @error: return location for errors
  *
- * This will cause a pixbuf loader to parse the next @count bytes of an image.
- * It will return TRUE if the data was loaded successfully, and FALSE if an
- * error occurred.  In the latter case, the loader will be closed, and will not
- * accept further writes.
+ * This will cause a pixbuf loader to parse the next @count bytes of
+ * an image.  It will return TRUE if the data was loaded successfully,
+ * and FALSE if an error occurred.  In the latter case, the loader
+ * will be closed, and will not accept further writes. If FALSE is
+ * returned, @error will be set to an error from the #GDK_PIXBUF_ERROR
+ * domain.
  *
  * Return value: #TRUE if the write was successful, or #FALSE if the loader
  * cannot parse the buffer.
@@ -423,7 +460,8 @@
 gboolean
 gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
 			 const guchar    *buf,
-			 gsize            count)
+			 gsize            count,
+                         GError         **error)
 {
   GdkPixbufLoaderPrivate *priv;
   
@@ -442,7 +480,7 @@
     {
       gint eaten;
       
-      eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count);
+      eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count, error);
       if (eaten <= 0)
 	return FALSE;
       
@@ -451,8 +489,27 @@
     }
   
   if (count > 0 && priv->image_module->load_increment)
-    return priv->image_module->load_increment (priv->context, buf, count);
-  
+    {
+      gboolean retval;
+      retval = priv->image_module->load_increment (priv->context, buf, count,
+                                                   error);
+      if (!retval && error && *error == NULL)
+        {
+          /* Fix up busted image loader */
+          g_warning ("Bug! loader '%s' didn't set an error on failure",
+                     priv->image_module->module_name);
+          g_set_error (error,
+                       GDK_PIXBUF_ERROR,
+                       GDK_PIXBUF_ERROR_FAILED,
+                       _("Internal error: Image loader module '%s'"
+                         " failed to begin loading an image, but didn't"
+                         " give a reason for the failure"),
+                       priv->image_module->module_name);
+        }
+
+      return retval;
+    }
+      
   return TRUE;
 }
 
@@ -477,13 +534,22 @@
  * Return value: A newly-created pixbuf loader.
  **/
 GdkPixbufLoader *
-gdk_pixbuf_loader_new_with_type (const char *image_type)
+gdk_pixbuf_loader_new_with_type (const char *image_type,
+                                 GError    **error)
 {
   GdkPixbufLoader *retval;
-
+  GError *tmp;
+  
   retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
 
-  gdk_pixbuf_loader_load_module(retval, image_type);
+  tmp = NULL;
+  gdk_pixbuf_loader_load_module(retval, image_type, &tmp);
+  if (tmp != NULL)
+    {
+      g_propagate_error (error, tmp);
+      g_object_unref (G_OBJECT (retval));
+      return NULL;
+    }
 
   return retval;
 }
@@ -579,7 +645,7 @@
   
   /* We have less the 128 bytes in the image.  Flush it, and keep going. */
   if (priv->image_module == NULL)
-    gdk_pixbuf_loader_load_module (loader, NULL);
+    gdk_pixbuf_loader_load_module (loader, NULL, NULL);
   
   if (priv->image_module && priv->image_module->stop_load)
     priv->image_module->stop_load (priv->context);
Index: gtk/gdk-pixbuf-loader.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gdk-pixbuf-loader.h,v
retrieving revision 1.17
diff -u -u -r1.17 gdk-pixbuf-loader.h
--- gtk/gdk-pixbuf-loader.h	2000/08/30 00:33:36	1.17
+++ gtk/gdk-pixbuf-loader.h	2000/10/16 18:00:17
@@ -72,10 +72,12 @@
 
 GtkType              gdk_pixbuf_loader_get_type      (void) G_GNUC_CONST;
 GdkPixbufLoader *    gdk_pixbuf_loader_new           (void);
-GdkPixbufLoader *    gdk_pixbuf_loader_new_with_type (const char *image_type);
+GdkPixbufLoader *    gdk_pixbuf_loader_new_with_type (const char *image_type,
+                                                      GError    **error);
 gboolean             gdk_pixbuf_loader_write         (GdkPixbufLoader *loader,
 						      const guchar    *buf,
-						      gsize            count);
+						      gsize            count,
+                                                      GError         **error);
 GdkPixbuf *          gdk_pixbuf_loader_get_pixbuf    (GdkPixbufLoader *loader);
 GdkPixbufAnimation * gdk_pixbuf_loader_get_animation (GdkPixbufLoader *loader);
 void                 gdk_pixbuf_loader_close         (GdkPixbufLoader *loader);
Index: gtk/gtkiconfactory.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkiconfactory.c,v
retrieving revision 1.4
diff -u -u -r1.4 gtkiconfactory.c
--- gtk/gtkiconfactory.c	2000/10/04 16:39:43	1.4
+++ gtk/gtkiconfactory.c	2000/10/16 18:00:17
@@ -27,6 +27,7 @@
 #include "gtkiconfactory.h"
 #include "stock-icons/gtkstockpixbufs.h"
 #include "gtkstock.h"
+#include "gtkintl.h"
 #include <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
@@ -214,7 +215,7 @@
 
   set = gtk_icon_set_new ();
 
-  source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1);
+  source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1, NULL);
 
   g_assert (source.pixbuf);
 
@@ -236,7 +237,7 @@
 
   set = gtk_icon_set_new ();
 
-  source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1);
+  source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1, NULL);
 
   g_assert (source.pixbuf);
 
@@ -651,6 +652,7 @@
   
   if (source->pixbuf == NULL)
     {
+      GError *error;
       gchar *full;
       
       g_assert (source->filename);
@@ -659,8 +661,9 @@
         full = gtk_rc_find_pixmap_in_path (NULL, source->filename);
       else
         full = g_strdup (source->filename);
-      
-      source->pixbuf = gdk_pixbuf_new_from_file (full);
+
+      error = NULL;
+      source->pixbuf = gdk_pixbuf_new_from_file (full, &error);
 
       g_free (full);
       
@@ -669,7 +672,8 @@
           /* Remove this icon source so we don't keep trying to
            * load it.
            */
-          g_warning ("Failed to load icon '%s'", source->filename);
+          g_warning (_("Error loading icon: %s"), error->message);
+          g_error_free (error);
           
           icon_set->sources = g_slist_remove (icon_set->sources, source);
 
Index: gtk/gtkimage.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkimage.c,v
retrieving revision 1.12
diff -u -u -r1.12 gtkimage.c
--- gtk/gtkimage.c	2000/09/26 20:22:13	1.12
+++ gtk/gtkimage.c	2000/10/16 18:00:17
@@ -255,7 +255,7 @@
   if (filename == NULL)
     return;
   
-  pixbuf = gdk_pixbuf_new_from_file (filename);
+  pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
 
   if (pixbuf == NULL)
     return;
Index: gtk/gtktextbuffer.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktextbuffer.c,v
retrieving revision 1.13
diff -u -u -r1.13 gtktextbuffer.c
--- gtk/gtktextbuffer.c	2000/10/04 14:23:09	1.13
+++ gtk/gtktextbuffer.c	2000/10/16 18:00:17
@@ -1508,16 +1508,19 @@
                          const GtkTextIter *start,
                          const GtkTextIter *end)
 {
+  GtkTextIter start_tmp = *start;
+  GtkTextIter end_tmp = *end;
+  
   g_return_if_fail(tag != NULL);
-
-  gtk_text_iter_reorder (start, end);
+  
+  gtk_text_iter_reorder (&start_tmp, &end_tmp);
   
   if (apply)
     gtk_signal_emit (GTK_OBJECT(buffer), signals[APPLY_TAG],
-                     tag, start, end);
+                     tag, &start_tmp, &end_tmp);
   else
     gtk_signal_emit (GTK_OBJECT(buffer), signals[REMOVE_TAG],
-                     tag, start, end);
+                     tag, &start_tmp, &end_tmp);
 }
 
 




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]