1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* GdkPixbuf library - animated gdip support
4 * Copyright (C) 1999 The Free Software Foundation
6 * Authors: Jonathan Blandford <jrb@redhat.com>
7 * Havoc Pennington <hp@redhat.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 #include "io-gdip-native.h"
27 #include "io-gdip-animation.h"
29 static void gdk_pixbuf_gdip_anim_class_init (GdkPixbufGdipAnimClass *klass);
30 static void gdk_pixbuf_gdip_anim_finalize (GObject *object);
32 static gboolean gdk_pixbuf_gdip_anim_is_static_image (GdkPixbufAnimation *animation);
33 static GdkPixbuf* gdk_pixbuf_gdip_anim_get_static_image (GdkPixbufAnimation *animation);
35 static void gdk_pixbuf_gdip_anim_get_size (GdkPixbufAnimation *anim,
38 static GdkPixbufAnimationIter* gdk_pixbuf_gdip_anim_get_iter (GdkPixbufAnimation *anim,
39 const GTimeVal *start_time);
41 static gpointer parent_class;
44 gdk_pixbuf_gdip_anim_get_type (void)
46 static GType object_type = 0;
49 static const GTypeInfo object_info = {
50 sizeof (GdkPixbufGdipAnimClass),
52 (GBaseFinalizeFunc) NULL,
53 (GClassInitFunc) gdk_pixbuf_gdip_anim_class_init,
54 NULL, /* class_finalize */
55 NULL, /* class_data */
56 sizeof (GdkPixbufGdipAnim),
58 (GInstanceInitFunc) NULL,
61 object_type = g_type_from_name ("GdkPixbufGdipAnim");
62 if (object_type == 0) {
63 object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
64 g_intern_static_string ("GdkPixbufGdipAnim"),
73 gdk_pixbuf_gdip_anim_class_init (GdkPixbufGdipAnimClass *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_gdip_anim_finalize;
82 anim_class->is_static_image = gdk_pixbuf_gdip_anim_is_static_image;
83 anim_class->get_static_image = gdk_pixbuf_gdip_anim_get_static_image;
84 anim_class->get_size = gdk_pixbuf_gdip_anim_get_size;
85 anim_class->get_iter = gdk_pixbuf_gdip_anim_get_iter;
89 gdk_pixbuf_gdip_anim_finalize (GObject *object)
91 GdkPixbufGdipAnim *gdip_anim = GDK_PIXBUF_GDIP_ANIM (object);
94 GdkPixbufFrame *frame;
96 for (l = gdip_anim->frames; l; l = l->next) {
98 g_object_unref (frame->pixbuf);
102 g_list_free (gdip_anim->frames);
104 G_OBJECT_CLASS (parent_class)->finalize (object);
108 gdk_pixbuf_gdip_anim_is_static_image (GdkPixbufAnimation *animation)
110 GdkPixbufGdipAnim *gdip_anim;
112 gdip_anim = GDK_PIXBUF_GDIP_ANIM (animation);
114 return (gdip_anim->frames != NULL &&
115 gdip_anim->frames->next == NULL);
119 gdk_pixbuf_gdip_anim_get_static_image (GdkPixbufAnimation *animation)
121 GdkPixbufGdipAnim *gdip_anim;
123 gdip_anim = GDK_PIXBUF_GDIP_ANIM (animation);
125 if (gdip_anim->frames == NULL)
128 return GDK_PIXBUF (((GdkPixbufFrame*)gdip_anim->frames->data)->pixbuf);
132 gdk_pixbuf_gdip_anim_get_size (GdkPixbufAnimation *anim,
136 GdkPixbufGdipAnim *gdip_anim;
138 gdip_anim = GDK_PIXBUF_GDIP_ANIM (anim);
141 *width = gdip_anim->width;
144 *height = gdip_anim->height;
149 iter_clear (GdkPixbufGdipAnimIter *iter)
151 iter->current_frame = NULL;
155 iter_restart (GdkPixbufGdipAnimIter *iter)
159 iter->current_frame = iter->gdip_anim->frames;
162 static GdkPixbufAnimationIter*
163 gdk_pixbuf_gdip_anim_get_iter (GdkPixbufAnimation *anim,
164 const GTimeVal *start_time)
166 GdkPixbufGdipAnimIter *iter;
168 iter = g_object_new (GDK_TYPE_PIXBUF_GDIP_ANIM_ITER, NULL);
170 iter->gdip_anim = GDK_PIXBUF_GDIP_ANIM (anim);
172 g_object_ref (iter->gdip_anim);
176 iter->start_time = *start_time;
177 iter->current_time = *start_time;
178 iter->first_loop_slowness = 0;
180 return GDK_PIXBUF_ANIMATION_ITER (iter);
183 static void gdk_pixbuf_gdip_anim_iter_class_init (GdkPixbufGdipAnimIterClass *klass);
184 static void gdk_pixbuf_gdip_anim_iter_finalize (GObject *object);
186 static int gdk_pixbuf_gdip_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
187 static GdkPixbuf* gdk_pixbuf_gdip_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
188 static gboolean gdk_pixbuf_gdip_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
189 static gboolean gdk_pixbuf_gdip_anim_iter_advance (GdkPixbufAnimationIter *iter,
190 const GTimeVal *current_time);
192 static gpointer iter_parent_class;
195 gdk_pixbuf_gdip_anim_iter_get_type (void)
197 static GType object_type = 0;
200 static const GTypeInfo object_info = {
201 sizeof (GdkPixbufGdipAnimIterClass),
202 (GBaseInitFunc) NULL,
203 (GBaseFinalizeFunc) NULL,
204 (GClassInitFunc) gdk_pixbuf_gdip_anim_iter_class_init,
205 NULL, /* class_finalize */
206 NULL, /* class_data */
207 sizeof (GdkPixbufGdipAnimIter),
209 (GInstanceInitFunc) NULL,
212 object_type = g_type_from_name ("GdkPixbufGdipAnimIter");
213 if (object_type == 0) {
214 object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
215 g_intern_static_string ("GdkPixbufGdipAnimIter"),
224 gdk_pixbuf_gdip_anim_iter_class_init (GdkPixbufGdipAnimIterClass *klass)
226 GObjectClass *object_class = G_OBJECT_CLASS (klass);
227 GdkPixbufAnimationIterClass *anim_iter_class =
228 GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
230 iter_parent_class = g_type_class_peek_parent (klass);
232 object_class->finalize = gdk_pixbuf_gdip_anim_iter_finalize;
234 anim_iter_class->get_delay_time = gdk_pixbuf_gdip_anim_iter_get_delay_time;
235 anim_iter_class->get_pixbuf = gdk_pixbuf_gdip_anim_iter_get_pixbuf;
236 anim_iter_class->on_currently_loading_frame = gdk_pixbuf_gdip_anim_iter_on_currently_loading_frame;
237 anim_iter_class->advance = gdk_pixbuf_gdip_anim_iter_advance;
241 gdk_pixbuf_gdip_anim_iter_finalize (GObject *object)
243 GdkPixbufGdipAnimIter *iter = GDK_PIXBUF_GDIP_ANIM_ITER (object);
247 g_object_unref (iter->gdip_anim);
249 G_OBJECT_CLASS (iter_parent_class)->finalize (object);
253 gdk_pixbuf_gdip_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
254 const GTimeVal *current_time)
256 GdkPixbufGdipAnimIter *iter;
262 iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
264 iter->current_time = *current_time;
266 /* We use milliseconds for all times */
268 (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
269 iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
272 /* Try to compensate; probably the system clock
275 iter->start_time = iter->current_time;
279 g_assert (iter->gdip_anim->total_time > 0);
281 /* See how many times we've already played the full animation,
282 * and subtract time for that.
285 if (iter->gdip_anim->loading)
288 /* If current_frame is NULL at this point, we have loaded the
289 * animation from a source which fell behind the speed of the
290 * display. We remember how much slower the first loop was due
291 * to this and correct the position calculation in order to not
292 * jump in the middle of the second loop.
294 if (iter->current_frame == NULL)
295 iter->first_loop_slowness = MAX(0, elapsed - iter->gdip_anim->total_time);
297 loop = (elapsed - iter->first_loop_slowness) / iter->gdip_anim->total_time;
298 elapsed = (elapsed - iter->first_loop_slowness) % iter->gdip_anim->total_time;
301 iter->position = elapsed;
303 /* Now move to the proper frame */
304 if (iter->gdip_anim->loop == 0 || loop < iter->gdip_anim->loop)
305 tmp = iter->gdip_anim->frames;
308 while (tmp != NULL) {
309 GdkPixbufFrame *frame = tmp->data;
311 if (iter->position >= frame->elapsed &&
312 iter->position < (frame->elapsed + frame->delay_time))
318 old = iter->current_frame;
320 iter->current_frame = tmp;
322 return iter->current_frame != old;
326 gdk_pixbuf_gdip_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
328 GdkPixbufFrame *frame;
329 GdkPixbufGdipAnimIter *iter;
331 iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
333 if (iter->current_frame) {
334 frame = iter->current_frame->data;
337 g_print ("frame start: %d pos: %d frame len: %d frame remaining: %d\n",
341 frame->delay_time - (iter->position - frame->elapsed));
344 return frame->delay_time - (iter->position - frame->elapsed);
346 return -1; /* show last frame forever */
350 gdk_pixbuf_gdip_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
352 GdkPixbufGdipAnimIter *iter;
353 GdkPixbufFrame *frame;
355 iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
357 frame = iter->current_frame ? iter->current_frame->data : g_list_last (iter->gdip_anim->frames)->data;
361 g_print ("current frame %d dispose mode %d %d x %d\n",
362 g_list_index (iter->gdip_anim->frames,
365 gdk_pixbuf_get_width (frame->pixbuf),
366 gdk_pixbuf_get_height (frame->pixbuf));
372 return frame->pixbuf;
376 gdk_pixbuf_gdip_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
378 GdkPixbufGdipAnimIter *iter;
380 iter = GDK_PIXBUF_GDIP_ANIM_ITER (anim_iter);
382 return iter->current_frame == NULL || iter->current_frame->next == NULL;