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, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "config.h"
23#include <errno.h>
24#include "io-ani-animation.h"
25
26static void gdk_pixbuf_ani_anim_finalize (GObject *object);
27
28static gboolean gdk_pixbuf_ani_anim_is_static_image (GdkPixbufAnimation *animation);
29static GdkPixbuf* gdk_pixbuf_ani_anim_get_static_image (GdkPixbufAnimation *animation);
30static void gdk_pixbuf_ani_anim_get_size (GdkPixbufAnimation *anim,
31 int *width,
32 int *height);
33G_GNUC_BEGIN_IGNORE_DEPRECATIONS
34static GdkPixbufAnimationIter* gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
35 const GTimeVal *start_time);
36G_GNUC_END_IGNORE_DEPRECATIONS
37
38
39
40G_DEFINE_TYPE (GdkPixbufAniAnim, gdk_pixbuf_ani_anim, GDK_TYPE_PIXBUF_ANIMATION)
41
42static void
43gdk_pixbuf_ani_anim_init (GdkPixbufAniAnim *anim)
44{
45}
46
47static void
48gdk_pixbuf_ani_anim_class_init (GdkPixbufAniAnimClass *klass)
49{
50 GObjectClass *object_class = G_OBJECT_CLASS (klass);
51 GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
52
53 object_class->finalize = gdk_pixbuf_ani_anim_finalize;
54
55 anim_class->is_static_image = gdk_pixbuf_ani_anim_is_static_image;
56 anim_class->get_static_image = gdk_pixbuf_ani_anim_get_static_image;
57 anim_class->get_size = gdk_pixbuf_ani_anim_get_size;
58 anim_class->get_iter = gdk_pixbuf_ani_anim_get_iter;
59}
60
61static void
62gdk_pixbuf_ani_anim_finalize (GObject *object)
63{
64 GdkPixbufAniAnim *ani_anim = GDK_PIXBUF_ANI_ANIM (object);
65 gint i;
66
67 for (i = 0; i < ani_anim->n_pixbufs; i++) {
68 if (ani_anim->pixbufs[i])
69 g_object_unref (object: ani_anim->pixbufs[i]);
70 }
71 g_free (mem: ani_anim->pixbufs);
72 g_free (mem: ani_anim->sequence);
73 g_free (mem: ani_anim->delay);
74
75 G_OBJECT_CLASS (gdk_pixbuf_ani_anim_parent_class)->finalize (object);
76}
77
78static gboolean
79gdk_pixbuf_ani_anim_is_static_image (GdkPixbufAnimation *animation)
80{
81 GdkPixbufAniAnim *ani_anim;
82
83 ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
84
85 return ani_anim->n_frames == 1;
86}
87
88static GdkPixbuf*
89gdk_pixbuf_ani_anim_get_static_image (GdkPixbufAnimation *animation)
90{
91 GdkPixbufAniAnim *ani_anim;
92
93 ani_anim = GDK_PIXBUF_ANI_ANIM (animation);
94
95 if (ani_anim->pixbufs == NULL)
96 return NULL;
97 else
98 return ani_anim->pixbufs[0];
99}
100
101static void
102gdk_pixbuf_ani_anim_get_size (GdkPixbufAnimation *anim,
103 int *width,
104 int *height)
105{
106 GdkPixbufAniAnim *ani_anim;
107
108 ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
109
110 if (width)
111 *width = ani_anim->width;
112
113 if (height)
114 *height = ani_anim->height;
115}
116
117
118static void
119iter_restart (GdkPixbufAniAnimIter *iter)
120{
121 iter->current_frame = 0;
122 iter->position = 0;
123 iter->elapsed = 0;
124}
125
126G_GNUC_BEGIN_IGNORE_DEPRECATIONS
127static GdkPixbufAnimationIter*
128gdk_pixbuf_ani_anim_get_iter (GdkPixbufAnimation *anim,
129 const GTimeVal *start_time)
130{
131 GdkPixbufAniAnimIter *iter;
132
133 iter = g_object_new (GDK_TYPE_PIXBUF_ANI_ANIM_ITER, NULL);
134
135 iter->ani_anim = GDK_PIXBUF_ANI_ANIM (anim);
136
137 g_object_ref (iter->ani_anim);
138
139 iter_restart (iter);
140
141 iter->start_time = *start_time;
142 iter->current_time = *start_time;
143
144 return GDK_PIXBUF_ANIMATION_ITER (iter);
145}
146G_GNUC_END_IGNORE_DEPRECATIONS
147
148
149
150static void gdk_pixbuf_ani_anim_iter_finalize (GObject *object);
151
152static int gdk_pixbuf_ani_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
153static GdkPixbuf* gdk_pixbuf_ani_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
154static gboolean gdk_pixbuf_ani_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
155G_GNUC_BEGIN_IGNORE_DEPRECATIONS
156static gboolean gdk_pixbuf_ani_anim_iter_advance (GdkPixbufAnimationIter *iter,
157 const GTimeVal *current_time);
158G_GNUC_END_IGNORE_DEPRECATIONS
159
160
161
162G_DEFINE_TYPE (GdkPixbufAniAnimIter, gdk_pixbuf_ani_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER);
163
164static void
165gdk_pixbuf_ani_anim_iter_init (GdkPixbufAniAnimIter *anim)
166{
167}
168
169static void
170gdk_pixbuf_ani_anim_iter_class_init (GdkPixbufAniAnimIterClass *klass)
171{
172 GObjectClass *object_class = G_OBJECT_CLASS (klass);
173 GdkPixbufAnimationIterClass *anim_iter_class =
174 GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
175
176 object_class->finalize = gdk_pixbuf_ani_anim_iter_finalize;
177
178 anim_iter_class->get_delay_time = gdk_pixbuf_ani_anim_iter_get_delay_time;
179 anim_iter_class->get_pixbuf = gdk_pixbuf_ani_anim_iter_get_pixbuf;
180 anim_iter_class->on_currently_loading_frame = gdk_pixbuf_ani_anim_iter_on_currently_loading_frame;
181 anim_iter_class->advance = gdk_pixbuf_ani_anim_iter_advance;
182}
183
184static void
185gdk_pixbuf_ani_anim_iter_finalize (GObject *object)
186{
187 GdkPixbufAniAnimIter *iter = GDK_PIXBUF_ANI_ANIM_ITER (object);
188
189 g_object_unref (object: iter->ani_anim);
190
191 G_OBJECT_CLASS (gdk_pixbuf_ani_anim_iter_parent_class)->finalize (object);
192}
193
194G_GNUC_BEGIN_IGNORE_DEPRECATIONS
195static gboolean
196gdk_pixbuf_ani_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
197 const GTimeVal *current_time)
198{
199 GdkPixbufAniAnimIter *iter;
200 gint elapsed;
201 gint tmp;
202 gint old;
203
204 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
205
206 iter->current_time = *current_time;
207
208 /* We use milliseconds for all times */
209 elapsed =
210 (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
211 iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
212
213 if (elapsed < 0) {
214 /* Try to compensate; probably the system clock
215 * was set backwards
216 */
217 iter->start_time = iter->current_time;
218 elapsed = 0;
219 }
220
221 g_assert (iter->ani_anim->total_time > 0);
222
223 /* See how many times we've already played the full animation,
224 * and subtract time for that.
225 */
226 elapsed = elapsed % iter->ani_anim->total_time;
227
228 iter->position = elapsed;
229
230 /* Now move to the proper frame */
231
232 iter->elapsed = 0;
233 for (tmp = 0; tmp < iter->ani_anim->n_frames; tmp++) {
234 if (iter->position >= iter->elapsed &&
235 iter->position < (iter->elapsed + iter->ani_anim->delay[tmp]))
236 break;
237 iter->elapsed += iter->ani_anim->delay[tmp];
238 }
239
240 old = iter->current_frame;
241
242 iter->current_frame = tmp;
243
244 return iter->current_frame != old;
245}
246G_GNUC_END_IGNORE_DEPRECATIONS
247
248int
249gdk_pixbuf_ani_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
250{
251 GdkPixbufAniAnimIter *iter;
252
253 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
254
255 return iter->ani_anim->delay[iter->current_frame] - (iter->position - iter->elapsed);
256}
257
258GdkPixbuf*
259gdk_pixbuf_ani_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
260{
261 GdkPixbufAniAnimIter *iter;
262 gint frame;
263
264 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
265
266 frame = iter->ani_anim->sequence[iter->current_frame];
267
268 /* this is necessary if the animation is displayed while loading */
269 while (frame > 0 && !iter->ani_anim->pixbufs[frame])
270 frame--;
271
272 return iter->ani_anim->pixbufs[frame];
273}
274
275static gboolean
276gdk_pixbuf_ani_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
277{
278 GdkPixbufAniAnimIter *iter;
279 gint frame;
280
281 iter = GDK_PIXBUF_ANI_ANIM_ITER (anim_iter);
282
283 if (iter->current_frame >= iter->ani_anim->n_frames - 1)
284 return TRUE;
285
286 frame = iter->ani_anim->sequence[iter->current_frame + 1];
287
288 if (!iter->ani_anim->pixbufs[frame])
289 return TRUE;
290
291 return FALSE;
292}
293
294
295
296
297
298
299
300
301
302
303

source code of gtk/subprojects/gdk-pixbuf/gdk-pixbuf/io-ani-animation.c