]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-ani-animation.c
Include "config.h" instead of <config.h> Command used: find -name
[~andy/gtk] / gdk-pixbuf / io-ani-animation.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /* GdkPixbuf library - ani support
3  *
4  * Copyright (C) 2002 The Free Software Foundation
5  *
6  * Author: Matthias Clasen <maclas@gmx.de>
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #include "config.h"
25 #include <errno.h>
26 #include "gdk-pixbuf-io.h"
27 #include "gdk-pixbuf-private.h"
28 #include "io-ani-animation.h"
29
30 static void gdk_pixbuf_ani_anim_class_init (GdkPixbufAniAnimClass *klass);
31 static void gdk_pixbuf_ani_anim_finalize   (GObject        *object);
32
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,
36                                                              int                *width,
37                                                              int                *height);
38 static GdkPixbufAnimationIter* gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
39                                                              const GTimeVal     *start_time);
40
41
42 \f
43
44 static gpointer parent_class;
45
46 GType
47 gdk_pixbuf_ani_anim_get_type (void)
48 {
49         static GType object_type = 0;
50
51         if (!object_type) {
52                 static const GTypeInfo object_info = {
53                         sizeof (GdkPixbufAniAnimClass),
54                         (GBaseInitFunc) NULL,
55                         (GBaseFinalizeFunc) NULL,
56                         (GClassInitFunc) gdk_pixbuf_ani_anim_class_init,
57                         NULL,           /* class_finalize */
58                         NULL,           /* class_data */
59                         sizeof (GdkPixbufAniAnim),
60                         0,              /* n_preallocs */
61                         (GInstanceInitFunc) NULL,
62                 };
63                 
64                 object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
65                                                       g_intern_static_string ("GdkPixbufAniAnim"),
66                                                       &object_info, 0);
67         }
68         
69         return object_type;
70 }
71
72 static void
73 gdk_pixbuf_ani_anim_class_init (GdkPixbufAniAnimClass *klass)
74 {
75         GObjectClass *object_class = G_OBJECT_CLASS (klass);
76         GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
77         
78         parent_class = g_type_class_peek_parent (klass);
79         
80         object_class->finalize = gdk_pixbuf_ani_anim_finalize;
81
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;
86 }
87
88 static void
89 gdk_pixbuf_ani_anim_finalize (GObject *object)
90 {
91         GdkPixbufAniAnim *ani_anim = GDK_PIXBUF_ANI_ANIM (object);
92         gint i;
93
94         for (i = 0; i < ani_anim->n_pixbufs; i++) {
95                 if (ani_anim->pixbufs[i])
96                         g_object_unref (ani_anim->pixbufs[i]);
97         }
98         g_free (ani_anim->pixbufs);
99         g_free (ani_anim->sequence);
100         g_free (ani_anim->delay);
101         
102         G_OBJECT_CLASS (parent_class)->finalize (object);
103 }
104
105 static gboolean
106 gdk_pixbuf_ani_anim_is_static_image  (GdkPixbufAnimation *animation)
107 {
108         GdkPixbufAniAnim *ani_anim;
109
110         ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
111
112         return ani_anim->n_frames == 1;
113 }
114
115 static GdkPixbuf*
116 gdk_pixbuf_ani_anim_get_static_image (GdkPixbufAnimation *animation)
117 {
118         GdkPixbufAniAnim *ani_anim;
119
120         ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
121
122         if (ani_anim->pixbufs == NULL)
123                 return NULL;
124         else
125                 return ani_anim->pixbufs[0];        
126 }
127
128 static void
129 gdk_pixbuf_ani_anim_get_size (GdkPixbufAnimation *anim,
130                               int                *width,
131                               int                *height)
132 {
133         GdkPixbufAniAnim *ani_anim;
134
135         ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
136
137         if (width)
138                 *width = ani_anim->width;
139
140         if (height)
141                 *height = ani_anim->height;
142 }
143
144
145 static void
146 iter_restart (GdkPixbufAniAnimIter *iter)
147 {
148         iter->current_frame = 0;        
149         iter->position = 0;
150         iter->elapsed = 0;
151 }
152
153 static GdkPixbufAnimationIter*
154 gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
155                               const GTimeVal     *start_time)
156 {
157         GdkPixbufAniAnimIter *iter;
158
159         iter = g_object_new (GDK_TYPE_PIXBUF_ANI_ANIM_ITER, NULL);
160
161         iter->ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
162
163         g_object_ref (iter->ani_anim);
164         
165         iter_restart (iter);
166
167         iter->start_time = *start_time;
168         iter->current_time = *start_time;
169         
170         return GDK_PIXBUF_ANIMATION_ITER (iter);
171 }
172
173 \f
174
175 static void gdk_pixbuf_ani_anim_iter_class_init (GdkPixbufAniAnimIterClass *klass);
176 static void gdk_pixbuf_ani_anim_iter_finalize   (GObject                   *object);
177
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);
183
184 \f
185
186 static gpointer iter_parent_class;
187
188 GType
189 gdk_pixbuf_ani_anim_iter_get_type (void)
190 {
191         static GType object_type = 0;
192
193         if (!object_type) {
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),
202                         0,              /* n_preallocs */
203                         (GInstanceInitFunc) NULL,
204                 };
205                 
206                 object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
207                                                       g_intern_static_string ("GdkPixbufAniAnimIter"),
208                                                       &object_info, 0);
209         }
210         
211         return object_type;
212 }
213
214 static void
215 gdk_pixbuf_ani_anim_iter_class_init (GdkPixbufAniAnimIterClass *klass)
216 {
217         GObjectClass *object_class = G_OBJECT_CLASS (klass);
218         GdkPixbufAnimationIterClass *anim_iter_class =
219                 GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
220         
221         iter_parent_class = g_type_class_peek_parent (klass);
222         
223         object_class->finalize = gdk_pixbuf_ani_anim_iter_finalize;
224
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;
229 }
230
231 static void
232 gdk_pixbuf_ani_anim_iter_finalize (GObject *object)
233 {
234         GdkPixbufAniAnimIter *iter = GDK_PIXBUF_ANI_ANIM_ITER (object);
235
236         g_object_unref (iter->ani_anim);
237         
238         G_OBJECT_CLASS (iter_parent_class)->finalize (object);
239 }
240
241 static gboolean
242 gdk_pixbuf_ani_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
243                                   const GTimeVal         *current_time)
244 {
245         GdkPixbufAniAnimIter *iter;
246         gint elapsed;
247         gint tmp;
248         gint old;
249
250         iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
251         
252         iter->current_time = *current_time;
253
254         /* We use milliseconds for all times */
255         elapsed =
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;
258
259         if (elapsed < 0) {
260                 /* Try to compensate; probably the system clock
261                  * was set backwards
262                  */
263                 iter->start_time = iter->current_time;
264                 elapsed = 0;
265         }
266
267         g_assert (iter->ani_anim->total_time > 0);
268         
269         /* See how many times we've already played the full animation,
270          * and subtract time for that.
271          */
272         elapsed = elapsed % iter->ani_anim->total_time;
273
274         iter->position = elapsed;
275         
276         /* Now move to the proper frame */
277         
278         iter->elapsed = 0;
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]))
282                         break;
283                 iter->elapsed += iter->ani_anim->delay[tmp];
284         }
285
286         old = iter->current_frame;
287         
288         iter->current_frame = tmp;
289
290         return iter->current_frame != old;
291 }
292
293 int
294 gdk_pixbuf_ani_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
295 {
296         GdkPixbufAniAnimIter *iter;
297   
298         iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
299
300         return iter->ani_anim->delay[iter->current_frame] - (iter->position - iter->elapsed);
301 }
302
303 GdkPixbuf*
304 gdk_pixbuf_ani_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
305 {
306         GdkPixbufAniAnimIter *iter;
307         gint frame;
308
309         iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
310
311         frame = iter->ani_anim->sequence[iter->current_frame];
312
313         /* this is necessary if the animation is displayed while loading */
314         while (frame > 0 && !iter->ani_anim->pixbufs[frame])
315                 frame--;
316
317         return iter->ani_anim->pixbufs[frame];
318 }
319
320 static gboolean
321 gdk_pixbuf_ani_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
322 {
323         GdkPixbufAniAnimIter *iter;
324         gint frame;
325
326         iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
327       
328         if (iter->current_frame >= iter->ani_anim->n_frames - 1)
329                 return TRUE;
330         
331         frame = iter->ani_anim->sequence[iter->current_frame + 1];
332
333         if (!iter->ani_anim->pixbufs[frame]) 
334                 return TRUE;
335
336         return FALSE;
337 }
338
339
340
341
342
343
344
345
346
347