/src/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-animation.c
Line | Count | Source |
1 | | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ |
2 | | /* GdkPixbuf library - Simple animation support |
3 | | * |
4 | | * Copyright (C) 1999 The Free Software Foundation |
5 | | * |
6 | | * Authors: Jonathan Blandford <jrb@redhat.com> |
7 | | * Havoc Pennington <hp@redhat.com> |
8 | | * |
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. |
13 | | * |
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. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | #define GLIB_DISABLE_DEPRECATION_WARNINGS |
25 | | #include <errno.h> |
26 | | #include "gdk-pixbuf-private.h" |
27 | | #include "gdk-pixbuf-animation.h" |
28 | | #include "gdk-pixbuf-loader.h" |
29 | | |
30 | | #include <glib/gstdio.h> |
31 | | |
32 | | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
33 | | |
34 | | /** |
35 | | * GdkPixbufAnimation: |
36 | | * |
37 | | * An opaque object representing an animation. |
38 | | * |
39 | | * The GdkPixBuf library provides a simple mechanism to load and |
40 | | * represent animations. An animation is conceptually a series of |
41 | | * frames to be displayed over time. |
42 | | * |
43 | | * The animation may not be represented as a series of frames |
44 | | * internally; for example, it may be stored as a sprite and |
45 | | * instructions for moving the sprite around a background. |
46 | | * |
47 | | * To display an animation you don't need to understand its |
48 | | * representation, however; you just ask `GdkPixbuf` what should |
49 | | * be displayed at a given point in time. |
50 | | * |
51 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
52 | | */ |
53 | | |
54 | | /** |
55 | | * GdkPixbufAnimationIter: |
56 | | * |
57 | | * An opaque object representing an iterator which points to a |
58 | | * certain position in an animation. |
59 | | * |
60 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
61 | | */ |
62 | | |
63 | | typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim; |
64 | | typedef struct _GdkPixbufNonAnimClass GdkPixbufNonAnimClass; |
65 | | |
66 | | |
67 | | #define GDK_PIXBUF_NON_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass)) |
68 | | #define GDK_IS_PIXBUF_NON_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM)) |
69 | | #define GDK_PIXBUF_NON_ANIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass)) |
70 | | |
71 | | /* Private part of the GdkPixbufNonAnim structure */ |
72 | | struct _GdkPixbufNonAnim { |
73 | | GdkPixbufAnimation parent_instance; |
74 | | |
75 | | GdkPixbuf *pixbuf; |
76 | | }; |
77 | | |
78 | | struct _GdkPixbufNonAnimClass { |
79 | | GdkPixbufAnimationClass parent_class; |
80 | | }; |
81 | | |
82 | | |
83 | | typedef struct _GdkPixbufNonAnimIter GdkPixbufNonAnimIter; |
84 | | typedef struct _GdkPixbufNonAnimIterClass GdkPixbufNonAnimIterClass; |
85 | | |
86 | | |
87 | 0 | #define GDK_TYPE_PIXBUF_NON_ANIM_ITER (gdk_pixbuf_non_anim_iter_get_type ()) |
88 | 0 | #define GDK_PIXBUF_NON_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIter)) |
89 | | #define GDK_IS_PIXBUF_NON_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER)) |
90 | | |
91 | | #define GDK_PIXBUF_NON_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass)) |
92 | | #define GDK_IS_PIXBUF_NON_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER)) |
93 | | #define GDK_PIXBUF_NON_ANIM_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass)) |
94 | | |
95 | | struct _GdkPixbufNonAnimIter { |
96 | | GdkPixbufAnimationIter parent_instance; |
97 | | |
98 | | GdkPixbufNonAnim *non_anim; |
99 | | }; |
100 | | |
101 | | struct _GdkPixbufNonAnimIterClass { |
102 | | GdkPixbufAnimationIterClass parent_class; |
103 | | |
104 | | }; |
105 | | |
106 | | static GType gdk_pixbuf_non_anim_iter_get_type (void) G_GNUC_CONST; |
107 | | |
108 | 0 | G_DEFINE_TYPE (GdkPixbufAnimation, gdk_pixbuf_animation, G_TYPE_OBJECT); |
109 | 0 |
|
110 | 0 | static void |
111 | 0 | gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass) |
112 | 0 | { |
113 | 0 | } |
114 | | |
115 | | static void |
116 | | gdk_pixbuf_animation_init (GdkPixbufAnimation *animation) |
117 | 0 | { |
118 | 0 | } |
119 | | |
120 | | static void |
121 | | noop_size_notify (gint *width, |
122 | | gint *height, |
123 | | gpointer data) |
124 | 0 | { |
125 | 0 | } |
126 | | |
127 | | static void |
128 | | prepared_notify (GdkPixbuf *pixbuf, |
129 | | GdkPixbufAnimation *anim, |
130 | | gpointer user_data) |
131 | 0 | { |
132 | 0 | if (anim != NULL) |
133 | 0 | g_object_ref (anim); |
134 | 0 | else |
135 | 0 | anim = gdk_pixbuf_non_anim_new (pixbuf); |
136 | |
|
137 | 0 | *((GdkPixbufAnimation **)user_data) = anim; |
138 | 0 | } |
139 | | |
140 | | static void |
141 | | noop_updated_notify (GdkPixbuf *pixbuf, |
142 | | int x, |
143 | | int y, |
144 | | int width, |
145 | | int height, |
146 | | gpointer user_data) |
147 | 0 | { |
148 | 0 | } |
149 | | |
150 | | /** |
151 | | * gdk_pixbuf_animation_new_from_file: |
152 | | * @filename: (type filename): Name of file to load, in the GLib file |
153 | | * name encoding |
154 | | * @error: return location for error |
155 | | * |
156 | | * Creates a new animation by loading it from a file. |
157 | | * |
158 | | * The file format is detected automatically. |
159 | | * |
160 | | * If the file's format does not support multi-frame images, then an animation |
161 | | * with a single frame will be created. |
162 | | * |
163 | | * Possible errors are in the `GDK_PIXBUF_ERROR` and `G_FILE_ERROR` domains. |
164 | | * |
165 | | * Return value: (transfer full) (nullable): A newly-created animation |
166 | | * |
167 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
168 | | */ |
169 | | GdkPixbufAnimation * |
170 | | gdk_pixbuf_animation_new_from_file (const gchar *filename, |
171 | | GError **error) |
172 | 12.8k | { |
173 | 12.8k | GdkPixbufAnimation *animation; |
174 | 12.8k | int size; |
175 | 12.8k | FILE *f; |
176 | 12.8k | guchar buffer[SNIFF_BUFFER_SIZE]; |
177 | 12.8k | GdkPixbufModule *image_module; |
178 | 12.8k | gchar *display_name; |
179 | | |
180 | 12.8k | g_return_val_if_fail (filename != NULL, NULL); |
181 | 12.8k | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
182 | | |
183 | 12.8k | display_name = g_filename_display_name (filename); |
184 | 12.8k | f = g_fopen (filename, "rb"); |
185 | 12.8k | if (!f) { |
186 | 0 | gint save_errno = errno; |
187 | 0 | g_set_error (error, |
188 | 0 | G_FILE_ERROR, |
189 | 0 | g_file_error_from_errno (save_errno), |
190 | 0 | _("Failed to open file “%s”: %s"), |
191 | 0 | display_name, |
192 | 0 | g_strerror (save_errno)); |
193 | 0 | g_free (display_name); |
194 | 0 | return NULL; |
195 | 0 | } |
196 | | |
197 | 12.8k | size = fread (&buffer, 1, sizeof (buffer), f); |
198 | | |
199 | 12.8k | if (size == 0) { |
200 | 0 | g_set_error (error, |
201 | 0 | GDK_PIXBUF_ERROR, |
202 | 0 | GDK_PIXBUF_ERROR_CORRUPT_IMAGE, |
203 | 0 | _("Image file “%s” contains no data"), |
204 | 0 | display_name); |
205 | 0 | g_free (display_name); |
206 | 0 | fclose (f); |
207 | 0 | return NULL; |
208 | 0 | } |
209 | | |
210 | 12.8k | image_module = _gdk_pixbuf_get_module (buffer, size, filename, error); |
211 | 12.8k | if (!image_module) { |
212 | 12.8k | g_free (display_name); |
213 | 12.8k | fclose (f); |
214 | 12.8k | return NULL; |
215 | 12.8k | } |
216 | | |
217 | 0 | if (image_module->module == NULL) |
218 | 0 | if (!_gdk_pixbuf_load_module (image_module, error)) { |
219 | 0 | g_free (display_name); |
220 | 0 | fclose (f); |
221 | 0 | return NULL; |
222 | 0 | } |
223 | | |
224 | 0 | if (image_module->load_animation != NULL) { |
225 | 0 | fseek (f, 0, SEEK_SET); |
226 | 0 | animation = (* image_module->load_animation) (f, error); |
227 | |
|
228 | 0 | if (animation == NULL && error != NULL && *error == NULL) { |
229 | | /* I don't trust these crufty longjmp()'ing |
230 | | * image libs to maintain proper error |
231 | | * invariants, and I don't want user code to |
232 | | * segfault as a result. We need to maintain |
233 | | * the invariant that error gets set if NULL |
234 | | * is returned. |
235 | | */ |
236 | 0 | g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", |
237 | 0 | image_module->module_name); |
238 | 0 | g_set_error (error, |
239 | 0 | GDK_PIXBUF_ERROR, |
240 | 0 | GDK_PIXBUF_ERROR_FAILED, |
241 | 0 | _("Failed to load animation “%s”: reason not known, probably a corrupt animation file"), |
242 | 0 | display_name); |
243 | 0 | } |
244 | |
|
245 | 0 | fclose (f); |
246 | 0 | } else if (image_module->begin_load != NULL) { |
247 | 0 | guchar buffer[4096]; |
248 | 0 | size_t length; |
249 | 0 | gpointer context; |
250 | 0 | gboolean success; |
251 | |
|
252 | 0 | success = FALSE; |
253 | 0 | animation = NULL; |
254 | 0 | fseek (f, 0, SEEK_SET); |
255 | |
|
256 | 0 | context = image_module->begin_load (noop_size_notify, prepared_notify, noop_updated_notify, &animation, error); |
257 | 0 | if (!context) |
258 | 0 | goto fail_begin_load; |
259 | | |
260 | 0 | while (!feof (f) && !ferror (f)) { |
261 | 0 | length = fread (buffer, 1, sizeof (buffer), f); |
262 | 0 | if (length > 0) { |
263 | 0 | if (!image_module->load_increment (context, buffer, length, error)) { |
264 | 0 | error = NULL; |
265 | 0 | goto fail_load_increment; |
266 | 0 | } |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | 0 | success = TRUE; |
271 | |
|
272 | 0 | fail_load_increment: |
273 | 0 | if (!image_module->stop_load (context, error)) |
274 | 0 | success = FALSE; |
275 | |
|
276 | 0 | fail_begin_load: |
277 | 0 | fclose (f); |
278 | |
|
279 | 0 | if (success) { |
280 | | /* If there was no error, there must be an animation that was successfully loaded */ |
281 | 0 | g_assert (animation); |
282 | 0 | } else { |
283 | 0 | if (animation) { |
284 | 0 | g_object_unref (animation); |
285 | 0 | animation = NULL; |
286 | 0 | } |
287 | 0 | } |
288 | 0 | } else { |
289 | 0 | GdkPixbuf *pixbuf; |
290 | | |
291 | | /* Keep this logic in sync with gdk_pixbuf_new_from_file() */ |
292 | |
|
293 | 0 | fseek (f, 0, SEEK_SET); |
294 | 0 | pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error); |
295 | 0 | fclose (f); |
296 | |
|
297 | 0 | if (pixbuf == NULL && error != NULL && *error == NULL) { |
298 | | /* I don't trust these crufty longjmp()'ing image libs |
299 | | * to maintain proper error invariants, and I don't |
300 | | * want user code to segfault as a result. We need to maintain |
301 | | * the invariant that error gets set if NULL is returned. |
302 | | */ |
303 | |
|
304 | 0 | g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.", |
305 | 0 | image_module->module_name); |
306 | 0 | g_set_error (error, |
307 | 0 | GDK_PIXBUF_ERROR, |
308 | 0 | GDK_PIXBUF_ERROR_FAILED, |
309 | 0 | _("Failed to load image “%s”: reason not known, probably a corrupt image file"), |
310 | 0 | display_name); |
311 | 0 | } |
312 | |
|
313 | 0 | if (pixbuf == NULL) { |
314 | 0 | g_free (display_name); |
315 | 0 | animation = NULL; |
316 | 0 | goto out; |
317 | 0 | } |
318 | | |
319 | 0 | animation = gdk_pixbuf_non_anim_new (pixbuf); |
320 | |
|
321 | 0 | g_object_unref (pixbuf); |
322 | 0 | } |
323 | | |
324 | 0 | g_free (display_name); |
325 | |
|
326 | 0 | out: |
327 | 0 | return animation; |
328 | 0 | } |
329 | | |
330 | | #ifdef G_OS_WIN32 |
331 | | /** |
332 | | * gdk_pixbuf_animation_new_from_file_utf8: |
333 | | * @filename: (type filename): Name of file to load, in the GLib file name encoding |
334 | | * @error: return location for error |
335 | | * |
336 | | * Same as gdk_pixbuf_animation_new_from_file() |
337 | | * |
338 | | * Return value: A newly-created animation with a reference count of 1, or `NULL` |
339 | | * if any of several error conditions ocurred: the file could not be opened, |
340 | | * there was no loader for the file's format, there was not enough memory to |
341 | | * allocate the image buffer, or the image file contained invalid data. |
342 | | * |
343 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
344 | | */ |
345 | | GdkPixbufAnimation * |
346 | | gdk_pixbuf_animation_new_from_file_utf8 (const gchar *filename, |
347 | | GError **error) |
348 | | { |
349 | | return gdk_pixbuf_animation_new_from_file (filename, error); |
350 | | } |
351 | | #endif |
352 | | |
353 | | /** |
354 | | * gdk_pixbuf_animation_new_from_stream: |
355 | | * @stream: a `GInputStream` to load the pixbuf from |
356 | | * @cancellable: (nullable): optional `GCancellable` object |
357 | | * @error: Return location for an error |
358 | | * |
359 | | * Creates a new animation by loading it from an input stream. |
360 | | * |
361 | | * The file format is detected automatically. |
362 | | * |
363 | | * If `NULL` is returned, then @error will be set. |
364 | | * |
365 | | * The @cancellable can be used to abort the operation from another thread. |
366 | | * If the operation was cancelled, the error `G_IO_ERROR_CANCELLED` will be |
367 | | * returned. Other possible errors are in the `GDK_PIXBUF_ERROR` and |
368 | | * `G_IO_ERROR` domains. |
369 | | * |
370 | | * The stream is not closed. |
371 | | * |
372 | | * Return value: (transfer full) (nullable): A newly-created animation |
373 | | * |
374 | | * Since: 2.28 |
375 | | * |
376 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
377 | | */ |
378 | | GdkPixbufAnimation * |
379 | | gdk_pixbuf_animation_new_from_stream (GInputStream *stream, |
380 | | GCancellable *cancellable, |
381 | | GError **error) |
382 | 0 | { |
383 | 0 | GdkPixbufAnimation *animation; |
384 | 0 | GdkPixbufLoader *loader; |
385 | 0 | gssize n_read; |
386 | 0 | guchar buffer[LOAD_BUFFER_SIZE]; |
387 | 0 | gboolean res; |
388 | |
|
389 | 0 | g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL); |
390 | 0 | g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); |
391 | 0 | g_return_val_if_fail (error == NULL || *error == NULL, NULL); |
392 | | |
393 | 0 | loader = gdk_pixbuf_loader_new (); |
394 | |
|
395 | 0 | res = TRUE; |
396 | 0 | while (1) { |
397 | 0 | n_read = g_input_stream_read (stream, buffer, sizeof (buffer), cancellable, error); |
398 | 0 | if (n_read < 0) { |
399 | 0 | res = FALSE; |
400 | 0 | error = NULL; /* Ignore further errors */ |
401 | 0 | break; |
402 | 0 | } |
403 | | |
404 | 0 | if (n_read == 0) |
405 | 0 | break; |
406 | | |
407 | 0 | if (!gdk_pixbuf_loader_write (loader, buffer, n_read, error)) { |
408 | 0 | res = FALSE; |
409 | 0 | error = NULL; |
410 | 0 | break; |
411 | 0 | } |
412 | 0 | } |
413 | |
|
414 | 0 | if (!gdk_pixbuf_loader_close (loader, error)) { |
415 | 0 | res = FALSE; |
416 | 0 | error = NULL; |
417 | 0 | } |
418 | |
|
419 | 0 | if (res) { |
420 | 0 | animation = gdk_pixbuf_loader_get_animation (loader); |
421 | 0 | if (animation) |
422 | 0 | g_object_ref (animation); |
423 | 0 | } else { |
424 | 0 | animation = NULL; |
425 | 0 | } |
426 | |
|
427 | 0 | g_object_unref (loader); |
428 | |
|
429 | 0 | return animation; |
430 | 0 | } |
431 | | |
432 | | static void |
433 | | animation_new_from_stream_thread (GTask *task, |
434 | | gpointer source_object, |
435 | | gpointer task_data, |
436 | | GCancellable *cancellable) |
437 | 0 | { |
438 | 0 | GInputStream *stream = G_INPUT_STREAM (source_object); |
439 | 0 | GdkPixbufAnimation *animation; |
440 | 0 | GError *error = NULL; |
441 | |
|
442 | 0 | animation = gdk_pixbuf_animation_new_from_stream (stream, cancellable, &error); |
443 | | |
444 | | /* Set the new pixbuf as the result, or error out */ |
445 | 0 | if (animation == NULL) { |
446 | 0 | g_task_return_error (task, error); |
447 | 0 | } else { |
448 | 0 | g_task_return_pointer (task, animation, g_object_unref); |
449 | 0 | } |
450 | 0 | } |
451 | | |
452 | | /** |
453 | | * gdk_pixbuf_animation_new_from_stream_async: |
454 | | * @stream: a #GInputStream from which to load the animation |
455 | | * @cancellable: (nullable): optional #GCancellable object |
456 | | * @callback: a `GAsyncReadyCallback` to call when the pixbuf is loaded |
457 | | * @user_data: the data to pass to the callback function |
458 | | * |
459 | | * Creates a new animation by asynchronously loading an image from an input stream. |
460 | | * |
461 | | * For more details see gdk_pixbuf_new_from_stream(), which is the synchronous |
462 | | * version of this function. |
463 | | * |
464 | | * When the operation is finished, `callback` will be called in the main thread. |
465 | | * You can then call gdk_pixbuf_animation_new_from_stream_finish() to get the |
466 | | * result of the operation. |
467 | | * |
468 | | * Since: 2.28 |
469 | | * |
470 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
471 | | **/ |
472 | | void |
473 | | gdk_pixbuf_animation_new_from_stream_async (GInputStream *stream, |
474 | | GCancellable *cancellable, |
475 | | GAsyncReadyCallback callback, |
476 | | gpointer user_data) |
477 | 0 | { |
478 | 0 | GTask *task; |
479 | |
|
480 | 0 | g_return_if_fail (G_IS_INPUT_STREAM (stream)); |
481 | 0 | g_return_if_fail (callback != NULL); |
482 | 0 | g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); |
483 | | |
484 | 0 | task = g_task_new (G_OBJECT (stream), cancellable, callback, user_data); |
485 | 0 | g_task_set_source_tag (task, gdk_pixbuf_animation_new_from_stream_async); |
486 | 0 | g_task_run_in_thread (task, animation_new_from_stream_thread); |
487 | 0 | g_object_unref (task); |
488 | 0 | } |
489 | | |
490 | | /** |
491 | | * gdk_pixbuf_animation_new_from_stream_finish: |
492 | | * @async_result: a #GAsyncResult |
493 | | * @error: a #GError, or `NULL` |
494 | | * |
495 | | * Finishes an asynchronous pixbuf animation creation operation started with |
496 | | * [func@GdkPixbuf.PixbufAnimation.new_from_stream_async]. |
497 | | * |
498 | | * Return value: (transfer full) (nullable): the newly created animation |
499 | | * |
500 | | * Since: 2.28 |
501 | | * |
502 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
503 | | **/ |
504 | | GdkPixbufAnimation * |
505 | | gdk_pixbuf_animation_new_from_stream_finish (GAsyncResult *async_result, |
506 | | GError **error) |
507 | 0 | { |
508 | 0 | GTask *task = G_TASK (async_result); |
509 | |
|
510 | 0 | g_return_val_if_fail (G_IS_TASK (async_result), NULL); |
511 | 0 | g_return_val_if_fail (!error || (error && !*error), NULL); |
512 | 0 | g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_animation_new_from_stream_async); |
513 | |
|
514 | 0 | return g_task_propagate_pointer (task, error); |
515 | 0 | } |
516 | | |
517 | | /** |
518 | | * gdk_pixbuf_animation_new_from_resource: |
519 | | * @resource_path: the path of the resource file |
520 | | * @error: Return location for an error |
521 | | * |
522 | | * Creates a new pixbuf animation by loading an image from an resource. |
523 | | * |
524 | | * The file format is detected automatically. If `NULL` is returned, then |
525 | | * @error will be set. |
526 | | * |
527 | | * Return value: (transfer full) (nullable): A newly-created animation |
528 | | * |
529 | | * Since: 2.28 |
530 | | * |
531 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
532 | | */ |
533 | | GdkPixbufAnimation * |
534 | | gdk_pixbuf_animation_new_from_resource (const gchar *resource_path, |
535 | | GError **error) |
536 | 0 | { |
537 | 0 | GInputStream *stream; |
538 | 0 | GdkPixbufAnimation *anim; |
539 | 0 | GdkPixbuf *pixbuf; |
540 | |
|
541 | 0 | pixbuf = _gdk_pixbuf_new_from_resource_try_pixdata (resource_path); |
542 | 0 | if (pixbuf) { |
543 | 0 | anim = gdk_pixbuf_non_anim_new (pixbuf); |
544 | 0 | g_object_unref (pixbuf); |
545 | 0 | return anim; |
546 | 0 | } |
547 | | |
548 | 0 | stream = g_resources_open_stream (resource_path, 0, error); |
549 | 0 | if (stream == NULL) |
550 | 0 | return NULL; |
551 | | |
552 | 0 | anim = gdk_pixbuf_animation_new_from_stream (stream, NULL, error); |
553 | 0 | g_object_unref (stream); |
554 | 0 | return anim; |
555 | 0 | } |
556 | | |
557 | | /** |
558 | | * gdk_pixbuf_animation_ref: (skip) |
559 | | * @animation: An animation. |
560 | | * |
561 | | * Adds a reference to an animation. |
562 | | * |
563 | | * Return value: The same as the @animation argument. |
564 | | * |
565 | | * Deprecated: 2.0: Use g_object_ref(). |
566 | | */ |
567 | | GdkPixbufAnimation * |
568 | | gdk_pixbuf_animation_ref (GdkPixbufAnimation *animation) |
569 | 0 | { |
570 | 0 | return (GdkPixbufAnimation*) g_object_ref (animation); |
571 | 0 | } |
572 | | |
573 | | /** |
574 | | * gdk_pixbuf_animation_unref: (skip) |
575 | | * @animation: An animation. |
576 | | * |
577 | | * Removes a reference from an animation. |
578 | | * |
579 | | * Deprecated: 2.0: Use g_object_unref(). |
580 | | */ |
581 | | void |
582 | | gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation) |
583 | 0 | { |
584 | 0 | g_object_unref (animation); |
585 | 0 | } |
586 | | |
587 | | /** |
588 | | * gdk_pixbuf_animation_is_static_image: |
589 | | * @animation: a #GdkPixbufAnimation |
590 | | * |
591 | | * Checks whether the animation is a static image. |
592 | | * |
593 | | * If you load a file with gdk_pixbuf_animation_new_from_file() and it |
594 | | * turns out to be a plain, unanimated image, then this function will |
595 | | * return `TRUE`. Use gdk_pixbuf_animation_get_static_image() to retrieve |
596 | | * the image. |
597 | | * |
598 | | * Return value: `TRUE` if the "animation" was really just an image |
599 | | * |
600 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
601 | | */ |
602 | | gboolean |
603 | | gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation) |
604 | 0 | { |
605 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE); |
606 | | |
607 | 0 | return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation); |
608 | 0 | } |
609 | | |
610 | | /** |
611 | | * gdk_pixbuf_animation_get_static_image: |
612 | | * @animation: a #GdkPixbufAnimation |
613 | | * |
614 | | * Retrieves a static image for the animation. |
615 | | * |
616 | | * If an animation is really just a plain image (has only one frame), |
617 | | * this function returns that image. |
618 | | * |
619 | | * If the animation is an animation, this function returns a reasonable |
620 | | * image to use as a static unanimated image, which might be the first |
621 | | * frame, or something more sophisticated depending on the file format. |
622 | | * |
623 | | * If an animation hasn't loaded any frames yet, this function will |
624 | | * return `NULL`. |
625 | | * |
626 | | * Return value: (transfer none): unanimated image representing the animation |
627 | | * |
628 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
629 | | */ |
630 | | GdkPixbuf* |
631 | | gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation) |
632 | 0 | { |
633 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL); |
634 | | |
635 | 0 | return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation); |
636 | 0 | } |
637 | | |
638 | | /** |
639 | | * gdk_pixbuf_animation_get_width: |
640 | | * @animation: An animation. |
641 | | * |
642 | | * Queries the width of the bounding box of a pixbuf animation. |
643 | | * |
644 | | * Return value: Width of the bounding box of the animation. |
645 | | * |
646 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
647 | | */ |
648 | | gint |
649 | | gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation) |
650 | 0 | { |
651 | 0 | gint width; |
652 | |
|
653 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0); |
654 | | |
655 | 0 | width = 0; |
656 | 0 | GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation, |
657 | 0 | &width, NULL); |
658 | |
|
659 | 0 | return width; |
660 | 0 | } |
661 | | |
662 | | /** |
663 | | * gdk_pixbuf_animation_get_height: |
664 | | * @animation: An animation. |
665 | | * |
666 | | * Queries the height of the bounding box of a pixbuf animation. |
667 | | * |
668 | | * Return value: Height of the bounding box of the animation. |
669 | | * |
670 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
671 | | */ |
672 | | gint |
673 | | gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation) |
674 | 0 | { |
675 | 0 | gint height; |
676 | |
|
677 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0); |
678 | | |
679 | 0 | height = 0; |
680 | 0 | GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation, |
681 | 0 | NULL, &height); |
682 | |
|
683 | 0 | return height; |
684 | 0 | } |
685 | | |
686 | | |
687 | | /** |
688 | | * gdk_pixbuf_animation_get_iter: |
689 | | * @animation: a #GdkPixbufAnimation |
690 | | * @start_time: (allow-none): time when the animation starts playing |
691 | | * |
692 | | * Get an iterator for displaying an animation. |
693 | | * |
694 | | * The iterator provides the frames that should be displayed at a |
695 | | * given time. |
696 | | * |
697 | | * @start_time would normally come from g_get_current_time(), and marks |
698 | | * the beginning of animation playback. After creating an iterator, you |
699 | | * should immediately display the pixbuf returned by |
700 | | * gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install |
701 | | * a timeout (with g_timeout_add()) or by some other mechanism ensure |
702 | | * that you'll update the image after |
703 | | * gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time |
704 | | * the image is updated, you should reinstall the timeout with the new, |
705 | | * possibly-changed delay time. |
706 | | * |
707 | | * As a shortcut, if @start_time is `NULL`, the result of |
708 | | * g_get_current_time() will be used automatically. |
709 | | * |
710 | | * To update the image (i.e. possibly change the result of |
711 | | * gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation), |
712 | | * call gdk_pixbuf_animation_iter_advance(). |
713 | | * |
714 | | * If you're using #GdkPixbufLoader, in addition to updating the image |
715 | | * after the delay time, you should also update it whenever you |
716 | | * receive the area_updated signal and |
717 | | * gdk_pixbuf_animation_iter_on_currently_loading_frame() returns |
718 | | * `TRUE`. In this case, the frame currently being fed into the loader |
719 | | * has received new data, so needs to be refreshed. The delay time for |
720 | | * a frame may also be modified after an area_updated signal, for |
721 | | * example if the delay time for a frame is encoded in the data after |
722 | | * the frame itself. So your timeout should be reinstalled after any |
723 | | * area_updated signal. |
724 | | * |
725 | | * A delay time of -1 is possible, indicating "infinite". |
726 | | * |
727 | | * Return value: (transfer full): an iterator to move over the animation |
728 | | * |
729 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
730 | | */ |
731 | | GdkPixbufAnimationIter* |
732 | | gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation, |
733 | | const GTimeVal *start_time) |
734 | 0 | { |
735 | 0 | GTimeVal val; |
736 | |
|
737 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL); |
738 | | |
739 | | |
740 | 0 | if (start_time) |
741 | 0 | val = *start_time; |
742 | 0 | else |
743 | 0 | g_get_current_time (&val); |
744 | |
|
745 | 0 | return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val); |
746 | 0 | } |
747 | | |
748 | 0 | G_DEFINE_TYPE (GdkPixbufAnimationIter, gdk_pixbuf_animation_iter, G_TYPE_OBJECT); |
749 | 0 |
|
750 | 0 | static void |
751 | 0 | gdk_pixbuf_animation_iter_class_init (GdkPixbufAnimationIterClass *klass) |
752 | 0 | { |
753 | 0 | } |
754 | | |
755 | | static void |
756 | | gdk_pixbuf_animation_iter_init (GdkPixbufAnimationIter *iter) |
757 | 0 | { |
758 | 0 | } |
759 | | |
760 | | /** |
761 | | * gdk_pixbuf_animation_iter_get_delay_time: |
762 | | * @iter: an animation iterator |
763 | | * |
764 | | * Gets the number of milliseconds the current pixbuf should be displayed, |
765 | | * or -1 if the current pixbuf should be displayed forever. |
766 | | * |
767 | | * The `g_timeout_add()` function conveniently takes a timeout in milliseconds, |
768 | | * so you can use a timeout to schedule the next update. |
769 | | * |
770 | | * Note that some formats, like GIF, might clamp the timeout values in the |
771 | | * image file to avoid updates that are just too quick. The minimum timeout |
772 | | * for GIF images is currently 20 milliseconds. |
773 | | * |
774 | | * Return value: delay time in milliseconds (thousandths of a second) |
775 | | * |
776 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
777 | | */ |
778 | | gint |
779 | | gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter) |
780 | 0 | { |
781 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1); |
782 | 0 | g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time, -1); |
783 | | |
784 | 0 | return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter); |
785 | 0 | } |
786 | | |
787 | | /** |
788 | | * gdk_pixbuf_animation_iter_get_pixbuf: |
789 | | * @iter: an animation iterator |
790 | | * |
791 | | * Gets the current pixbuf which should be displayed. |
792 | | * |
793 | | * The pixbuf might not be the same size as the animation itself |
794 | | * (gdk_pixbuf_animation_get_width(), gdk_pixbuf_animation_get_height()). |
795 | | * |
796 | | * This pixbuf should be displayed for gdk_pixbuf_animation_iter_get_delay_time() |
797 | | * milliseconds. |
798 | | * |
799 | | * The caller of this function does not own a reference to the returned |
800 | | * pixbuf; the returned pixbuf will become invalid when the iterator |
801 | | * advances to the next frame, which may happen anytime you call |
802 | | * gdk_pixbuf_animation_iter_advance(). |
803 | | * |
804 | | * Copy the pixbuf to keep it (don't just add a reference), as it may get |
805 | | * recycled as you advance the iterator. |
806 | | * |
807 | | * Return value: (transfer none): the pixbuf to be displayed |
808 | | * |
809 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
810 | | */ |
811 | | GdkPixbuf* |
812 | | gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter) |
813 | 0 | { |
814 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL); |
815 | 0 | g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf, NULL); |
816 | | |
817 | 0 | return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter); |
818 | 0 | } |
819 | | |
820 | | /** |
821 | | * gdk_pixbuf_animation_iter_on_currently_loading_frame: |
822 | | * @iter: a #GdkPixbufAnimationIter |
823 | | * |
824 | | * Used to determine how to respond to the area_updated signal on |
825 | | * #GdkPixbufLoader when loading an animation. |
826 | | * |
827 | | * The `::area_updated` signal is emitted for an area of the frame currently |
828 | | * streaming in to the loader. So if you're on the currently loading frame, |
829 | | * you will need to redraw the screen for the updated area. |
830 | | * |
831 | | * Return value: `TRUE` if the frame we're on is partially loaded, or the last frame |
832 | | * |
833 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
834 | | */ |
835 | | gboolean |
836 | | gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter) |
837 | 0 | { |
838 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE); |
839 | 0 | g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame, FALSE); |
840 | | |
841 | 0 | return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter); |
842 | 0 | } |
843 | | |
844 | | /** |
845 | | * gdk_pixbuf_animation_iter_advance: |
846 | | * @iter: a #GdkPixbufAnimationIter |
847 | | * @current_time: (allow-none): current time |
848 | | * |
849 | | * Possibly advances an animation to a new frame. |
850 | | * |
851 | | * Chooses the frame based on the start time passed to |
852 | | * gdk_pixbuf_animation_get_iter(). |
853 | | * |
854 | | * @current_time would normally come from g_get_current_time(), and |
855 | | * must be greater than or equal to the time passed to |
856 | | * gdk_pixbuf_animation_get_iter(), and must increase or remain |
857 | | * unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is |
858 | | * called. That is, you can't go backward in time; animations only |
859 | | * play forward. |
860 | | * |
861 | | * As a shortcut, pass `NULL` for the current time and g_get_current_time() |
862 | | * will be invoked on your behalf. So you only need to explicitly pass |
863 | | * @current_time if you're doing something odd like playing the animation |
864 | | * at double speed. |
865 | | * |
866 | | * If this function returns `FALSE`, there's no need to update the animation |
867 | | * display, assuming the display had been rendered prior to advancing; |
868 | | * if `TRUE`, you need to call gdk_pixbuf_animation_iter_get_pixbuf() |
869 | | * and update the display with the new pixbuf. |
870 | | * |
871 | | * Returns: `TRUE` if the image may need updating |
872 | | * |
873 | | * Deprecated: 2.44: Use a different image loading library for animatable assets |
874 | | */ |
875 | | gboolean |
876 | | gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter, |
877 | | const GTimeVal *current_time) |
878 | 0 | { |
879 | 0 | GTimeVal val; |
880 | |
|
881 | 0 | g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE); |
882 | 0 | g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance, FALSE); |
883 | | |
884 | 0 | if (current_time) |
885 | 0 | val = *current_time; |
886 | 0 | else |
887 | 0 | g_get_current_time (&val); |
888 | |
|
889 | 0 | return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val); |
890 | 0 | } |
891 | | |
892 | | static void gdk_pixbuf_non_anim_finalize (GObject *object); |
893 | | static gboolean gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation); |
894 | | static GdkPixbuf* gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation); |
895 | | static void gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim, |
896 | | gint *width, |
897 | | gint *height); |
898 | | static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim, |
899 | | const GTimeVal *start_time); |
900 | | |
901 | 0 | G_DEFINE_TYPE (GdkPixbufNonAnim, gdk_pixbuf_non_anim, GDK_TYPE_PIXBUF_ANIMATION); |
902 | 0 |
|
903 | 0 | static void |
904 | 0 | gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass) |
905 | 0 | { |
906 | 0 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
907 | 0 | GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass); |
908 | |
|
909 | 0 | object_class->finalize = gdk_pixbuf_non_anim_finalize; |
910 | |
|
911 | 0 | anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image; |
912 | 0 | anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image; |
913 | 0 | anim_class->get_size = gdk_pixbuf_non_anim_get_size; |
914 | 0 | anim_class->get_iter = gdk_pixbuf_non_anim_get_iter; |
915 | 0 | } |
916 | | |
917 | | static void |
918 | | gdk_pixbuf_non_anim_init (GdkPixbufNonAnim *non_anim) |
919 | 0 | { |
920 | 0 | } |
921 | | |
922 | | static void |
923 | | gdk_pixbuf_non_anim_finalize (GObject *object) |
924 | 0 | { |
925 | 0 | GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object); |
926 | |
|
927 | 0 | if (non_anim->pixbuf) |
928 | 0 | g_object_unref (non_anim->pixbuf); |
929 | |
|
930 | 0 | G_OBJECT_CLASS (gdk_pixbuf_non_anim_parent_class)->finalize (object); |
931 | 0 | } |
932 | | |
933 | | GdkPixbufAnimation* |
934 | | gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf) |
935 | 0 | { |
936 | 0 | GdkPixbufNonAnim *non_anim; |
937 | |
|
938 | 0 | non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL); |
939 | |
|
940 | 0 | non_anim->pixbuf = pixbuf; |
941 | |
|
942 | 0 | if (pixbuf) |
943 | 0 | g_object_ref (pixbuf); |
944 | |
|
945 | 0 | return GDK_PIXBUF_ANIMATION (non_anim); |
946 | 0 | } |
947 | | |
948 | | static gboolean |
949 | | gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation) |
950 | 0 | { |
951 | |
|
952 | 0 | return TRUE; |
953 | 0 | } |
954 | | |
955 | | static GdkPixbuf* |
956 | | gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation) |
957 | 0 | { |
958 | 0 | GdkPixbufNonAnim *non_anim; |
959 | |
|
960 | 0 | non_anim = GDK_PIXBUF_NON_ANIM (animation); |
961 | |
|
962 | 0 | return non_anim->pixbuf; |
963 | 0 | } |
964 | | |
965 | | static void |
966 | | gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim, |
967 | | gint *width, |
968 | | gint *height) |
969 | 0 | { |
970 | 0 | GdkPixbufNonAnim *non_anim; |
971 | |
|
972 | 0 | non_anim = GDK_PIXBUF_NON_ANIM (anim); |
973 | |
|
974 | 0 | if (width) |
975 | 0 | *width = gdk_pixbuf_get_width (non_anim->pixbuf); |
976 | |
|
977 | 0 | if (height) |
978 | 0 | *height = gdk_pixbuf_get_height (non_anim->pixbuf); |
979 | 0 | } |
980 | | |
981 | | static GdkPixbufAnimationIter* |
982 | | gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim, |
983 | | const GTimeVal *start_time) |
984 | 0 | { |
985 | 0 | GdkPixbufNonAnimIter *iter; |
986 | |
|
987 | 0 | iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL); |
988 | |
|
989 | 0 | iter->non_anim = GDK_PIXBUF_NON_ANIM (anim); |
990 | |
|
991 | 0 | g_object_ref (iter->non_anim); |
992 | |
|
993 | 0 | return GDK_PIXBUF_ANIMATION_ITER (iter); |
994 | 0 | } |
995 | | |
996 | | static void gdk_pixbuf_non_anim_iter_finalize (GObject *object); |
997 | | static gint gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter); |
998 | | static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter); |
999 | | static gboolean gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter); |
1000 | | static gboolean gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter, |
1001 | | const GTimeVal *current_time); |
1002 | | |
1003 | 0 | G_DEFINE_TYPE (GdkPixbufNonAnimIter, gdk_pixbuf_non_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER) |
1004 | 0 |
|
1005 | 0 | static void |
1006 | 0 | gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass) |
1007 | 0 | { |
1008 | 0 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
1009 | 0 | GdkPixbufAnimationIterClass *anim_iter_class = |
1010 | 0 | GDK_PIXBUF_ANIMATION_ITER_CLASS (klass); |
1011 | |
|
1012 | 0 | object_class->finalize = gdk_pixbuf_non_anim_iter_finalize; |
1013 | |
|
1014 | 0 | anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time; |
1015 | 0 | anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf; |
1016 | 0 | anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame; |
1017 | 0 | anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance; |
1018 | 0 | } |
1019 | | |
1020 | | static void |
1021 | | gdk_pixbuf_non_anim_iter_init (GdkPixbufNonAnimIter *non_iter) |
1022 | 0 | { |
1023 | 0 | } |
1024 | | |
1025 | | static void |
1026 | | gdk_pixbuf_non_anim_iter_finalize (GObject *object) |
1027 | 0 | { |
1028 | 0 | GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object); |
1029 | |
|
1030 | 0 | g_object_unref (iter->non_anim); |
1031 | |
|
1032 | 0 | G_OBJECT_CLASS (gdk_pixbuf_non_anim_iter_parent_class)->finalize (object); |
1033 | 0 | } |
1034 | | |
1035 | | static gint |
1036 | | gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter) |
1037 | 0 | { |
1038 | 0 | return -1; /* show only frame forever */ |
1039 | 0 | } |
1040 | | |
1041 | | static GdkPixbuf* |
1042 | | gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter) |
1043 | 0 | { |
1044 | 0 | return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf; |
1045 | 0 | } |
1046 | | |
1047 | | |
1048 | | static gboolean |
1049 | | gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter) |
1050 | 0 | { |
1051 | 0 | return TRUE; |
1052 | 0 | } |
1053 | | |
1054 | | static gboolean |
1055 | | gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter, |
1056 | | const GTimeVal *current_time) |
1057 | 0 | { |
1058 | | |
1059 | | /* Advancing never requires a refresh */ |
1060 | 0 | return FALSE; |
1061 | 0 | } |