pixbuf animation



Hi,

After much cursing of the foul GIF "specification," I have animation
working pretty well.

Appended is the patch I came up with.

GdkPixbufAnimation and GdkPixbufAnimationIter are now abstract base
classes. The individual loaders have to override them.

Playing an animation works in terms of timestamps, much like
libmng. You specify a start time, and later request already-composited
pixbufs to display for a given timestamp. A nice side-effect here is
that we automatically drop frames for smoothness if the CPU or network
can't keep up with the animation.

This should allow an MNG animation loader. The only problem is that in
libmng there's only one iterator per animation, so to implement this
API you'd need to copy the MNG image data for every view on the
animation. I'm going to mail the libmng maintainer and whine about
this.

With progressive loading, things should just work properly; the
animation will stream in and the iterator will give you the right
composite image for the amount of image data currently available.

Havoc


Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/ChangeLog,v
retrieving revision 1.287
diff -u -u -r1.287 ChangeLog
--- ChangeLog	2001/04/22 19:52:55	1.287
+++ ChangeLog	2001/05/04 16:35:10
@@ -1,3 +1,32 @@
+2001-05-04  Havoc Pennington  <hp redhat com>
+
+	* pixops/pixops.c (pixops_process): merge fix from stable: Patch
+	 from hoshem mel comcen com au to fix nonzero X offsets.  Fixes
+	 bug #50371.
+	
+        * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): merge
+	from stable: Patch from OKADA Mitsuru <m-okada fjb co jp> to fix
+	confusion of using "src" instead of "p".
+        (pixops_composite_color_nearest): Use a more accurate (and
+	correct, to begin with) compositing method.  This cures checks
+	showing through on images with no alpha.
+
+	* gdk-pixbuf.c (gdk_pixbuf_fill): fix bug that left some trailing
+	bytes unfilled.
+
+	* gdk-pixbuf-io.h: fix UpdatedNotifyFunc to use signed ints
+
+	* gdk-pixbuf-loader.h (struct _GdkPixbufLoaderClass): Change
+	area_updated signal to use signed ints.  Removed animation-related
+	signals.
+
+	* io-gif.c, io-gif-animation.h, io-gif-animation.c: Massive
+	rewrite action
+
+	* gdk-pixbuf-animation.c: Add GdkPixbufAnimationIter to abstract
+	all the pesky details. Remove old frame-based API. Make
+	GdkPixbufAnimation an abstract base class, derived by the loaders.
+
 Sun Apr 22 15:51:32 2001  Owen Taylor  <otaylor redhat com>
 
 	* Makefile.am (LDADDS): Add $(MATH_LIB).
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/Makefile.am,v
retrieving revision 1.87
diff -u -u -r1.87 Makefile.am
--- Makefile.am	2001/05/03 20:11:06	1.87
+++ Makefile.am	2001/05/04 16:35:10
@@ -32,8 +32,8 @@
 #
 # The GIF loader
 #
-libpixbufloader_static_gif_la_SOURCES = io-gif.c
-libpixbufloader_gif_la_SOURCES = io-gif.c
+libpixbufloader_static_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
+libpixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
 libpixbufloader_gif_la_LDFLAGS = -avoid-version -module
 libpixbufloader_gif_la_LIBADD =
 
Index: gdk-pixbuf-animation.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-animation.c,v
retrieving revision 1.18
diff -u -u -r1.18 gdk-pixbuf-animation.c
--- gdk-pixbuf-animation.c	2001/03/07 14:49:14	1.18
+++ gdk-pixbuf-animation.c	2001/05/04 16:35:10
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 /* GdkPixbuf library - Simple animation support
  *
  * Copyright (C) 1999 The Free Software Foundation
@@ -26,12 +27,59 @@
 #include "gdk-pixbuf-io.h"
 #include "gdk-pixbuf-private.h"
 
-static void gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass);
-static void gdk_pixbuf_animation_finalize   (GObject        *object);
+typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim;
+typedef struct _GdkPixbufNonAnimClass GdkPixbufNonAnimClass;
 
+#define GDK_TYPE_PIXBUF_NON_ANIM              (gdk_pixbuf_non_anim_get_type ())
+#define GDK_PIXBUF_NON_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnim))
+#define GDK_IS_PIXBUF_NON_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM))
+
+#define GDK_PIXBUF_NON_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+#define GDK_IS_PIXBUF_NON_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM))
+#define GDK_PIXBUF_NON_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+
+/* Private part of the GdkPixbufNonAnim structure */
+struct _GdkPixbufNonAnim {
+        GdkPixbufAnimation parent_instance;
+
+        GdkPixbuf *pixbuf;
+};
+
+struct _GdkPixbufNonAnimClass {
+        GdkPixbufAnimationClass parent_class;
+        
+};
+
+static GType gdk_pixbuf_non_anim_get_type (void) G_GNUC_CONST;
+
 
+
+typedef struct _GdkPixbufNonAnimIter GdkPixbufNonAnimIter;
+typedef struct _GdkPixbufNonAnimIterClass GdkPixbufNonAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_NON_ANIM_ITER              (gdk_pixbuf_non_anim_iter_get_type ())
+#define GDK_PIXBUF_NON_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIter))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
 
-static gpointer parent_class;
+#define GDK_PIXBUF_NON_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
+#define GDK_PIXBUF_NON_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+
+struct _GdkPixbufNonAnimIter {
+        GdkPixbufAnimationIter parent_instance;
+
+        GdkPixbufNonAnim   *non_anim;
+};
+
+struct _GdkPixbufNonAnimIterClass {
+        GdkPixbufAnimationIterClass parent_class;
+
+};
+
+static GType gdk_pixbuf_non_anim_iter_get_type (void) G_GNUC_CONST;
+
+
 
 GType
 gdk_pixbuf_animation_get_type (void)
@@ -43,7 +91,7 @@
                         sizeof (GdkPixbufAnimationClass),
                         (GBaseInitFunc) NULL,
                         (GBaseFinalizeFunc) NULL,
-                        (GClassInitFunc) gdk_pixbuf_animation_class_init,
+                        (GClassInitFunc) NULL,
                         NULL,           /* class_finalize */
                         NULL,           /* class_data */
                         sizeof (GdkPixbufAnimation),
@@ -59,35 +107,6 @@
         return object_type;
 }
 
-static void
-gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass)
-{
-        GObjectClass *object_class = G_OBJECT_CLASS (klass);
-        
-        parent_class = g_type_class_peek_parent (klass);
-        
-        object_class->finalize = gdk_pixbuf_animation_finalize;
-}
-
-static void
-gdk_pixbuf_animation_finalize (GObject *object)
-{
-        GdkPixbufAnimation *animation = GDK_PIXBUF_ANIMATION (object);
-
-        GList *l;
-        GdkPixbufFrame *frame;
-        
-        for (l = animation->frames; l; l = l->next) {
-                frame = l->data;
-                gdk_pixbuf_unref (frame->pixbuf);
-                g_free (frame);
-        }
-        
-        g_list_free (animation->frames);
-        
-        G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
 
 
 /**
@@ -154,7 +173,6 @@
 
 	if (image_module->load_animation == NULL) {
 		GdkPixbuf *pixbuf;
-		GdkPixbufFrame *frame;
 
 		/* Keep this logic in sync with gdk_pixbuf_new_from_file() */
 
@@ -190,21 +208,10 @@
                 
 		if (pixbuf == NULL)
                         return NULL;
+
+                animation = gdk_pixbuf_non_anim_new (pixbuf);
 
-		frame = g_new (GdkPixbufFrame, 1);
-		frame->pixbuf = pixbuf;
-                g_object_ref (G_OBJECT (frame->pixbuf));
-		frame->x_offset = 0;
-		frame->y_offset = 0;
-		frame->delay_time = -1;
-		frame->action = GDK_PIXBUF_FRAME_RETAIN;
-
-		animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-
-		animation->n_frames = 1;
-		animation->frames = g_list_prepend (NULL, frame);
-		animation->width = gdk_pixbuf_get_width (pixbuf);
-		animation->height = gdk_pixbuf_get_height (pixbuf);
+                g_object_unref (G_OBJECT (pixbuf));
 	} else {
 		fseek (f, 0, SEEK_SET);
 		animation = (* image_module->load_animation) (f, error);
@@ -262,6 +269,46 @@
 }
 
 /**
+ * gdk_pixbuf_animation_is_static_image:
+ * @animation: a #GdkPixbufAnimation
+ * 
+ * If you load a file with gdk_pixbuf_animation_new_from_file() and it turns
+ * out to be a plain, unanimated image, then this function will return
+ * %TRUE. Use gdk_pixbuf_animation_get_static_image() to retrieve
+ * the image.
+ * 
+ * Return value: %TRUE if the "animation" was really just an image
+ **/
+gboolean
+gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation)
+{
+	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE);
+
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation);
+}
+
+/**
+ * gdk_pixbuf_animation_get_static_image:
+ * @animation: a #GdkPixbufAnimation
+ * 
+ * If an animation is really just a plain image (has only one frame),
+ * this function returns that image. If the animation is an animation,
+ * this function returns a reasonable thing to display as a static
+ * unanimated image, which might be the first frame, or something more
+ * sophisticated. If an animation hasn't loaded any frames yet, this
+ * function will return %NULL.
+ * 
+ * Return value: unanimated image representing the animation
+ **/
+GdkPixbuf*
+gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation)
+{
+	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+        
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation);
+}
+
+/**
  * gdk_pixbuf_animation_get_width:
  * @animation: An animation.
  *
@@ -272,9 +319,16 @@
 int
 gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
 {
-	g_return_val_if_fail (animation != NULL, -1);
+        int width;
+        
+	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
 
-	return animation->width;
+        width = 0;
+        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+                                                              &width, NULL);
+        
+
+	return width;
 }
 
 /**
@@ -288,179 +342,436 @@
 int
 gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation)
 {
-	g_return_val_if_fail (animation != NULL, -1);
-
-	return animation->height;
-}
+        int height;
+        
+	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
 
-/**
- * gdk_pixbuf_animation_get_num_frames:
- * @animation: An animation.
- *
- * Queries the number of frames in a pixbuf animation.
- * 
- * Return value: Number of frames in the animation.
- **/
-int
-gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation)
-{
-	g_return_val_if_fail (animation != NULL, -1);
+        height = 0;
+        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+                                                              NULL, &height);
+        
 
-	return animation->n_frames;
+	return height;
 }
 
+
 /**
- * gdk_pixbuf_animation_get_frames:
- * @animation: An animation.
+ * gdk_pixbuf_animation_get_iter:
+ * @animation: a #GdkPixbufAnimation
+ * @start_time: time when the animation starts playing
+ * 
+ * Get an iterator for displaying an animation. The iterator provides
+ * the frames that should be displayed at a given time.
+ * It should be freed after use with g_object_unref().
+ * 
+ * @start_time would normally come from g_get_current_time(), and
+ * marks the beginning of animation playback. After creating an
+ * iterator, you should immediately display the pixbuf returned by
+ * gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install a
+ * timeout (with g_timeout_add()) or by some other mechanism ensure
+ * that you'll update the image after
+ * gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time
+ * the image is updated, you should reinstall the timeout with the new,
+ * possibly-changed delay time.
+ *
+ * As a shortcut, if @start_time is %NULL, the result of
+ * g_get_current_time() will be used automatically.
+ *
+ * To update the image (i.e. possibly change the result of
+ * gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation),
+ * call gdk_pixbuf_animation_iter_advance().
  *
- * Queries the list of frames of an animation.
+ * If you're using #GdkPixbufLoader, in addition to updating the image
+ * after the delay time, you should also update it whenever you
+ * receive the area_updated signal and
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame() returns
+ * %TRUE. In this case, the frame currently being fed into the loader
+ * has received new data, so needs to be refreshed. The delay time for
+ * a frame may also be modified after an area_updated signal, for
+ * example if the delay time for a frame is encoded in the data after
+ * the frame itself. So your timeout should be reinstalled after any
+ * area_updated signal.
+ *
+ * A delay time of -1 is possible, indicating "infinite."
  * 
- * Return value: List of frames in the animation; this is a #GList of
- * #GdkPixbufFrame structures.
+ * Return value: an iterator to move over the animation
  **/
-GList *
-gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation)
+GdkPixbufAnimationIter*
+gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
+                               const GTimeVal     *start_time)
 {
-	g_return_val_if_fail (animation != NULL, NULL);
+        GTimeVal val;
+        
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
 
-	return animation->frames;
+
+        if (start_time)
+                val = *start_time;
+        else
+                g_get_current_time (&val);
+        
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
 }
 
 
 
-/**
- * gdk_pixbuf_frame_get_pixbuf:
- * @frame: A pixbuf animation frame.
- * 
- * Queries the pixbuf of an animation frame.
- * 
- * Return value: A pixbuf.
- **/
-GdkPixbuf *
-gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame)
+GType
+gdk_pixbuf_animation_iter_get_type (void)
 {
-	g_return_val_if_fail (frame != NULL, NULL);
+        static GType object_type = 0;
 
-	return frame->pixbuf;
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufAnimationIterClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) NULL,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufAnimationIter),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (G_TYPE_OBJECT,
+                                                      "GdkPixbufAnimationIter",
+                                                      &object_info, 0);
+        }
+  
+        return object_type;
 }
 
 /**
- * gdk_pixbuf_frame_get_x_offset:
- * @frame: A pixbuf animation frame.
- * 
- * Queries the X offset of an animation frame.
+ * gdk_pixbuf_animation_iter_get_delay_time:
+ * @iter: an animation iterator
  * 
- * Return value: X offset from the top left corner of the animation.
+ * Gets the number of milliseconds the current pixbuf should be displayed,
+ * or -1 if the current pixbuf should be displayed forever. g_timeout_add()
+ * conveniently takes a timeout in milliseconds, so you can use a timeout
+ * to schedule the next update.
+ *
+ * Return value: delay time in milliseconds (thousandths of a second)
  **/
 int
-gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame)
+gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
 {
-	g_return_val_if_fail (frame != NULL, -1);
-
-	return frame->x_offset;
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1);
+  
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter);
 }
 
 /**
- * gdk_pixbuf_frame_get_y_offset:
- * @frame: A pixbuf animation frame.
- * 
- * Queries the Y offset of an animation frame.
+ * gdk_pixbuf_animation_iter_get_pixbuf:
+ * @iter: an animation iterator
  * 
- * Return value: Y offset from the top left corner of the animation.
+ * Gets the current pixbuf which should be displayed; the pixbuf will
+ * be the same size as the animation itself
+ * (gdk_pixbuf_animation_get_width(),
+ * gdk_pixbuf_animation_get_height()). This pixbuf should be displayed
+ * for gdk_pixbuf_animation_get_delay_time() milliseconds.  The caller
+ * of this function does not own a reference to the returned pixbuf;
+ * the returned pixbuf will become invalid when the iterator advances
+ * to the next frame, which may happen anytime you call
+ * gdk_pixbuf_animation_iter_advance(). Copy the pixbuf to keep it
+ * (don't just add a reference), as it may get recycled as you advance
+ * the iterator.
+ *
+ * Return value: the pixbuf to be displayed
  **/
-int
-gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame)
+GdkPixbuf*
+gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
 {
-	g_return_val_if_fail (frame != NULL, -1);
-
-	return frame->y_offset;
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
+  
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
 }
 
 /**
- * gdk_pixbuf_frame_get_delay_time:
- * @frame: A pixbuf animation frame.
- * 
- * Queries the delay time in milliseconds of an animation frame.
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame:
+ * @iter: a #GdkPixbufAnimationIter
+ *
+ * Used to determine how to respond to the area_updated signal on
+ * #GdkPixbufLoader when loading an animation. area_updated is emitted
+ * for an area of the frame currently streaming in to the loader. So if
+ * you're on the currently loading frame, you need to redraw the screen for
+ * the updated area.
  * 
- * Return value: Delay time in milliseconds.
+ * Return value: %TRUE if the frame we're on is partially loaded, or the last frame
  **/
-int
-gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame)
+gboolean
+gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
 {
-	g_return_val_if_fail (frame != NULL, -1);
-
-	return frame->delay_time;
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
+        
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
 }
 
 /**
- * gdk_pixbuf_frame_get_action:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_advance:
+ * @iter: a #GdkPixbufAnimationIter
+ * @current_time: current time
+ *
+ * Possibly advances an animation to a new frame. Chooses the frame based
+ * on the start time passed to gdk_pixbuf_animation_get_iter().
  * 
- * Queries the overlay action of an animation frame.
+ * @current_time would normally come from g_get_current_time(), and
+ * must be greater than or equal to the time passed to
+ * gdk_pixbuf_animation_get_iter(), and must increase or remain
+ * unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is
+ * called. That is, you can't go backward in time; animations only
+ * play forward.
+ *
+ * As a shortcut, pass %NULL for the current time and g_get_current_time()
+ * will be invoked on your behalf. So you only need to explicitly pass
+ * @current_time if you're doing something odd like playing the animation
+ * at double speed.
  * 
- * Return value: Overlay action for this frame.
  **/
-GdkPixbufFrameAction
-gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame)
+void
+gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
+                                   const GTimeVal         *current_time)
 {
-	g_return_val_if_fail (frame != NULL, GDK_PIXBUF_FRAME_RETAIN);
+        GTimeVal val;
+        
+        g_return_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter));
 
-	return frame->action;
+        if (current_time)
+                val = *current_time;
+        else
+                g_get_current_time (&val);
+        
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val);
 }
 
-/**
- * gdk_pixbuf_frame_copy:
- * @src: a #GdkPixbufFrame to copy
- * 
- * Copies a #GdkPixbufFrame. Free the result
- * with gdk_pixbuf_frame_free().
- * 
- * Return value: a new #GdkPixbufFrame
- **/
-GdkPixbufFrame*
-gdk_pixbuf_frame_copy (GdkPixbufFrame *src)
+
+
+static void gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass);
+static void gdk_pixbuf_non_anim_finalize   (GObject        *object);
+
+static gboolean                gdk_pixbuf_non_anim_is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf*              gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation);
+static void                    gdk_pixbuf_non_anim_get_size         (GdkPixbufAnimation *anim,
+                                                                     int                *width,
+                                                                     int                *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter         (GdkPixbufAnimation *anim,
+                                                                     const GTimeVal     *start_time);
+
+
+
+
+
+static gpointer non_parent_class;
+
+GType
+gdk_pixbuf_non_anim_get_type (void)
 {
-  GdkPixbufFrame *frame;
+        static GType object_type = 0;
 
-  frame = g_new (GdkPixbufFrame, 1);
-  frame->pixbuf = src->pixbuf;
-  g_object_ref (G_OBJECT (frame->pixbuf));
-  frame->x_offset = src->x_offset;
-  frame->y_offset = src->y_offset;
-  frame->delay_time = src->delay_time;
-  frame->action = src->action;
-  
-  return frame;
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufNonAnimClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) gdk_pixbuf_non_anim_class_init,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufNonAnim),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+                                                      "GdkPixbufNonAnim",
+                                                      &object_info, 0);
+        }
+        
+        return object_type;
 }
 
-/**
- * gdk_pixbuf_frame_free:
- * @frame: a #GdkPixbufFrame
- * 
- * Frees a #GdkPixbufFrame. Don't do this with frames you got from
- * #GdkPixbufAnimation, usually the animation owns those (it doesn't
- * make a copy before returning the frame).
- **/
-void
-gdk_pixbuf_frame_free (GdkPixbufFrame *frame)
+static void
+gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+        
+        non_parent_class = g_type_class_peek_parent (klass);
+        
+        object_class->finalize = gdk_pixbuf_non_anim_finalize;
+
+        anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image;
+        anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image;
+        anim_class->get_size = gdk_pixbuf_non_anim_get_size;
+        anim_class->get_iter = gdk_pixbuf_non_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_non_anim_finalize (GObject *object)
+{
+        GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object);
+
+        if (non_anim->pixbuf)
+                g_object_unref (G_OBJECT (non_anim->pixbuf));
+        
+        G_OBJECT_CLASS (non_parent_class)->finalize (object);
+}
+
+GdkPixbufAnimation*
+gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL);
+
+        non_anim->pixbuf = pixbuf;
+
+        if (pixbuf)
+                g_object_ref (G_OBJECT (pixbuf));
+
+        return GDK_PIXBUF_ANIMATION (non_anim);
+}
+
+static gboolean
+gdk_pixbuf_non_anim_is_static_image  (GdkPixbufAnimation *animation)
+{
+
+        return TRUE;
+}
+
+static GdkPixbuf*
+gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation)
 {
-  g_return_if_fail (frame != NULL);
+        GdkPixbufNonAnim *non_anim;
 
-  g_object_unref (G_OBJECT (frame->pixbuf));
-  g_free (frame);
+        non_anim = GDK_PIXBUF_NON_ANIM (animation);
+
+        return non_anim->pixbuf;
 }
 
+static void
+gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
+                              int                *width,
+                              int                *height)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+        if (width)
+                *width = gdk_pixbuf_get_width (non_anim->pixbuf);
+
+        if (height)
+                *height = gdk_pixbuf_get_height (non_anim->pixbuf);
+}
+
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
+                              const GTimeVal     *start_time)
+{
+        GdkPixbufNonAnimIter *iter;
+
+        iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL);
+
+        iter->non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+        g_object_ref (G_OBJECT (iter->non_anim));
+        
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+
+
+static void gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass);
+static void gdk_pixbuf_non_anim_iter_finalize   (GObject                   *object);
+static int        gdk_pixbuf_non_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static void       gdk_pixbuf_non_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                       const GTimeVal         *current_time);
+
+
+
+
+
+static gpointer non_iter_parent_class;
+
 GType
-gdk_pixbuf_frame_get_type (void)
+gdk_pixbuf_non_anim_iter_get_type (void)
 {
-  static GType our_type = 0;
+        static GType object_type = 0;
 
-  if (our_type == 0)
-    our_type = g_boxed_type_register_static ("GdkPixbufFrame",
-					     NULL,
-					     gdk_pixbuf_frame_copy,
-					     gdk_pixbuf_frame_free,
-					     FALSE);
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufNonAnimIterClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) gdk_pixbuf_non_anim_iter_class_init,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufNonAnimIter),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
+                                                      "GdkPixbufNonAnimIter",
+                                                      &object_info, 0);
+        }
+        
+        return object_type;
+}
+
+static void
+gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationIterClass *anim_iter_class =
+                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+        
+        non_iter_parent_class = g_type_class_peek_parent (klass);
+        
+        object_class->finalize = gdk_pixbuf_non_anim_iter_finalize;
 
-  return our_type;
+        anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time;
+        anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame;
+        anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance;
 }
+
+static void
+gdk_pixbuf_non_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
+
+        g_object_unref (G_OBJECT (iter->non_anim));
+        
+        G_OBJECT_CLASS (non_iter_parent_class)->finalize (object);
+}
+
+static int
+gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter)
+{
+        return -1; /* show only frame forever */
+}
+
+static GdkPixbuf*
+gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
+{
+        return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf;
+}
+
+
+static gboolean
+gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
+{
+        return TRUE;
+}
+        
+static void
+gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
+                                  const GTimeVal         *current_time)
+{
+
+        /* total no-op */
+}
+
Index: gdk-pixbuf-io.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-io.h,v
retrieving revision 1.24
diff -u -u -r1.24 gdk-pixbuf-io.h
--- gdk-pixbuf-io.h	2001/02/20 02:59:30	1.24
+++ gdk-pixbuf-io.h	2001/05/04 16:35:10
@@ -39,16 +39,15 @@
 
 
 
-typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf, gpointer user_data);
-typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
-					  guint x, guint y,
-					  guint width, guint height,
-					  gpointer user_data);
-/* Needed only for animated images. */
-typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbufFrame *frame,
-					    gpointer user_data);
-typedef void (* ModuleAnimationDoneNotifyFunc) (GdkPixbuf *pixbuf,
-						gpointer user_data);
+typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf          *pixbuf,
+                                           GdkPixbufAnimation *anim,
+                                           gpointer            user_data);
+typedef void (* ModuleUpdatedNotifyFunc)  (GdkPixbuf *pixbuf,
+                                           int        x,
+                                           int        y,
+                                           int        width,
+                                           int        height,
+                                           gpointer   user_data);
 
 typedef struct _GdkPixbufModule GdkPixbufModule;
 struct _GdkPixbufModule {
@@ -63,8 +62,6 @@
 
         gpointer (* begin_load)     (ModulePreparedNotifyFunc prepare_func,
                                      ModuleUpdatedNotifyFunc update_func,
-                                     ModuleFrameDoneNotifyFunc frame_done_func,
-                                     ModuleAnimationDoneNotifyFunc anim_done_func,
                                      gpointer user_data,
                                      GError **error);
         gboolean (* stop_load)      (gpointer context,
Index: gdk-pixbuf-loader.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-loader.c,v
retrieving revision 1.54
diff -u -u -r1.54 gdk-pixbuf-loader.c
--- gdk-pixbuf-loader.c	2001/03/08 16:36:16	1.54
+++ gdk-pixbuf-loader.c	2001/05/04 16:35:10
@@ -35,8 +35,6 @@
 enum {
   AREA_UPDATED,
   AREA_PREPARED,
-  FRAME_DONE,
-  ANIMATION_DONE,
   CLOSED,
   LAST_SIGNAL
 };
@@ -56,7 +54,6 @@
 
 typedef struct
 {
-  GdkPixbuf *pixbuf;
   GdkPixbufAnimation *animation;
   gboolean closed;
   guchar header_buf[LOADER_HEADER_SIZE];
@@ -136,25 +133,6 @@
                    G_TYPE_INT,
                    G_TYPE_INT);
   
-  pixbuf_loader_signals[FRAME_DONE] =
-    g_signal_newc ("frame_done",
-                   G_TYPE_FROM_CLASS (object_class),
-                   G_SIGNAL_RUN_LAST,
-                   G_STRUCT_OFFSET (GdkPixbufLoaderClass, frame_done),
-		   NULL, NULL,
-                   gdk_pixbuf_marshal_VOID__POINTER,
-                   G_TYPE_NONE, 1,
-                   GDK_TYPE_PIXBUF_FRAME);
-  
-  pixbuf_loader_signals[ANIMATION_DONE] =
-    g_signal_newc ("animation_done",
-                   G_TYPE_FROM_CLASS (object_class),
-                   G_SIGNAL_RUN_LAST,                   
-                   G_STRUCT_OFFSET (GdkPixbufLoaderClass, animation_done),
-		   NULL, NULL,
-                   gdk_pixbuf_marshal_VOID__VOID,
-                   G_TYPE_NONE, 0);
-  
   pixbuf_loader_signals[CLOSED] =
     g_signal_newc ("closed",
                    G_TYPE_FROM_CLASS (object_class),
@@ -188,9 +166,6 @@
   
   if (priv->animation)
     gdk_pixbuf_animation_unref (priv->animation);
-
-  if (priv->pixbuf)
-    gdk_pixbuf_unref (priv->pixbuf);
   
   g_free (priv);
   
@@ -198,26 +173,30 @@
 }
 
 static void
-gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
-			   gpointer   loader)
+gdk_pixbuf_loader_prepare (GdkPixbuf          *pixbuf,
+                           GdkPixbufAnimation *anim,
+			   gpointer            loader)
 {
   GdkPixbufLoaderPrivate *priv = NULL;
   
   priv = GDK_PIXBUF_LOADER (loader)->priv;
-  gdk_pixbuf_ref (pixbuf);
 
-  g_assert (priv->pixbuf == NULL);
+  if (anim)
+    g_object_ref (G_OBJECT (anim));
+  else
+    anim = gdk_pixbuf_non_anim_new (pixbuf);
   
-  priv->pixbuf = pixbuf;
+  priv->animation = anim;
+  
   g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[AREA_PREPARED], 0);
 }
 
 static void
 gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
-			  guint      x,
-			  guint      y,
-			  guint      width,
-			  guint      height,
+			  gint       x,
+			  gint       y,
+			  gint       width,
+			  gint       height,
 			  gpointer   loader)
 {
   GdkPixbufLoaderPrivate *priv = NULL;
@@ -229,84 +208,10 @@
                  0,
                  x, y,
                  /* sanity check in here.  Defend against an errant loader */
-                 MIN (width, gdk_pixbuf_get_width (priv->pixbuf)),
-                 MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
+                 MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
+                 MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
 }
 
-static void
-gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame,
-			      gpointer        loader)
-{
-  GdkPixbufLoaderPrivate *priv = NULL;
-  
-  priv = GDK_PIXBUF_LOADER (loader)->priv;
-  
-  priv->pixbuf = NULL;
-  
-  if (priv->animation == NULL)
-    {
-      priv->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-      
-      priv->animation->n_frames = 0;
-      priv->animation->width  = gdk_pixbuf_get_width  (frame->pixbuf) + frame->x_offset;
-      priv->animation->height = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-    }
-  else
-    {
-      int w, h;
-      
-      /* update bbox size */
-      w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
-      h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-      
-      if (w > priv->animation->width) {
-	priv->animation->width = w;
-      }
-      if (h > priv->animation->height) {
-	priv->animation->height = h;
-      }
-    }
-  
-  priv->animation->frames = g_list_append (priv->animation->frames, frame);
-  priv->animation->n_frames++;
-  g_signal_emit (G_OBJECT (loader),
-                 pixbuf_loader_signals[FRAME_DONE],
-                 0,
-                 frame);
-}
-
-static void
-gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf,
-				  gpointer   loader)
-{
-  GdkPixbufLoaderPrivate *priv = NULL;
-  GdkPixbufFrame    *frame;
-  GList *current = NULL;
-  gint h, w;
-  
-  priv = GDK_PIXBUF_LOADER (loader)->priv;
-  priv->pixbuf = NULL;
-  
-  current = gdk_pixbuf_animation_get_frames (priv->animation);
-  
-  while (current)
-    {
-      frame = (GdkPixbufFrame *) current->data;
-      
-      /* update bbox size */
-      w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
-      h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-      
-      if (w > priv->animation->width)
-	priv->animation->width = w;
-      if (h > priv->animation->height)
-	priv->animation->height = h;
-      current = current->next;
-    }
-  
-  g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[ANIMATION_DONE], 0);
-}
-
 static gint
 gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
                                const char      *image_type,
@@ -353,8 +258,6 @@
   
   priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_prepare,
 						  gdk_pixbuf_loader_update,
-						  gdk_pixbuf_loader_frame_done,
-						  gdk_pixbuf_loader_animation_done,
 						  loader,
                                                   error);
   
@@ -450,7 +353,7 @@
     {
       gint eaten;
       
-      eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count, error);
+      eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
       if (eaten <= 0)
 	return FALSE;
       
@@ -540,13 +443,14 @@
  * "area_prepared" signal has been emitted by the loader; this means
  * that enough data has been read to know the size of the image that
  * will be allocated.  If the loader has not received enough data via
- * gdk_pixbuf_loader_write(), then this function returns NULL.  The
+ * gdk_pixbuf_loader_write(), then this function returns %NULL.  The
  * returned pixbuf will be the same in all future calls to the loader,
  * so simply calling gdk_pixbuf_ref() should be sufficient to continue
  * using it.  Additionally, if the loader is an animation, it will
- * return the first frame of the animation.
+ * return the "static image" of the animation
+ * (see gdk_pixbuf_animation_get_static_image()).
  * 
- * Return value: The GdkPixbuf that the loader is creating, or NULL if not
+ * Return value: The #GdkPixbuf that the loader is creating, or %NULL if not
  * enough data has been read to determine how to create the image buffer.
  **/
 GdkPixbuf *
@@ -560,19 +464,9 @@
   priv = loader->priv;
 
   if (priv->animation)
-    {
-      GList *list;
-      
-      list = gdk_pixbuf_animation_get_frames (priv->animation);
-      if (list != NULL)
-        {
-          GdkPixbufFrame *frame = list->data;
-          
-          return gdk_pixbuf_frame_get_pixbuf (frame);
-        }
-    }
-  
-  return priv->pixbuf;
+    return gdk_pixbuf_animation_get_static_image (priv->animation);
+  else
+    return NULL;
 }
 
 /**
@@ -581,8 +475,9 @@
  *
  * Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
  * In general it only makes sense to call this function afer the "area_prepared"
- * signal has been emitted by the loader.  If the image is not an animation,
- * then it will return NULL.
+ * signal has been emitted by the loader. If the loader doesn't have enough
+ * bytes yet (hasn't emitted the area_prepared signal) this function will return
+ * %NULL.
  *
  * Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
  not enough data has been read to determine the information.
Index: gdk-pixbuf-loader.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-loader.h,v
retrieving revision 1.21
diff -u -u -r1.21 gdk-pixbuf-loader.h
--- gdk-pixbuf-loader.h	2001/02/02 05:31:27	1.21
+++ gdk-pixbuf-loader.h	2001/05/04 16:35:10
@@ -51,21 +51,21 @@
 struct _GdkPixbufLoaderClass
 {
   GObjectClass parent_class;
-  
-  void (*area_prepared)   (GdkPixbufLoader *loader);
-  void (*area_updated)    (GdkPixbufLoader *loader,
-			   guint            x,
-			   guint            y,
-			   guint            width,
-			   guint            height);
-  void (*frame_done)      (GdkPixbufLoader *loader,
-			   GdkPixbufFrame  *frame);
-  void (*animation_done)  (GdkPixbufLoader *loader);
-  void (*closed)          (GdkPixbufLoader *loader);
+
+  void (*area_prepared)      (GdkPixbufLoader *loader);
+
+  /* Last known frame needs a redraw for x, y, width, height */
+  void (*area_updated)       (GdkPixbufLoader *loader,
+                              int              x,
+                              int              y,
+			      int              width,
+			      int              height);
+
+  void (*closed)             (GdkPixbufLoader *loader);
 };
 
 
-GType              gdk_pixbuf_loader_get_type      (void) G_GNUC_CONST;
+GType                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,
                                                       GError    **error);
Index: gdk-pixbuf-private.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-private.h,v
retrieving revision 1.5
diff -u -u -r1.5 gdk-pixbuf-private.h
--- gdk-pixbuf-private.h	2000/09/26 20:22:17	1.5
+++ gdk-pixbuf-private.h	2001/05/04 16:35:10
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 /* GdkPixbuf library - Private declarations
  *
  * Copyright (C) 1999 The Free Software Foundation
@@ -73,22 +74,6 @@
 
 };
 
-/* Private part of the GdkPixbufFrame structure */
-struct _GdkPixbufFrame {
-	/* The pixbuf with this frame's image data */
-	GdkPixbuf *pixbuf;
-
-	/* Offsets for overlaying onto the animation's area */
-	int x_offset;
-	int y_offset;
-
-	/* Frame duration in ms */
-	int delay_time;
-
-	/* Overlay mode */
-	GdkPixbufFrameAction action;
-};
-
 typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
 
 #define GDK_PIXBUF_ANIMATION_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass))
@@ -99,24 +84,52 @@
 struct _GdkPixbufAnimation {
         GObject parent_instance;
 
-	/* Number of frames */
-        int n_frames;
-
-	/* List of GdkPixbufFrame structures */
-        GList *frames;
-
-	/* bounding box size */
-	int width, height;
 };
 
 struct _GdkPixbufAnimationClass {
         GObjectClass parent_class;
 
+        gboolean                (*is_static_image)  (GdkPixbufAnimation *anim);
+
+        GdkPixbuf*              (*get_static_image) (GdkPixbufAnimation *anim);
+        
+        void                    (*get_size) (GdkPixbufAnimation *anim,
+                                             int                 *width,
+                                             int                 *height);
+        
+        GdkPixbufAnimationIter* (*get_iter) (GdkPixbufAnimation *anim,
+                                             const GTimeVal     *start_time);
 
 };
 
 
 
+typedef struct _GdkPixbufAnimationIterClass GdkPixbufAnimationIterClass;
+
+#define GDK_PIXBUF_ANIMATION_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+#define GDK_IS_PIXBUF_ANIMATION_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER))
+#define GDK_PIXBUF_ANIMATION_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+
+struct _GdkPixbufAnimationIter {
+        GObject parent_instance;
+
+};
+
+struct _GdkPixbufAnimationIterClass {
+        GObjectClass parent_class;
+
+        int        (*get_delay_time)   (GdkPixbufAnimationIter *iter);
+
+        GdkPixbuf* (*get_pixbuf)       (GdkPixbufAnimationIter *iter);
+
+        gboolean (*on_currently_loading_frame) (GdkPixbufAnimationIter *iter);
+
+        void     (*advance)            (GdkPixbufAnimationIter *iter,
+                                        const GTimeVal         *current_time);
+};
+      
+
+
 #define GDK_PIXBUF_INLINE_MAGIC_NUMBER 0x47646B50 /* 'GdkP' */
 
 typedef enum
@@ -125,6 +138,8 @@
   GDK_PIXBUF_INLINE_RLE = 1
 } GdkPixbufInlineFormat;
 
+
 
+GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf);
 
 #endif
Index: gdk-pixbuf-util.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-util.c,v
retrieving revision 1.10
diff -u -u -r1.10 gdk-pixbuf-util.c
--- gdk-pixbuf-util.c	2000/10/18 18:42:52	1.10
+++ gdk-pixbuf-util.c	2001/05/04 16:35:10
@@ -121,6 +121,8 @@
 	g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width);
 	g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height);
 
+        g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf)));
+        
 	/* This will perform format conversions automatically */
 
 	gdk_pixbuf_scale (src_pixbuf,
Index: gdk-pixbuf.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf.c,v
retrieving revision 1.43
diff -u -u -r1.43 gdk-pixbuf.c
--- gdk-pixbuf.c	2001/04/18 18:09:17	1.43
+++ gdk-pixbuf.c	2001/05/04 16:35:10
@@ -412,7 +412,7 @@
 /**
  * gdk_pixbuf_fill:
  * @pixbuf: a #GdkPixbuf
- * @pixel: RGBA pixel to clear to (0xffffff00 is opaque white, 0x000000ff transparent black)
+ * @pixel: RGBA pixel to clear to (0xffffffff is opaque white, 0x00000000 transparent black)
  *
  * Clears a pixbuf to the given RGBA value, converting the RGBA value into
  * the pixbuf's pixel format. The alpha will be ignored if the pixbuf
@@ -454,7 +454,7 @@
                 
                 p = pixels;
                 end = pixels + pixbuf->rowstride * pixbuf->height;
-                end -= (pixbuf->rowstride - pixbuf->width);
+                end -= (pixbuf->rowstride - pixbuf->width * pixbuf->n_channels);
                 
                 while (p < end) {
                         *p++ = r;
Index: gdk-pixbuf.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf.h,v
retrieving revision 1.56
diff -u -u -r1.56 gdk-pixbuf.h
--- gdk-pixbuf.h	2001/04/18 18:09:17	1.56
+++ gdk-pixbuf.h	2001/05/04 16:35:10
@@ -54,6 +54,7 @@
 /* All of these are opaque structures */
 typedef struct _GdkPixbuf GdkPixbuf;
 typedef struct _GdkPixbufAnimation GdkPixbufAnimation;
+typedef struct _GdkPixbufAnimationIter GdkPixbufAnimationIter;
 typedef struct _GdkPixbufFrame GdkPixbufFrame;
 
 #define GDK_TYPE_PIXBUF              (gdk_pixbuf_get_type ())
@@ -64,6 +65,9 @@
 #define GDK_PIXBUF_ANIMATION(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimation))
 #define GDK_IS_PIXBUF_ANIMATION(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION))
 
+#define GDK_TYPE_PIXBUF_ANIMATION_ITER              (gdk_pixbuf_animation_iter_get_type ())
+#define GDK_PIXBUF_ANIMATION_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIter))
+#define GDK_IS_PIXBUF_ANIMATION_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER))
 
 /* Handler that must free the pixel array */
 typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
@@ -255,13 +259,6 @@
 
 /* Animation support */
 
-/* GIF-like animation overlay modes for frames */
-typedef enum {
-	GDK_PIXBUF_FRAME_RETAIN,
-	GDK_PIXBUF_FRAME_DISPOSE,
-	GDK_PIXBUF_FRAME_REVERT
-} GdkPixbufFrameAction;
-
 GType               gdk_pixbuf_animation_get_type        (void) G_GNUC_CONST;
 
 GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file   (const char         *filename,
@@ -272,21 +269,20 @@
 
 int                 gdk_pixbuf_animation_get_width       (GdkPixbufAnimation *animation);
 int                 gdk_pixbuf_animation_get_height      (GdkPixbufAnimation *animation);
-GList              *gdk_pixbuf_animation_get_frames      (GdkPixbufAnimation *animation);
-int                 gdk_pixbuf_animation_get_num_frames  (GdkPixbufAnimation *animation);
+gboolean            gdk_pixbuf_animation_is_static_image  (GdkPixbufAnimation *animation);
+GdkPixbuf          *gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation);
 
-/* Frame accessors */
+GdkPixbufAnimationIter *gdk_pixbuf_animation_get_iter                        (GdkPixbufAnimation     *animation,
+                                                                              const GTimeVal         *start_time);
+GType                   gdk_pixbuf_animation_iter_get_type                   (void) G_GNUC_CONST;
+int                     gdk_pixbuf_animation_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+GdkPixbuf              *gdk_pixbuf_animation_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+gboolean                gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+void                    gdk_pixbuf_animation_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                              const GTimeVal         *current_time);
 
-GdkPixbuf           *gdk_pixbuf_frame_get_pixbuf     (GdkPixbufFrame *frame);
-int                  gdk_pixbuf_frame_get_x_offset   (GdkPixbufFrame *frame);
-int                  gdk_pixbuf_frame_get_y_offset   (GdkPixbufFrame *frame);
-int                  gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame);
-GdkPixbufFrameAction gdk_pixbuf_frame_get_action     (GdkPixbufFrame *frame);
-GdkPixbufFrame      *gdk_pixbuf_frame_copy           (GdkPixbufFrame *src);
-void                 gdk_pixbuf_frame_free           (GdkPixbufFrame *frame);
-GType                gdk_pixbuf_frame_get_type       (void) G_GNUC_CONST;
-#define              GDK_TYPE_PIXBUF_FRAME gdk_pixbuf_frame_get_type ()
 
+ 
 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
 
 
Index: io-bmp.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-bmp.c,v
retrieving revision 1.20
diff -u -u -r1.20 io-bmp.c
--- io-bmp.c	2001/01/22 23:09:43	1.20
+++ io-bmp.c	2001/05/04 16:35:10
@@ -174,9 +174,7 @@
 static gpointer
 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
 				 ModuleUpdatedNotifyFunc updated_func,
-				 ModuleFrameDoneNotifyFunc frame_done_func,
-				 ModuleAnimationDoneNotifyFunc
-				 anim_done_func, gpointer user_data,
+                                 gpointer user_data,
                                  GError **error);
 
 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
@@ -198,7 +196,7 @@
 	GdkPixbuf *pb;
 
 	State =
-	    gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+	    gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL,
                                              error);
 
         if (State == NULL)
@@ -312,7 +310,7 @@
                 
 		if (State->prepared_func != NULL)
 			/* Notify the client that we are ready to go */
-			(*State->prepared_func) (State->pixbuf, State->user_data);
+			(*State->prepared_func) (State->pixbuf, NULL, State->user_data);
 
 	}
 
@@ -328,9 +326,7 @@
 static gpointer
 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
 				 ModuleUpdatedNotifyFunc updated_func,
-				 ModuleFrameDoneNotifyFunc frame_done_func,
-				 ModuleAnimationDoneNotifyFunc
-				 anim_done_func, gpointer user_data,
+                                 gpointer user_data,
                                  GError **error)
 {
 	struct bmp_progressive_state *context;
Index: io-gif.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-gif.c,v
retrieving revision 1.54
diff -u -u -r1.54 io-gif.c
--- io-gif.c	2001/01/22 23:09:43	1.54
+++ io-gif.c	2001/05/04 16:35:10
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 /* GdkPixbuf library - GIF image loader
  *
  * Copyright (C) 1999 Mark Crichton
@@ -30,10 +31,6 @@
  * in it got a bit messy.  Basicly, every function is written to expect a failed
  * read_gif, and lets you call it again assuming that the bytes are there.
  *
- * A note on Animations:
- * Currently, it doesn't correctly read the different colormap per frame.  This
- * needs implementing sometime.
- *
  * Return vals.
  * Unless otherwise specified, these are the return vals for most functions:
  *
@@ -59,11 +56,15 @@
 #include <config.h>
 #include <stdio.h>
 #include <string.h>
+#include <errno.h>
 #include "gdk-pixbuf-private.h"
 #include "gdk-pixbuf-io.h"
+#include "io-gif-animation.h"
 
 
 
+#undef DUMP_IMAGE_DETAILS
+
 #define MAXCOLORMAPSIZE  256
 #define MAX_LZW_BITS     12
 
@@ -88,7 +89,7 @@
 	GIF_LZW_FILL_BUFFER,
 	GIF_LZW_CLEAR_CODE,
 	GIF_GET_LZW,
-	GIF_DONE,
+	GIF_DONE
 };
 
 
@@ -107,19 +108,27 @@
 	int state; /* really only relevant for progressive loading */
 	unsigned int width;
 	unsigned int height;
-	CMap color_map;
-	CMap frame_color_map;
-	unsigned int bit_pixel;
-	unsigned int color_resolution;
-	unsigned int background;
+
+        gboolean has_global_cmap;
+
+        CMap global_color_map;
+        gint global_colormap_size;
+        unsigned int global_bit_pixel;
+	unsigned int global_color_resolution;
+        unsigned int background_index;
+
+        gboolean frame_cmap_active;
+        CMap frame_color_map;
+        gint frame_colormap_size;
+        unsigned int frame_bit_pixel;
+
 	unsigned int aspect_ratio;
 	GdkPixbuf *pixbuf;
-	GdkPixbufAnimation *animation;
+	GdkPixbufGifAnim *animation;
 	GdkPixbufFrame *frame;
 	Gif89 gif89;
 
-	/* stuff per frame.  As we only support the first one, not so
-	 * relevant.  But still needed */
+	/* stuff per frame. */
 	int frame_len;
 	int frame_height;
 	int frame_interlace;
@@ -132,18 +141,12 @@
 	/* progressive read, only. */
 	ModulePreparedNotifyFunc prepare_func;
 	ModuleUpdatedNotifyFunc update_func;
-	ModuleFrameDoneNotifyFunc frame_done_func;
-	ModuleAnimationDoneNotifyFunc anim_done_func;
 	gpointer user_data;
         guchar *buf;
 	guint ptr;
 	guint size;
 	guint amount_needed;
 
-	/* colormap context */
-	gint colormap_index;
-	gint colormap_flag;
-
 	/* extension context */
 	guchar extension_label;
 	guchar extension_flag;
@@ -207,7 +210,14 @@
 		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);
+
+                if (!retval && ferror (context->file))
+                        g_set_error (context->error,
+                                     G_FILE_ERROR,
+                                     g_file_error_from_errno (errno),
+                                     _("Failure reading GIF: %s"), strerror (errno));
+                
 #ifdef IO_GIFDEBUG
 		if (len < 100) {
 			for (i = 0; i < len; i++)
@@ -247,16 +257,14 @@
 static void
 gif_set_get_colormap (GifContext *context)
 {
-	context->colormap_flag = TRUE;
-	context->colormap_index = 0;
+	context->global_colormap_size = 0;
 	context->state = GIF_GET_COLORMAP;
 }
 
 static void
 gif_set_get_colormap2 (GifContext *context)
 {
-	context->colormap_flag = TRUE;
-	context->colormap_index = 0;
+	context->frame_colormap_size = 0;
 	context->state = GIF_GET_COLORMAP2;
 }
 
@@ -264,19 +272,44 @@
 gif_get_colormap (GifContext *context)
 {
 	unsigned char rgb[3];
+
+	while (context->global_colormap_size < context->global_bit_pixel) {
+		if (!gif_read (context, rgb, sizeof (rgb))) {
+			return -1;
+		}
+
+		context->global_color_map[0][context->global_colormap_size] = rgb[0];
+		context->global_color_map[1][context->global_colormap_size] = rgb[1];
+		context->global_color_map[2][context->global_colormap_size] = rgb[2];
+
+                if (context->global_colormap_size == context->background_index) {
+                        context->animation->bg_red = rgb[0];
+                        context->animation->bg_green = rgb[1];
+                        context->animation->bg_blue = rgb[2];
+                }
+
+		context->global_colormap_size ++;
+	}
+
+	return 0;
+}
+
+
+static gint
+gif_get_colormap2 (GifContext *context)
+{
+	unsigned char rgb[3];
 
-	while (context->colormap_index < context->bit_pixel) {
+	while (context->frame_colormap_size < context->frame_bit_pixel) {
 		if (!gif_read (context, rgb, sizeof (rgb))) {
-			/*g_message (_("GIF: bad colormap\n"));*/
 			return -1;
 		}
 
-		context->color_map[0][context->colormap_index] = rgb[0];
-		context->color_map[1][context->colormap_index] = rgb[1];
-		context->color_map[2][context->colormap_index] = rgb[2];
+		context->frame_color_map[0][context->frame_colormap_size] = rgb[0];
+		context->frame_color_map[1][context->frame_colormap_size] = rgb[1];
+		context->frame_color_map[2][context->frame_colormap_size] = rgb[2];
 
-		context->colormap_flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
-		context->colormap_index ++;
+		context->frame_colormap_size ++;
 	}
 
 	return 0;
@@ -348,9 +381,11 @@
 			retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
 			if (retval != 0)
 				return retval;
-			if (context->pixbuf == NULL) {
+
+			if (context->frame == NULL) {
 				/* I only want to set the transparency if I haven't
-				 * created the pixbuf yet. */
+				 * created the frame yet.
+                                 */
 				context->gif89.disposal = (context->block_buf[0] >> 2) & 0x7;
 				context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1;
 				context->gif89.delay_time = LM_to_uint (context->block_buf[1], context->block_buf[2]);
@@ -623,18 +658,24 @@
 gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
 {
 	guchar *pixel = NULL;
+        guchar (*cmap)[MAXCOLORMAPSIZE];
 
+        if (context->frame_cmap_active)
+                cmap = context->frame_color_map;
+        else
+                cmap = context->global_color_map;
+        
 	if (context->gif89.transparent != -1) {
-		pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
-		*pixel = context->color_map [0][(guchar) v];
-		*(pixel+1) = context->color_map [1][(guchar) v];
-		*(pixel+2) = context->color_map [2][(guchar) v];
-		*(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 65535);
+		pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+		*pixel = cmap [0][(guchar) v];
+		*(pixel+1) = cmap [1][(guchar) v];
+		*(pixel+2) = cmap [2][(guchar) v];
+		*(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
 	} else {
-		pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
-		*pixel = context->color_map [0][(guchar) v];
-		*(pixel+1) = context->color_map [1][(guchar) v];
-		*(pixel+2) = context->color_map [2][(guchar) v];
+		pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 3;
+		*pixel = cmap [0][(guchar) v];
+		*(pixel+1) = cmap [1][(guchar) v];
+		*(pixel+2) = cmap [2][(guchar) v];
 	}
 }
 
@@ -682,80 +723,123 @@
 	gint first_pass; /* bounds for emitting the area_updated signal */
 	gint v;
 
-	if (context->pixbuf == NULL) {
-		context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-						  context->gif89.transparent != -1,
-						  8,
-						  context->frame_len,
-						  context->frame_height);
-
-		if (context->prepare_func)
-			(* context->prepare_func) (context->pixbuf, context->user_data);
-		if (context->animation || context->frame_done_func || context->anim_done_func) {
-			context->frame = g_new (GdkPixbufFrame, 1);
-			context->frame->x_offset = context->x_offset;
-			context->frame->y_offset = context->y_offset;;
-			context->frame->delay_time = context->gif89.delay_time;
-			switch (context->gif89.disposal) {
-			case 0:
-			case 1:
-				context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
-				break;
-			case 2:
-				context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
-				break;
-			case 3:
-				context->frame->action = GDK_PIXBUF_FRAME_REVERT;
-				break;
-			default:
-				context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
-				break;
-			}
-			context->frame->pixbuf = context->pixbuf;
-			if (context->animation) {
-				int w,h;
-				context->animation->n_frames ++;
-				context->animation->frames = g_list_append (context->animation->frames, context->frame);
-				w = gdk_pixbuf_get_width (context->pixbuf);
-				h = gdk_pixbuf_get_height (context->pixbuf);
-				if (w > context->animation->width)
-					context->animation->width = w;
-				if (h > context->animation->height)
-					context->animation->height = h;
-			}
-		}
-	}
-	dest = gdk_pixbuf_get_pixels (context->pixbuf);
+	if (context->frame == NULL) {
+                context->frame = g_new (GdkPixbufFrame, 1);
+
+                context->frame->composited = NULL;
+                context->frame->revert = NULL;
+                
+                context->frame->pixbuf =
+                        gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                        TRUE,
+                                        8,
+                                        context->frame_len,
+                                        context->frame_height);
+                
+                context->frame->x_offset = context->x_offset;
+                context->frame->y_offset = context->y_offset;
+                context->frame->need_recomposite = TRUE;
+                
+                /* GIF delay is in hundredths, we want thousandths */
+                context->frame->delay_time = context->gif89.delay_time * 10;
+                context->frame->elapsed = context->animation->total_time;
+                context->animation->total_time += context->frame->delay_time;
+                
+                switch (context->gif89.disposal) {
+                case 0:
+                case 1:
+                        context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+                        break;
+                case 2:
+                        context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
+                        break;
+                case 3:
+                        context->frame->action = GDK_PIXBUF_FRAME_REVERT;
+                        break;
+                default:
+                        context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+                        break;
+                }
+
+                context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
+                
+                {
+                        /* Update animation size */
+                        int w, h;
+                        
+                        context->animation->n_frames ++;
+                        context->animation->frames = g_list_append (context->animation->frames, context->frame);
+
+                        w = context->frame->x_offset +
+                                gdk_pixbuf_get_width (context->frame->pixbuf);
+                        h = context->frame->y_offset +
+                                gdk_pixbuf_get_height (context->frame->pixbuf);
+                        if (w > context->animation->width)
+                                context->animation->width = w;
+                        if (h > context->animation->height)
+                                context->animation->height = h;
+                }
+
+                /* Only call prepare_func for the first frame */
+		if (context->animation->frames->next == NULL) { 
+                        if (context->prepare_func)
+                                (* context->prepare_func) (context->frame->pixbuf,
+                                                           GDK_PIXBUF_ANIMATION (context->animation),
+                                                           context->user_data);
+                } else {
+                        /* Otherwise init frame with last frame */
+                        GList *link;
+                        GdkPixbufFrame *prev_frame;
+                        
+                        link = g_list_find (context->animation->frames, context->frame);
+
+                        prev_frame = link->prev->data;
+
+                        gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
+
+                        gdk_pixbuf_copy_area (prev_frame->composited,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              gdk_pixbuf_get_height (context->frame->pixbuf),
+                                              context->frame->pixbuf,
+                                              0, 0);
+                }
+        }
+
+	dest = gdk_pixbuf_get_pixels (context->frame->pixbuf);
 
 	bound_flag = FALSE;
 	lower_bound = upper_bound = context->draw_ypos;
 	first_pass = context->draw_pass;
 
 	while (TRUE) {
+                guchar (*cmap)[MAXCOLORMAPSIZE];
+
+                if (context->frame_cmap_active)
+                        cmap = context->frame_color_map;
+                else
+                        cmap = context->global_color_map;
+                
 		v = lzw_read_byte (context);
 		if (v < 0) {
 			goto finished_data;
 		}
 		bound_flag = TRUE;
 
-		if (context->gif89.transparent != -1) {
-			temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
-			*temp = context->color_map [0][(guchar) v];
-			*(temp+1) = context->color_map [1][(guchar) v];
-			*(temp+2) = context->color_map [2][(guchar) v];
-			*(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : -1);
-		} else {
-			temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
-			*temp = context->color_map [0][(guchar) v];
-			*(temp+1) = context->color_map [1][(guchar) v];
-			*(temp+2) = context->color_map [2][(guchar) v];
-		}
+                g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
+                
+                temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+                *temp = cmap [0][(guchar) v];
+                *(temp+1) = cmap [1][(guchar) v];
+                *(temp+2) = cmap [2][(guchar) v];
+                *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
 
 		if (context->prepare_func && context->frame_interlace)
 			gif_fill_in_lines (context, dest, v);
 
 		context->draw_xpos++;
-
+                
 		if (context->draw_xpos == context->frame_len) {
 			context->draw_xpos = 0;
 			if (context->frame_interlace) {
@@ -796,7 +880,7 @@
 					lower_bound = 0;
 					upper_bound = context->frame_height;
 				} else {
-
+                                        
 				}
 			} else
 				upper_bound = context->draw_ypos;
@@ -804,56 +888,60 @@
 		if (context->draw_ypos >= context->frame_height)
 			break;
 	}
+
  done:
-	/* we got enough data. there may be more (ie, newer layers) but we can quit now */
-	if (context->animation || context->frame_done_func || context->anim_done_func) {
-		context->state = GIF_GET_NEXT_STEP;
-	} else
-		context->state = GIF_DONE;
-	v = 0;
+
+        context->state = GIF_GET_NEXT_STEP;
+
+        v = 0;
+
  finished_data:
+        
+        if (bound_flag)
+                context->frame->need_recomposite = TRUE;
+        
 	if (bound_flag && context->update_func) {
 		if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
 			(* context->update_func)
-				(context->pixbuf,
+				(context->frame->pixbuf,
 				 0, lower_bound,
-				 gdk_pixbuf_get_width (context->pixbuf),
+				 gdk_pixbuf_get_width (context->frame->pixbuf),
 				 upper_bound - lower_bound,
 				 context->user_data);
 		} else {
 			if (lower_bound <= upper_bound) {
 				(* context->update_func)
-					(context->pixbuf,
-					 0, 0,
-					 gdk_pixbuf_get_width (context->pixbuf),
-					 gdk_pixbuf_get_height (context->pixbuf),
+					(context->frame->pixbuf,
+					 context->frame->x_offset,
+                                         context->frame->y_offset,
+					 gdk_pixbuf_get_width (context->frame->pixbuf),
+					 gdk_pixbuf_get_height (context->frame->pixbuf),
 					 context->user_data);
 			} else {
 				(* context->update_func)
-					(context->pixbuf,
-					 0, 0,
-					 gdk_pixbuf_get_width (context->pixbuf),
+					(context->frame->pixbuf,
+					 context->frame->x_offset,
+                                         context->frame->y_offset,
+					 gdk_pixbuf_get_width (context->frame->pixbuf),
 					 upper_bound,
 					 context->user_data);
 				(* context->update_func)
-					(context->pixbuf,
-					 0, lower_bound,
-					 gdk_pixbuf_get_width (context->pixbuf),
-					 gdk_pixbuf_get_height (context->pixbuf),
+					(context->frame->pixbuf,
+					 context->frame->x_offset,
+                                         lower_bound + context->frame->y_offset,
+					 gdk_pixbuf_get_width (context->frame->pixbuf),
+					 gdk_pixbuf_get_height (context->frame->pixbuf),
 					 context->user_data);
 			}
 		}
 	}
 
-	if ((context->animation || context->frame_done_func || context->anim_done_func)
-	    && context->state == GIF_GET_NEXT_STEP) {
-		if (context->frame_done_func)
-			(* context->frame_done_func) (context->frame,
-						      context->user_data);
-		if (context->frame_done_func)
-			gdk_pixbuf_unref (context->pixbuf);
-		context->pixbuf = NULL;
+	if (context->state == GIF_GET_NEXT_STEP) {
+                /* Will be freed with context->animation, we are just
+                 * marking that we're done with it (no current frame)
+                 */
 		context->frame = NULL;
+                context->frame_cmap_active = FALSE;
 	}
 	
 	return v;
@@ -943,16 +1031,36 @@
 
 	context->width = LM_to_uint (buf[0], buf[1]);
 	context->height = LM_to_uint (buf[2], buf[3]);
-	context->bit_pixel = 2 << (buf[4] & 0x07);
-	context->color_resolution = (((buf[4] & 0x70) >> 3) + 1);
-	context->background = buf[5];
+        /* The 4th byte is
+         * high bit: whether to use the background index
+         * next 3:   color resolution
+         * next:     whether colormap is sorted by priority of allocation
+         * last 3:   size of colormap
+         */
+	context->global_bit_pixel = 2 << (buf[4] & 0x07);
+	context->global_color_resolution = (((buf[4] & 0x70) >> 3) + 1);
+        context->has_global_cmap = (buf[4] & 0x80) != 0;
+	context->background_index = buf[5];
 	context->aspect_ratio = buf[6];
 
-	if (BitSet (buf[4], LOCALCOLORMAP)) {
+        /* Use background of transparent black as default, though if
+         * one isn't set explicitly no one should ever use it.
+         */
+        context->animation->bg_red = 0;
+        context->animation->bg_green = 0;
+        context->animation->bg_blue = 0;
+        
+	if (context->has_global_cmap) {
 		gif_set_get_colormap (context);
 	} else {
 		context->state = GIF_GET_NEXT_STEP;
 	}
+
+#ifdef DUMP_IMAGE_DETAILS
+        g_print (">Image width: %d height: %d global_cmap: %d background: %d\n",
+                 context->width, context->height, context->has_global_cmap, context->background_index);
+#endif
+        
 	return 0;
 }
 
@@ -966,38 +1074,81 @@
 gif_get_frame_info (GifContext *context)
 {
 	unsigned char buf[9];
+        
 	if (!gif_read (context, buf, 9)) {
 		return -1;
 	}
+        
 	/* Okay, we got all the info we need.  Lets record it */
 	context->frame_len = LM_to_uint (buf[4], buf[5]);
 	context->frame_height = LM_to_uint (buf[6], buf[7]);
 	context->x_offset = LM_to_uint (buf[0], buf[1]);
 	context->y_offset = LM_to_uint (buf[2], buf[3]);
+
+	if (((context->frame_height + context->y_offset) > context->height) ||
+            ((context->frame_len + context->x_offset) > context->width)) {
+		/* All frames must fit in the image bounds */
+		context->state = GIF_DONE;
 
-	if (context->frame_height > context->height) {
-		/* we don't want to resize things.  So we exit */
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("GIF image contained a frame appearing outside the image bounds."));
+                
+		return -2;
+	}
+        
+	if (context->animation->frames == NULL &&
+            context->gif89.disposal == 3) {
+                /* First frame can't have "revert to previous" as its
+                 * dispose mode.
+                 */
+                
 		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"));
+                             _("First frame of GIF image had 'revert to previous' as its disposal mode."));
                 
 		return -2;
 	}
 
+#ifdef DUMP_IMAGE_DETAILS
+        g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d\n",
+                 context->frame_len, context->frame_height, context->x_offset, context->y_offset,
+                 context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent);
+#endif
+        
 	context->frame_interlace = BitSet (buf[8], INTERLACE);
 	if (BitSet (buf[8], LOCALCOLORMAP)) {
+
+#ifdef DUMP_IMAGE_DETAILS
+                g_print (">has local colormap\n");
+#endif
+                
 		/* Does this frame have it's own colormap. */
 		/* really only relevant when looking at the first frame
 		 * of an animated gif. */
 		/* if it does, we need to re-read in the colormap,
 		 * the gray_scale, and the bit_pixel */
-		context->bit_pixel = 1 << ((buf[8] & 0x07) + 1);
+                context->frame_cmap_active = TRUE;
+		context->frame_bit_pixel = 1 << ((buf[8] & 0x07) + 1);
 		gif_set_get_colormap2 (context);
 		return 0;
 	}
+
+        if (!context->has_global_cmap) {
+                context->state = GIF_DONE;
+                
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("GIF image has no global colormap, and a frame inside it has no local colormap."));
+                
+		return -2;
+        }
+
 	gif_set_prepare_lzw (context);
 	return 0;
 
@@ -1037,6 +1188,8 @@
 }
 
 
+#define LOG(x)
+
 static gint
 gif_main_loop (GifContext *context)
 {
@@ -1045,52 +1198,63 @@
 	do {
 		switch (context->state) {
 		case GIF_START:
+                        LOG("start\n");
 			retval = gif_init (context);
 			break;
 
 		case GIF_GET_COLORMAP:
+                        LOG("get_colormap\n");
 			retval = gif_get_colormap (context);
 			if (retval == 0)
 				context->state = GIF_GET_NEXT_STEP;
 			break;
 
 		case GIF_GET_NEXT_STEP:
+                        LOG("next_step\n");
 			retval = gif_get_next_step (context);
 			break;
 
 		case GIF_GET_FRAME_INFO:
+                        LOG("frame_info\n");
 			retval = gif_get_frame_info (context);
 			break;
 
 		case GIF_GET_EXTENTION:
+                        LOG("get_extension\n");
 			retval = gif_get_extension (context);
 			if (retval == 0)
 				context->state = GIF_GET_NEXT_STEP;
 			break;
 
 		case GIF_GET_COLORMAP2:
-			retval = gif_get_colormap (context);
+                        LOG("get_colormap2\n");
+			retval = gif_get_colormap2 (context);
 			if (retval == 0)
 				gif_set_prepare_lzw (context);
 			break;
 
 		case GIF_PREPARE_LZW:
+                        LOG("prepare_lzw\n");
 			retval = gif_prepare_lzw (context);
 			break;
 
 		case GIF_LZW_FILL_BUFFER:
+                        LOG("fill_buffer\n");
 			retval = gif_lzw_fill_buffer (context);
 			break;
 
 		case GIF_LZW_CLEAR_CODE:
+                        LOG("clear_code\n");
 			retval = gif_lzw_clear_code (context);
 			break;
 
 		case GIF_GET_LZW:
+                        LOG("get_lzw\n");
 			retval = gif_get_lzw (context);
 			break;
 
 		case GIF_DONE:
+                        LOG("done\n");
 		default:
 			retval = 0;
 			goto done;
@@ -1107,13 +1271,12 @@
 
 	context = g_new0 (GifContext, 1);
 
-	context->pixbuf = NULL;
+        context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);        
+	context->frame = NULL;
 	context->file = NULL;
 	context->state = GIF_START;
 	context->prepare_func = NULL;
 	context->update_func = NULL;
-	context->frame_done_func = NULL;
-	context->anim_done_func = NULL;
 	context->user_data = NULL;
 	context->buf = NULL;
 	context->amount_needed = 0;
@@ -1136,10 +1299,23 @@
 	context = new_context ();
 	context->file = file;
         context->error = error;
+        
+	if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
+                if (context->error && *(context->error) == NULL)
+                        g_set_error (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+        }
         
-	gif_main_loop (context);
+        pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
 
-	pixbuf = context->pixbuf;
+        if (pixbuf)
+                g_object_ref (G_OBJECT (pixbuf));
+
+        g_object_unref (G_OBJECT (context->animation));
+        
+        g_free (context->buf);
 	g_free (context);
  
 	return pixbuf;
@@ -1148,8 +1324,6 @@
 static gpointer
 gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
 				  ModuleUpdatedNotifyFunc update_func,
-				  ModuleFrameDoneNotifyFunc frame_done_func,
-				  ModuleAnimationDoneNotifyFunc anim_done_func,
 				  gpointer user_data,
                                   GError **error)
 {
@@ -1162,8 +1336,6 @@
         context->error = error;
 	context->prepare_func = prepare_func;
 	context->update_func = update_func;
-	context->frame_done_func = frame_done_func;
-	context->anim_done_func = anim_done_func;
 	context->user_data = user_data;
 
 	return (gpointer) context;
@@ -1173,21 +1345,23 @@
 gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
 {
 	GifContext *context = (GifContext *) data;
-
-	/* FIXME: free the animation data */
+        gboolean retval = TRUE;
         
-        /* FIXME this thing needs to report errors if
-         * we have unused image data
-         */
+        if (context->state != GIF_DONE) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("GIF image was truncated or incomplete."));
+
+                retval = FALSE;
+        }
         
-	if (context->pixbuf)
-		gdk_pixbuf_unref (context->pixbuf);
-	if (context->animation)
-		gdk_pixbuf_animation_unref (context->animation);
-/*  	g_free (context->buf);*/
+        g_object_unref (G_OBJECT (context->animation));
+
+  	g_free (context->buf);
 	g_free (context);
 
-        return TRUE;
+        return retval;
 }
 
 static gboolean
@@ -1264,18 +1438,28 @@
 	context = new_context ();
 
         context->error = error;
-        
-	context->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-
-	context->animation->n_frames = 0;
-	context->animation->frames = NULL;
-	context->animation->width = 0;
-	context->animation->height = 0;
 	context->file = file;
 
-	gif_main_loop (context);
+	if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
+                if (context->error && *(context->error) == NULL)
+                        g_set_error (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+
+                g_object_unref (G_OBJECT (context->animation));
+                context->animation = NULL;
+        }
+
+        if (context->animation)
+                animation = GDK_PIXBUF_ANIMATION (context->animation);
+        else
+                animation = NULL;
 
-	animation = context->animation;
+        if (context->error && *(context->error))
+                g_print ("%s\n", (*(context->error))->message);
+        
+        g_free (context->buf);
 	g_free (context);
 	return animation;
 }
Index: io-ico.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-ico.c,v
retrieving revision 1.13
diff -u -u -r1.13 io-ico.c
--- io-ico.c	2001/01/22 23:09:43	1.13
+++ io-ico.c	2001/05/04 16:35:10
@@ -156,8 +156,6 @@
 static gpointer
 gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
 				 ModuleUpdatedNotifyFunc updated_func,
-				 ModuleFrameDoneNotifyFunc frame_done_func,
-				 ModuleAnimationDoneNotifyFunc anim_done_func,
 				 gpointer user_data,
                                  GError **error);
 static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
@@ -178,8 +176,8 @@
 
 	GdkPixbuf *pb;
 
-	State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL,
-                                                 NULL, NULL, error);
+	State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
+
         if (State == NULL)
           return NULL;
         
@@ -363,6 +361,7 @@
 		if (State->prepared_func != NULL)
 			/* Notify the client that we are ready to go */
 			(*State->prepared_func) (State->pixbuf,
+                                                 NULL,
 						 State->user_data);
 
 	}
@@ -378,8 +377,6 @@
 static gpointer
 gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
 				 ModuleUpdatedNotifyFunc updated_func,
-				 ModuleFrameDoneNotifyFunc frame_done_func,
-				 ModuleAnimationDoneNotifyFunc anim_done_func,
 				 gpointer user_data,
                                  GError **error)
 {
Index: io-jpeg.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-jpeg.c,v
retrieving revision 1.36
diff -u -u -r1.36 io-jpeg.c
--- io-jpeg.c	2001/02/19 14:35:24	1.36
+++ io-jpeg.c	2001/05/04 16:35:10
@@ -96,8 +96,6 @@
 static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
 static gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func, 
                                                    ModuleUpdatedNotifyFunc func2,
-                                                   ModuleFrameDoneNotifyFunc func3,
-                                                   ModuleAnimationDoneNotifyFunc func4,
                                                    gpointer user_data,
                                                    GError **error);
 static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
@@ -321,8 +319,6 @@
 gpointer
 gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func, 
 				   ModuleUpdatedNotifyFunc  updated_func,
-				   ModuleFrameDoneNotifyFunc frame_func,
-				   ModuleAnimationDoneNotifyFunc anim_done_func,
 				   gpointer user_data,
                                    GError **error)
 {
@@ -539,6 +535,7 @@
 
 			/* Notify the client that we are ready to go */
 			(* context->prepared_func) (context->pixbuf,
+                                                    NULL,
 						    context->user_data);
 
 		} else if (!context->did_prescan) {
Index: io-png.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-png.c,v
retrieving revision 1.37
diff -u -u -r1.37 io-png.c
--- io-png.c	2001/02/19 14:35:24	1.37
+++ io-png.c	2001/05/04 16:35:10
@@ -324,8 +324,6 @@
 static gpointer
 gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func,
 				  ModuleUpdatedNotifyFunc update_func,
-				  ModuleFrameDoneNotifyFunc frame_done_func,
-				  ModuleAnimationDoneNotifyFunc anim_done_func,
 				  gpointer user_data,
                                   GError **error)
 {
@@ -540,7 +538,7 @@
         /* Notify the client that we are ready to go */
 
         if (lc->prepare_func)
-                (* lc->prepare_func) (lc->pixbuf, lc->notify_user_data);
+                (* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);
         
         return;
 }
Index: io-pnm.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-pnm.c,v
retrieving revision 1.20
diff -u -u -r1.20 io-pnm.c
--- io-pnm.c	2001/01/22 23:09:43	1.20
+++ io-pnm.c	2001/05/04 16:35:10
@@ -84,8 +84,6 @@
 static GdkPixbuf   *gdk_pixbuf__pnm_image_load          (FILE *f, GError **error);
 static gpointer    gdk_pixbuf__pnm_image_begin_load     (ModulePreparedNotifyFunc func, 
 							 ModuleUpdatedNotifyFunc func2,
-							 ModuleFrameDoneNotifyFunc frame_done_func,
-							 ModuleAnimationDoneNotifyFunc anim_done_func,
 							 gpointer user_data,
 							 GError **error);
 static gboolean    gdk_pixbuf__pnm_image_stop_load      (gpointer context, GError **error);
@@ -763,8 +761,6 @@
 static gpointer
 gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func, 
 				  ModuleUpdatedNotifyFunc  updated_func,
-				  ModuleFrameDoneNotifyFunc frame_done_func,
-				  ModuleAnimationDoneNotifyFunc anim_done_func,
 				  gpointer user_data,
 				  GError **error)
 {
@@ -923,6 +919,7 @@
 			
 			/* Notify the client that we are ready to go */
 			(* context->prepared_func) (context->pixbuf,
+						    NULL,
 						    context->user_data);
 		}
 		
Index: io-ras.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-ras.c,v
retrieving revision 1.17
diff -u -u -r1.17 io-ras.c
--- io-ras.c	2001/01/22 23:09:43	1.17
+++ io-ras.c	2001/05/04 16:35:10
@@ -96,8 +96,6 @@
 static gpointer
 gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
 				 ModuleUpdatedNotifyFunc updated_func,
-				 ModuleFrameDoneNotifyFunc frame_done_func,
-				 ModuleAnimationDoneNotifyFunc anim_done_func,
 				 gpointer user_data,
                                  GError **error);
 static gboolean gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error);
@@ -116,8 +114,7 @@
 	
 	GdkPixbuf *pb;
 	
-	State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL,
-                                                 NULL, NULL, error);
+	State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, error);
 	
 	membuf = g_malloc(4096);
 	
@@ -195,6 +192,7 @@
 		if (State->prepared_func != NULL)
 			/* Notify the client that we are ready to go */
 			(*State->prepared_func) (State->pixbuf,
+                                                 NULL,
 						 State->user_data);
 
 	}
@@ -219,8 +217,6 @@
 static gpointer
 gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
 				 ModuleUpdatedNotifyFunc updated_func,
-				 ModuleFrameDoneNotifyFunc frame_done_func,
-				 ModuleAnimationDoneNotifyFunc anim_done_func,
 				 gpointer user_data,
                                  GError **error)
 {
Index: io-tiff.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-tiff.c,v
retrieving revision 1.24
diff -u -u -r1.24 io-tiff.c
--- io-tiff.c	2001/01/22 23:09:43	1.24
+++ io-tiff.c	2001/05/04 16:35:10
@@ -92,7 +92,7 @@
         }
         
 	if (context)
-		(* context->prepare_func) (pixbuf, context->user_data);
+		(* context->prepare_func) (pixbuf, NULL, context->user_data);
 
 	/* Yes, it needs to be _TIFFMalloc... */
 	rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
@@ -163,8 +163,6 @@
 static gpointer
 gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
 				   ModuleUpdatedNotifyFunc update_func,
-				   ModuleFrameDoneNotifyFunc frame_done_func,
-				   ModuleAnimationDoneNotifyFunc anim_done_func,
 				   gpointer user_data,
                                    GError **error)
 {
Index: io-wbmp.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-wbmp.c,v
retrieving revision 1.8
diff -u -u -r1.8 io-wbmp.c
--- io-wbmp.c	2001/01/22 23:09:43	1.8
+++ io-wbmp.c	2001/05/04 16:35:10
@@ -65,9 +65,7 @@
 static gpointer
 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
 				  ModuleUpdatedNotifyFunc updated_func,
-				  ModuleFrameDoneNotifyFunc frame_done_func,
-				  ModuleAnimationDoneNotifyFunc
-				  anim_done_func, gpointer user_data,
+                                  gpointer user_data,
                                   GError **error);
 
 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
@@ -87,7 +85,7 @@
 
 	GdkPixbuf *pb;
 
-	State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+	State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL,
                                                   error);
 
         if (State == NULL)
@@ -120,9 +118,7 @@
 static gpointer
 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                   ModuleUpdatedNotifyFunc updated_func,
-                                  ModuleFrameDoneNotifyFunc frame_done_func,
-                                  ModuleAnimationDoneNotifyFunc
-                                  anim_done_func, gpointer user_data,
+                                  gpointer user_data,
                                   GError **error)
 {
 	struct wbmp_progressive_state *context;
@@ -285,7 +281,7 @@
 		    g_assert(context->pixbuf);
 
 		    if(context->prepared_func)
-		      context->prepared_func(context->pixbuf, context->user_data);
+		      context->prepared_func(context->pixbuf, NULL, context->user_data);
 		  }
 	      }
 	    else if(context->needmore)
Index: io-xbm.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-xbm.c,v
retrieving revision 1.2
diff -u -u -r1.2 io-xbm.c
--- io-xbm.c	2001/01/22 23:09:43	1.2
+++ io-xbm.c	2001/05/04 16:35:10
@@ -300,7 +300,7 @@
 	row_stride = gdk_pixbuf_get_rowstride (pixbuf);
 
 	if (context)
-		(* context->prepare_func) (pixbuf, context->user_data);
+		(* context->prepare_func) (pixbuf, NULL, context->user_data);
 
 
 	/* Initialize PIXBUF */
@@ -355,8 +355,6 @@
 static gpointer
 gdk_pixbuf__xbm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
 				  ModuleUpdatedNotifyFunc update_func,
-				  ModuleFrameDoneNotifyFunc frame_done_func,
-				  ModuleAnimationDoneNotifyFunc anim_done_func,
 				  gpointer user_data,
 				  GError **error)
 {
Index: io-xpm.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-xpm.c,v
retrieving revision 1.26
diff -u -u -r1.26 io-xpm.c
--- io-xpm.c	2001/02/07 11:37:05	1.26
+++ io-xpm.c	2001/05/04 16:35:10
@@ -1424,8 +1424,6 @@
 static gpointer
 gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
                                   ModuleUpdatedNotifyFunc update_func,
-                                  ModuleFrameDoneNotifyFunc frame_done_func,
-                                  ModuleAnimationDoneNotifyFunc anim_done_func,
                                   gpointer user_data,
                                   GError **error)
 {
@@ -1471,7 +1469,9 @@
                pixbuf = gdk_pixbuf__xpm_image_load (context->file, error);
 
                if (pixbuf != NULL) {
-                       (* context->prepare_func) (pixbuf, context->user_data);
+                       (* context->prepare_func) (pixbuf,
+                                                  NULL,
+                                                  context->user_data);
                        (* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
                        gdk_pixbuf_unref (pixbuf);
 
Index: pixops/pixops.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/pixops/pixops.c,v
retrieving revision 1.15
diff -u -u -r1.15 pixops.c
--- pixops/pixops.c	2000/10/09 17:22:20	1.15
+++ pixops/pixops.c	2001/05/04 16:35:10
@@ -1,4 +1,5 @@
 #include <math.h>
+#include <glib.h>
 #include "config.h"
 
 #include "pixops.h"
@@ -93,6 +94,7 @@
   for (i = 0; i < (render_y1 - render_y0); i++)
     {
       const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
+      /* FIXME Owen needs to look at this */
       guchar       *dest = dest_buf + i * dest_rowstride;
 
       x = render_x0 * x_step + x_step / 2;
@@ -160,7 +162,6 @@
   for (i = 0; i < (render_y1 - render_y0); i++)
     {
       const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
-      /* FIXME Owen needs to look at this */
       guchar       *dest = dest_buf + i * dest_rowstride;
 
       x = render_x0 * x_step + x_step / 2;
@@ -183,9 +184,9 @@
 
 	      if (w != 0)
 		{
-		  dest[0] = (w0 * src[0] + w1 * dest[0]) / w;
-		  dest[1] = (w0 * src[1] + w1 * dest[1]) / w;
-		  dest[2] = (w0 * src[2] + w1 * dest[2]) / w;
+		  dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
+		  dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
+		  dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
 		  dest[3] = w / 0xff;
 		}
 	      else
@@ -274,25 +275,39 @@
       for (j=0 ; j < (render_x1 - render_x0); j++)
 	{
 	  const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
-          unsigned int  a0;
+          int a0;
+	  int tmp;
 
 	  if (src_has_alpha)
 	    a0 = (p[3] * overall_alpha + 0xff) >> 8;
 	  else
 	    a0 = overall_alpha;
 
-	  if (((j + check_x) >> check_shift) & 1)
+	  if (a0 == 255)
 	    {
-	      dest[0] = r2 + ((a0 * ((int)p[0] - r2) + 0xff) >> 8);
-	      dest[1] = g2 + ((a0 * ((int)p[1] - g2) + 0xff) >> 8);
-	      dest[2] = b2 + ((a0 * ((int)p[2] - b2) + 0xff) >> 8);
-	    }
-	  else
-	    {
-	      dest[0] = r1 + ((a0 * ((int)p[0] - r1) + 0xff) >> 8);
-	      dest[1] = g1 + ((a0 * ((int)p[1] - g1) + 0xff) >> 8);
-	      dest[2] = b1 + ((a0 * ((int)p[2] - b1) + 0xff) >> 8);
-	    }
+	      dest[0] = p[0];
+	      dest[1] = p[1];
+	      dest[2] = p[2];
+	    }
+	  else
+	    if (((j + check_x) >> check_shift) & 1)
+	      {
+		tmp = ((int) p[0] - r2) * a0;
+		dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+		tmp = ((int) p[1] - g2) * a0;
+		dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+		tmp = ((int) p[2] - b2) * a0;
+		dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+	      }
+	    else
+	      {
+		tmp = ((int) p[0] - r1) * a0;
+		dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+		tmp = ((int) p[1] - g1) * a0;
+		dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+		tmp = ((int) p[2] - b1) * a0;
+		dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+	      }
 	  
 	  if (dest_channels == 4)
 	    dest[3] = 0xff;
@@ -1003,7 +1018,7 @@
 
       dest_x += (new_outbuf - outbuf) / dest_channels;
 
-      x = dest_x * x_step + scaled_x_offset;
+      x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
       outbuf = new_outbuf;
 
       while (outbuf < outbuf_end)




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