1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /* GdkPixbuf library - ani support
4 * Copyright (C) 2002 The Free Software Foundation
6 * Author: Matthias Clasen <maclas@gmx.de>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
26 #include "gdk-pixbuf-io.h"
27 #include "gdk-pixbuf-private.h"
28 #include "io-ani-animation.h"
30 static void gdk_pixbuf_ani_anim_class_init (GdkPixbufAniAnimClass *klass);
31 static void gdk_pixbuf_ani_anim_finalize (GObject *object);
33 static gboolean gdk_pixbuf_ani_anim_is_static_image (GdkPixbufAnimation *animation);
34 static GdkPixbuf* gdk_pixbuf_ani_anim_get_static_image (GdkPixbufAnimation *animation);
35 static void gdk_pixbuf_ani_anim_get_size (GdkPixbufAnimation *anim,
38 static GdkPixbufAnimationIter* gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
39 const GTimeVal *start_time);
44 static gpointer parent_class;
47 gdk_pixbuf_ani_anim_get_type (void)
49 static GType object_type = 0;
52 static const GTypeInfo object_info = {
53 sizeof (GdkPixbufAniAnimClass),
55 (GBaseFinalizeFunc) NULL,
56 (GClassInitFunc) gdk_pixbuf_ani_anim_class_init,
57 NULL, /* class_finalize */
58 NULL, /* class_data */
59 sizeof (GdkPixbufAniAnim),
61 (GInstanceInitFunc) NULL,
64 object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
65 g_intern_static_string ("GdkPixbufAniAnim"),
73 gdk_pixbuf_ani_anim_class_init (GdkPixbufAniAnimClass *klass)
75 GObjectClass *object_class = G_OBJECT_CLASS (klass);
76 GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
78 parent_class = g_type_class_peek_parent (klass);
80 object_class->finalize = gdk_pixbuf_ani_anim_finalize;
82 anim_class->is_static_image = gdk_pixbuf_ani_anim_is_static_image;
83 anim_class->get_static_image = gdk_pixbuf_ani_anim_get_static_image;
84 anim_class->get_size = gdk_pixbuf_ani_anim_get_size;
85 anim_class->get_iter = gdk_pixbuf_ani_anim_get_iter;
89 gdk_pixbuf_ani_anim_finalize (GObject *object)
91 GdkPixbufAniAnim *ani_anim = GDK_PIXBUF_ANI_ANIM (object);
94 for (i = 0; i < ani_anim->n_pixbufs; i++) {
95 if (ani_anim->pixbufs[i])
96 g_object_unref (ani_anim->pixbufs[i]);
98 g_free (ani_anim->pixbufs);
99 g_free (ani_anim->sequence);
100 g_free (ani_anim->delay);
102 G_OBJECT_CLASS (parent_class)->finalize (object);
106 gdk_pixbuf_ani_anim_is_static_image (GdkPixbufAnimation *animation)
108 GdkPixbufAniAnim *ani_anim;
110 ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
112 return ani_anim->n_frames == 1;
116 gdk_pixbuf_ani_anim_get_static_image (GdkPixbufAnimation *animation)
118 GdkPixbufAniAnim *ani_anim;
120 ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
122 if (ani_anim->pixbufs == NULL)
125 return ani_anim->pixbufs[0];
129 gdk_pixbuf_ani_anim_get_size (GdkPixbufAnimation *anim,
133 GdkPixbufAniAnim *ani_anim;
135 ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
138 *width = ani_anim->width;
141 *height = ani_anim->height;
146 iter_restart (GdkPixbufAniAnimIter *iter)
148 iter->current_frame = 0;
153 static GdkPixbufAnimationIter*
154 gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
155 const GTimeVal *start_time)
157 GdkPixbufAniAnimIter *iter;
159 iter = g_object_new (GDK_TYPE_PIXBUF_ANI_ANIM_ITER, NULL);
161 iter->ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
163 g_object_ref (iter->ani_anim);
167 iter->start_time = *start_time;
168 iter->current_time = *start_time;
170 return GDK_PIXBUF_ANIMATION_ITER (iter);
175 static void gdk_pixbuf_ani_anim_iter_class_init (GdkPixbufAniAnimIterClass *klass);
176 static void gdk_pixbuf_ani_anim_iter_finalize (GObject *object);
178 static int gdk_pixbuf_ani_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
179 static GdkPixbuf* gdk_pixbuf_ani_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
180 static gboolean gdk_pixbuf_ani_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
181 static gboolean gdk_pixbuf_ani_anim_iter_advance (GdkPixbufAnimationIter *iter,
182 const GTimeVal *current_time);
186 static gpointer iter_parent_class;
189 gdk_pixbuf_ani_anim_iter_get_type (void)
191 static GType object_type = 0;
194 static const GTypeInfo object_info = {
195 sizeof (GdkPixbufAniAnimIterClass),
196 (GBaseInitFunc) NULL,
197 (GBaseFinalizeFunc) NULL,
198 (GClassInitFunc) gdk_pixbuf_ani_anim_iter_class_init,
199 NULL, /* class_finalize */
200 NULL, /* class_data */
201 sizeof (GdkPixbufAniAnimIter),
203 (GInstanceInitFunc) NULL,
206 object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
207 g_intern_static_string ("GdkPixbufAniAnimIter"),
215 gdk_pixbuf_ani_anim_iter_class_init (GdkPixbufAniAnimIterClass *klass)
217 GObjectClass *object_class = G_OBJECT_CLASS (klass);
218 GdkPixbufAnimationIterClass *anim_iter_class =
219 GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
221 iter_parent_class = g_type_class_peek_parent (klass);
223 object_class->finalize = gdk_pixbuf_ani_anim_iter_finalize;
225 anim_iter_class->get_delay_time = gdk_pixbuf_ani_anim_iter_get_delay_time;
226 anim_iter_class->get_pixbuf = gdk_pixbuf_ani_anim_iter_get_pixbuf;
227 anim_iter_class->on_currently_loading_frame = gdk_pixbuf_ani_anim_iter_on_currently_loading_frame;
228 anim_iter_class->advance = gdk_pixbuf_ani_anim_iter_advance;
232 gdk_pixbuf_ani_anim_iter_finalize (GObject *object)
234 GdkPixbufAniAnimIter *iter = GDK_PIXBUF_ANI_ANIM_ITER (object);
236 g_object_unref (iter->ani_anim);
238 G_OBJECT_CLASS (iter_parent_class)->finalize (object);
242 gdk_pixbuf_ani_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
243 const GTimeVal *current_time)
245 GdkPixbufAniAnimIter *iter;
250 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
252 iter->current_time = *current_time;
254 /* We use milliseconds for all times */
256 (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
257 iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
260 /* Try to compensate; probably the system clock
263 iter->start_time = iter->current_time;
267 g_assert (iter->ani_anim->total_time > 0);
269 /* See how many times we've already played the full animation,
270 * and subtract time for that.
272 elapsed = elapsed % iter->ani_anim->total_time;
274 iter->position = elapsed;
276 /* Now move to the proper frame */
279 for (tmp = 0; tmp < iter->ani_anim->n_frames; tmp++) {
280 if (iter->position >= iter->elapsed &&
281 iter->position < (iter->elapsed + iter->ani_anim->delay[tmp]))
283 iter->elapsed += iter->ani_anim->delay[tmp];
286 old = iter->current_frame;
288 iter->current_frame = tmp;
290 return iter->current_frame != old;
294 gdk_pixbuf_ani_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
296 GdkPixbufAniAnimIter *iter;
298 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
300 return iter->ani_anim->delay[iter->current_frame] - (iter->position - iter->elapsed);
304 gdk_pixbuf_ani_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
306 GdkPixbufAniAnimIter *iter;
309 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
311 frame = iter->ani_anim->sequence[iter->current_frame];
313 /* this is necessary if the animation is displayed while loading */
314 while (frame > 0 && !iter->ani_anim->pixbufs[frame])
317 return iter->ani_anim->pixbufs[frame];
321 gdk_pixbuf_ani_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
323 GdkPixbufAniAnimIter *iter;
326 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
328 if (iter->current_frame >= iter->ani_anim->n_frames - 1)
331 frame = iter->ani_anim->sequence[iter->current_frame + 1];
333 if (!iter->ani_anim->pixbufs[frame])