gdk-pixbuf-animation.c 34.2 KB
Newer Older
Havoc Pennington's avatar
Havoc Pennington committed
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3
4
5
6
7
8
9
/* GdkPixbuf library - Simple animation support
 *
 * Copyright (C) 1999 The Free Software Foundation
 *
 * Authors: Jonathan Blandford <jrb@redhat.com>
 *          Havoc Pennington <hp@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
12
13
14
15
16
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 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
Havoc Pennington's avatar
Havoc Pennington committed
25
#include <errno.h>
26
#include "gdk-pixbuf-private.h"
27
#include "gdk-pixbuf-animation.h"
28
#include "gdk-pixbuf-loader.h"
29

30
31
#include <glib/gstdio.h>

32
/**
33
34
35
 * GdkPixbufAnimation:
 *
 * An opaque object representing an animation.
Matthias Clasen's avatar
Matthias Clasen committed
36
 *
37
 * The GdkPixBuf library provides a simple mechanism to load and
38
 * represent animations. An animation is conceptually a series of
39
40
41
42
43
44
45
46
 * frames to be displayed over time.
 *
 * The animation may not be represented as a series of frames
 * internally; for example, it may be stored as a sprite and
 * instructions for moving the sprite around a background.
 *
 * To display an animation you don't need to understand its
 * representation, however; you just ask `GdkPixbuf` what should
47
 * be displayed at a given point in time.
48
49
 */

50
51
52
53
54
55
56
/**
 * GdkPixbufAnimationIter:
 *
 * An opaque object representing an iterator which points to a
 * certain position in an animation.
 */

Havoc Pennington's avatar
Havoc Pennington committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim;
typedef struct _GdkPixbufNonAnimClass GdkPixbufNonAnimClass;

#define GDK_TYPE_PIXBUF_NON_ANIM              (gdk_pixbuf_non_anim_get_type ())
#define GDK_PIXBUF_NON_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnim))
#define GDK_IS_PIXBUF_NON_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM))

#define GDK_PIXBUF_NON_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
#define GDK_IS_PIXBUF_NON_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM))
#define GDK_PIXBUF_NON_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))

/* Private part of the GdkPixbufNonAnim structure */
struct _GdkPixbufNonAnim {
        GdkPixbufAnimation parent_instance;

        GdkPixbuf *pixbuf;
};

struct _GdkPixbufNonAnimClass {
        GdkPixbufAnimationClass parent_class;
};

79

Havoc Pennington's avatar
Havoc Pennington committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
typedef struct _GdkPixbufNonAnimIter GdkPixbufNonAnimIter;
typedef struct _GdkPixbufNonAnimIterClass GdkPixbufNonAnimIterClass;


#define GDK_TYPE_PIXBUF_NON_ANIM_ITER              (gdk_pixbuf_non_anim_iter_get_type ())
#define GDK_PIXBUF_NON_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIter))
#define GDK_IS_PIXBUF_NON_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER))

#define GDK_PIXBUF_NON_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
#define GDK_IS_PIXBUF_NON_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
#define GDK_PIXBUF_NON_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))

struct _GdkPixbufNonAnimIter {
        GdkPixbufAnimationIter parent_instance;

        GdkPixbufNonAnim   *non_anim;
};

struct _GdkPixbufNonAnimIterClass {
        GdkPixbufAnimationIterClass parent_class;

};

static GType gdk_pixbuf_non_anim_iter_get_type (void) G_GNUC_CONST;

105
106
107
108
109
G_DEFINE_TYPE (GdkPixbufAnimation, gdk_pixbuf_animation, G_TYPE_OBJECT);

static void
gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass)
{
110
111
}

112
113
114
115
static void
gdk_pixbuf_animation_init (GdkPixbufAnimation *animation)
{
}
116

117
118
119
120
121
122
123
static void
noop_size_notify (gint     *width,
		  gint     *height,
		  gpointer  data)
{
}

124
static void
Matthias Clasen's avatar
Matthias Clasen committed
125
126
127
prepared_notify (GdkPixbuf          *pixbuf,
                 GdkPixbufAnimation *anim,
                 gpointer            user_data)
128
129
130
131
132
133
134
135
136
{
        if (anim != NULL)
                g_object_ref (anim);
        else
                anim = gdk_pixbuf_non_anim_new (pixbuf);

        *((GdkPixbufAnimation **)user_data) = anim;
}

137
138
139
140
141
142
143
144
145
146
static void
noop_updated_notify (GdkPixbuf *pixbuf,
                     int        x,
                     int        y,
                     int        width,
                     int        height,
                     gpointer   user_data)
{
}

147
148
/**
 * gdk_pixbuf_animation_new_from_file:
149
 * @filename: (type filename): Name of file to load, in the GLib file
150
 *   name encoding
Havoc Pennington's avatar
Havoc Pennington committed
151
 * @error: return location for error
152
 *
153
 * Creates a new animation by loading it from a file.
154
 *
155
156
157
158
159
160
161
162
 * The file format is detected automatically.
 *
 * If the file's format does not support multi-frame images, then an animation
 * with a single frame will be created.
 *
 * Possible errors are in the `GDK_PIXBUF_ERROR` and `G_FILE_ERROR` domains.
 *
 * Return value: (transfer full) (nullable): A newly-created animation
Matthias Clasen's avatar
Matthias Clasen committed
163
 */
164
GdkPixbufAnimation *
Matthias Clasen's avatar
Matthias Clasen committed
165
166
gdk_pixbuf_animation_new_from_file (const gchar  *filename,
                                    GError      **error)
167
168
169
170
{
	GdkPixbufAnimation *animation;
	int size;
	FILE *f;
Matthias Clasen's avatar
Matthias Clasen committed
171
	guchar buffer[SNIFF_BUFFER_SIZE];
172
	GdkPixbufModule *image_module;
173
        gchar *display_name;
174
175

	g_return_val_if_fail (filename != NULL, NULL);
176
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
177

178
        display_name = g_filename_display_name (filename);
179
	f = g_fopen (filename, "rb");
Havoc Pennington's avatar
Havoc Pennington committed
180
	if (!f) {
181
                gint save_errno = errno;
Havoc Pennington's avatar
Havoc Pennington committed
182
183
                g_set_error (error,
                             G_FILE_ERROR,
184
                             g_file_error_from_errno (save_errno),
185
                             _("Failed to open file “%s”: %s"),
186
                             display_name,
187
                             g_strerror (save_errno));
188
                g_free (display_name);
189
		return NULL;
Havoc Pennington's avatar
Havoc Pennington committed
190
        }
191
192
193
194

	size = fread (&buffer, 1, sizeof (buffer), f);

	if (size == 0) {
Havoc Pennington's avatar
Havoc Pennington committed
195
196
197
                g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
198
                             _("Image file “%s” contains no data"),
199
200
                             display_name);
                g_free (display_name);
201
202
203
204
		fclose (f);
		return NULL;
	}

205
	image_module = _gdk_pixbuf_get_module (buffer, size, filename, error);
206
	if (!image_module) {
207
                g_free (display_name);
208
209
210
211
212
		fclose (f);
		return NULL;
	}

	if (image_module->module == NULL)
213
                if (!_gdk_pixbuf_load_module (image_module, error)) {
214
                        g_free (display_name);
Havoc Pennington's avatar
Havoc Pennington committed
215
216
217
                        fclose (f);
                        return NULL;
                }
218

Benjamin Otte's avatar
Benjamin Otte committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
	if (image_module->load_animation != NULL) {
		fseek (f, 0, SEEK_SET);
		animation = (* image_module->load_animation) (f, error);

                if (animation == NULL && error != NULL && *error == NULL) {
                        /* I don't trust these crufty longjmp()'ing
                         * image libs to maintain proper error
                         * invariants, and I don't want user code to
                         * segfault as a result. We need to maintain
                         * the invariant that error gets set if NULL
                         * is returned.
                         */
                        g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
                                   image_module->module_name);
                        g_set_error (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
236
                                     _("Failed to load animation “%s”: reason not known, probably a corrupt animation file"),
Benjamin Otte's avatar
Benjamin Otte committed
237
238
                                     display_name);
                }
Matthias Clasen's avatar
Matthias Clasen committed
239

240
241
242
243
244
		fclose (f);
        } else if (image_module->begin_load != NULL) {
                guchar buffer[4096];
                size_t length;
                gpointer context;
245
                gboolean success;
246

247
                success = FALSE;
Benjamin Otte's avatar
Benjamin Otte committed
248
                animation = NULL;
249
250
		fseek (f, 0, SEEK_SET);

251
                context = image_module->begin_load (noop_size_notify, prepared_notify, noop_updated_notify, &animation, error);
252
253
                if (!context)
                        goto fail_begin_load;
Matthias Clasen's avatar
Matthias Clasen committed
254

255
256
                while (!feof (f) && !ferror (f)) {
                        length = fread (buffer, 1, sizeof (buffer), f);
Benjamin Otte's avatar
Benjamin Otte committed
257
                        if (length > 0) {
258
                                if (!image_module->load_increment (context, buffer, length, error)) {
Benjamin Otte's avatar
Benjamin Otte committed
259
                                        error = NULL;
260
                                        goto fail_load_increment;
261
                                }
Benjamin Otte's avatar
Benjamin Otte committed
262
                        }
263
264
                }

265
266
267
268
269
270
271
                success = TRUE;

fail_load_increment:
                if (!image_module->stop_load (context, error))
                        success = FALSE;

fail_begin_load:
Benjamin Otte's avatar
Benjamin Otte committed
272
273
		fclose (f);

274
275
276
277
278
279
280
281
                if (success) {
                        /* If there was no error, there must be an animation that was successfully loaded */
                        g_assert (animation);
                } else {
                        if (animation) {
                                g_object_unref (animation);
                                animation = NULL;
                        }
282
                }
Benjamin Otte's avatar
Benjamin Otte committed
283
	} else {
284
285
286
287
288
		GdkPixbuf *pixbuf;

		/* Keep this logic in sync with gdk_pixbuf_new_from_file() */

		fseek (f, 0, SEEK_SET);
289
		pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
290
291
		fclose (f);

Havoc Pennington's avatar
Havoc Pennington committed
292
293
294
295
296
297
                if (pixbuf == NULL && error != NULL && *error == NULL) {
                        /* I don't trust these crufty longjmp()'ing image libs
                         * to maintain proper error invariants, and I don't
                         * want user code to segfault as a result. We need to maintain
                         * the invariant that error gets set if NULL is returned.
                         */
Matthias Clasen's avatar
Matthias Clasen committed
298

Havoc Pennington's avatar
Havoc Pennington committed
299
300
301
302
303
                        g_warning ("Bug! gdk-pixbuf loader '%s' didn't set an error on failure.",
                                   image_module->module_name);
                        g_set_error (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_FAILED,
304
                                     _("Failed to load image “%s”: reason not known, probably a corrupt image file"),
305
                                     display_name);
Havoc Pennington's avatar
Havoc Pennington committed
306
                }
Matthias Clasen's avatar
Matthias Clasen committed
307

308
309
		if (pixbuf == NULL) {
                        g_free (display_name);
310
                        animation = NULL;
311
                        goto out;
312
                }
313

314
                animation = gdk_pixbuf_non_anim_new (pixbuf);
315

316
                g_object_unref (pixbuf);
317
318
	}

319
320
        g_free (display_name);

321
 out:
322
323
324
	return animation;
}

325
#ifdef G_OS_WIN32
326
327
/**
 * gdk_pixbuf_animation_new_from_file_utf8:
328
 * @filename: (type filename): Name of file to load, in the GLib file name encoding
329
330
331
332
 * @error: return location for error
 *
 * Same as gdk_pixbuf_animation_new_from_file()
 *
333
 * Return value: A newly-created animation with a reference count of 1, or `NULL`
334
335
336
337
 * if any of several error conditions ocurred:  the file could not be opened,
 * there was no loader for the file's format, there was not enough memory to
 * allocate the image buffer, or the image file contained invalid data.
 */
338
GdkPixbufAnimation *
339
340
gdk_pixbuf_animation_new_from_file_utf8 (const gchar  *filename,
                                         GError      **error)
341
{
342
    return gdk_pixbuf_animation_new_from_file (filename, error);
343
344
345
}
#endif

346
347
/**
 * gdk_pixbuf_animation_new_from_stream:
348
349
 * @stream:  a `GInputStream` to load the pixbuf from
 * @cancellable: (nullable): optional `GCancellable` object
350
351
352
353
 * @error: Return location for an error
 *
 * Creates a new animation by loading it from an input stream.
 *
354
355
356
357
358
359
360
361
 * The file format is detected automatically.
 *
 * If `NULL` is returned, then @error will be set.
 *
 * The @cancellable can be used to abort the operation from another thread.
 * If the operation was cancelled, the error `G_IO_ERROR_CANCELLED` will be
 * returned. Other possible errors are in the `GDK_PIXBUF_ERROR` and
 * `G_IO_ERROR` domains.
362
363
364
 *
 * The stream is not closed.
 *
365
 * Return value: (transfer full) (nullable): A newly-created animation
366
367
 *
 * Since: 2.28
Matthias Clasen's avatar
Matthias Clasen committed
368
 */
369
GdkPixbufAnimation *
Matthias Clasen's avatar
Matthias Clasen committed
370
371
372
gdk_pixbuf_animation_new_from_stream (GInputStream  *stream,
                                      GCancellable  *cancellable,
                                      GError       **error)
373
374
375
376
377
378
379
380
381
382
383
384
385
386
{
        GdkPixbufAnimation *animation;
        GdkPixbufLoader *loader;
        gssize n_read;
        guchar buffer[LOAD_BUFFER_SIZE];
        gboolean res;

        g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL);
        g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);

        loader = gdk_pixbuf_loader_new ();

        res = TRUE;
Matthias Clasen's avatar
Matthias Clasen committed
387
388
        while (1) {
                n_read = g_input_stream_read (stream, buffer, sizeof (buffer), cancellable, error);
389
390
391
392
393
394
395
396
397
                if (n_read < 0) {
                        res = FALSE;
                        error = NULL; /* Ignore further errors */
                        break;
                }

                if (n_read == 0)
                        break;

Matthias Clasen's avatar
Matthias Clasen committed
398
                if (!gdk_pixbuf_loader_write (loader, buffer, n_read, error)) {
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
                        res = FALSE;
                        error = NULL;
                        break;
                }
        }

        if (!gdk_pixbuf_loader_close (loader, error)) {
                res = FALSE;
                error = NULL;
        }

        if (res) {
                animation = gdk_pixbuf_loader_get_animation (loader);
                if (animation)
                        g_object_ref (animation);
        } else {
                animation = NULL;
        }

        g_object_unref (loader);

        return animation;
}

423
static void
Matthias Clasen's avatar
Matthias Clasen committed
424
425
426
427
animation_new_from_stream_thread (GTask        *task,
                                  gpointer      source_object,
                                  gpointer      task_data,
                                  GCancellable *cancellable)
428
{
Matthias Clasen's avatar
Matthias Clasen committed
429
        GInputStream *stream = G_INPUT_STREAM (source_object);
430
431
432
433
434
435
436
	GdkPixbufAnimation *animation;
	GError *error = NULL;

	animation = gdk_pixbuf_animation_new_from_stream (stream, cancellable, &error);

	/* Set the new pixbuf as the result, or error out */
	if (animation == NULL) {
Matthias Clasen's avatar
Matthias Clasen committed
437
                g_task_return_error (task, error);
438
	} else {
Matthias Clasen's avatar
Matthias Clasen committed
439
                g_task_return_pointer (task, animation, g_object_unref);
440
441
442
443
444
445
	}
}

/**
 * gdk_pixbuf_animation_new_from_stream_async:
 * @stream: a #GInputStream from which to load the animation
446
447
 * @cancellable: (nullable): optional #GCancellable object
 * @callback: a `GAsyncReadyCallback` to call when the pixbuf is loaded
448
449
450
451
452
453
454
 * @user_data: the data to pass to the callback function
 *
 * Creates a new animation by asynchronously loading an image from an input stream.
 *
 * For more details see gdk_pixbuf_new_from_stream(), which is the synchronous
 * version of this function.
 *
455
 * When the operation is finished, `callback` will be called in the main thread.
456
457
458
459
460
461
462
463
464
465
466
 * You can then call gdk_pixbuf_animation_new_from_stream_finish() to get the
 * result of the operation.
 *
 * Since: 2.28
 **/
void
gdk_pixbuf_animation_new_from_stream_async (GInputStream        *stream,
                                            GCancellable        *cancellable,
                                            GAsyncReadyCallback  callback,
                                            gpointer             user_data)
{
Matthias Clasen's avatar
Matthias Clasen committed
467
	GTask *task;
468
469
470
471
472

	g_return_if_fail (G_IS_INPUT_STREAM (stream));
	g_return_if_fail (callback != NULL);
	g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));

Matthias Clasen's avatar
Matthias Clasen committed
473
474
475
476
	task = g_task_new (G_OBJECT (stream), cancellable, callback, user_data);
        g_task_set_source_tag (task, gdk_pixbuf_animation_new_from_stream_async);
	g_task_run_in_thread (task, animation_new_from_stream_thread);
	g_object_unref (task);
477
478
479
480
481
}

/**
 * gdk_pixbuf_animation_new_from_stream_finish:
 * @async_result: a #GAsyncResult
482
 * @error: a #GError, or `NULL`
483
484
 *
 * Finishes an asynchronous pixbuf animation creation operation started with
485
 * [func@GdkPixbuf.PixbufAnimation.new_from_stream_async].
486
 *
487
 * Return value: (transfer full) (nullable): the newly created animation
488
 *
Benjamin Otte's avatar
Benjamin Otte committed
489
 * Since: 2.28
490
491
492
493
494
 **/
GdkPixbufAnimation *
gdk_pixbuf_animation_new_from_stream_finish (GAsyncResult  *async_result,
			              	     GError       **error)
{
Matthias Clasen's avatar
Matthias Clasen committed
495
        GTask *task = G_TASK (async_result);
496

Matthias Clasen's avatar
Matthias Clasen committed
497
	g_return_val_if_fail (G_IS_TASK (async_result), NULL);
498
	g_return_val_if_fail (!error || (error && !*error), NULL);
Matthias Clasen's avatar
Matthias Clasen committed
499
	g_warn_if_fail (g_task_get_source_tag (task) == gdk_pixbuf_animation_new_from_stream_async);
500

Matthias Clasen's avatar
Matthias Clasen committed
501
	return g_task_propagate_pointer (task, error);
502
503
}

504
505
506
507
508
509
510
/**
 * gdk_pixbuf_animation_new_from_resource:
 * @resource_path: the path of the resource file
 * @error: Return location for an error
 *
 * Creates a new pixbuf animation by loading an image from an resource.
 *
511
 * The file format is detected automatically. If `NULL` is returned, then
512
513
 * @error will be set.
 *
514
 * Return value: (transfer full) (nullable): A newly-created animation
515
516
 *
 * Since: 2.28
Matthias Clasen's avatar
Matthias Clasen committed
517
 */
518
GdkPixbufAnimation *
Matthias Clasen's avatar
Matthias Clasen committed
519
520
gdk_pixbuf_animation_new_from_resource (const gchar  *resource_path,
                                        GError      **error)
521
522
523
524
525
{
	GInputStream *stream;
	GdkPixbufAnimation *anim;
	GdkPixbuf *pixbuf;

526
        pixbuf = _gdk_pixbuf_new_from_resource_try_pixdata (resource_path);
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
        if (pixbuf) {
                anim = gdk_pixbuf_non_anim_new (pixbuf);
                g_object_unref (pixbuf);
                return anim;
        }

	stream = g_resources_open_stream (resource_path, 0, error);
	if (stream == NULL)
		return NULL;

	anim = gdk_pixbuf_animation_new_from_stream (stream, NULL, error);
	g_object_unref (stream);
	return anim;
}

Matthias Clasen's avatar
Matthias Clasen committed
542
/**
Johan Dahlin's avatar
Johan Dahlin committed
543
 * gdk_pixbuf_animation_ref: (skip)
Matthias Clasen's avatar
Matthias Clasen committed
544
545
546
547
548
549
550
 * @animation: An animation.
 *
 * Adds a reference to an animation.
 *
 * Return value: The same as the @animation argument.
 *
 * Deprecated: 2.0: Use g_object_ref().
Matthias Clasen's avatar
Matthias Clasen committed
551
 */
Matthias Clasen's avatar
Matthias Clasen committed
552
553
554
555
556
557
558
GdkPixbufAnimation *
gdk_pixbuf_animation_ref (GdkPixbufAnimation *animation)
{
        return (GdkPixbufAnimation*) g_object_ref (animation);
}

/**
Johan Dahlin's avatar
Johan Dahlin committed
559
 * gdk_pixbuf_animation_unref: (skip)
Matthias Clasen's avatar
Matthias Clasen committed
560
561
562
563
564
 * @animation: An animation.
 *
 * Removes a reference from an animation.
 *
 * Deprecated: 2.0: Use g_object_unref().
Matthias Clasen's avatar
Matthias Clasen committed
565
 */
Matthias Clasen's avatar
Matthias Clasen committed
566
567
568
569
570
571
void
gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
{
        g_object_unref (animation);
}

Havoc Pennington's avatar
Havoc Pennington committed
572
573
574
/**
 * gdk_pixbuf_animation_is_static_image:
 * @animation: a #GdkPixbufAnimation
Matthias Clasen's avatar
Matthias Clasen committed
575
 *
576
577
 * Checks whether the animation is a static image.
 *
Matthias Clasen's avatar
Matthias Clasen committed
578
579
 * If you load a file with gdk_pixbuf_animation_new_from_file() and it
 * turns out to be a plain, unanimated image, then this function will
580
 * return `TRUE`. Use gdk_pixbuf_animation_get_static_image() to retrieve
Havoc Pennington's avatar
Havoc Pennington committed
581
 * the image.
Matthias Clasen's avatar
Matthias Clasen committed
582
 *
583
 * Return value: `TRUE` if the "animation" was really just an image
Matthias Clasen's avatar
Matthias Clasen committed
584
 */
Havoc Pennington's avatar
Havoc Pennington committed
585
586
587
588
589
590
591
592
593
594
595
gboolean
gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation)
{
	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE);

        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation);
}

/**
 * gdk_pixbuf_animation_get_static_image:
 * @animation: a #GdkPixbufAnimation
Matthias Clasen's avatar
Matthias Clasen committed
596
 *
597
598
 * Retrieves a static image for the animation.
 *
Havoc Pennington's avatar
Havoc Pennington committed
599
 * If an animation is really just a plain image (has only one frame),
600
601
602
603
604
605
606
607
 * this function returns that image.
 *
 * If the animation is an animation, this function returns a reasonable
 * image to use as a static unanimated image, which might be the first
 * frame, or something more sophisticated depending on the file format.
 *
 * If an animation hasn't loaded any frames yet, this function will
 * return `NULL`.
Matthias Clasen's avatar
Matthias Clasen committed
608
 *
Johan Dahlin's avatar
Johan Dahlin committed
609
 * Return value: (transfer none): unanimated image representing the animation
Matthias Clasen's avatar
Matthias Clasen committed
610
 */
Havoc Pennington's avatar
Havoc Pennington committed
611
612
613
614
GdkPixbuf*
gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation)
{
	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
Matthias Clasen's avatar
Matthias Clasen committed
615

Havoc Pennington's avatar
Havoc Pennington committed
616
617
618
        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation);
}

619
620
621
/**
 * gdk_pixbuf_animation_get_width:
 * @animation: An animation.
622
623
 *
 * Queries the width of the bounding box of a pixbuf animation.
Matthias Clasen's avatar
Matthias Clasen committed
624
 *
625
 * Return value: Width of the bounding box of the animation.
Matthias Clasen's avatar
Matthias Clasen committed
626
627
 */
gint
628
629
gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
{
Matthias Clasen's avatar
Matthias Clasen committed
630
631
        gint width;

Havoc Pennington's avatar
Havoc Pennington committed
632
633
634
635
636
	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);

        width = 0;
        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
                                                              &width, NULL);
637

Havoc Pennington's avatar
Havoc Pennington committed
638
	return width;
639
640
641
642
643
}

/**
 * gdk_pixbuf_animation_get_height:
 * @animation: An animation.
644
645
 *
 * Queries the height of the bounding box of a pixbuf animation.
Matthias Clasen's avatar
Matthias Clasen committed
646
 *
647
 * Return value: Height of the bounding box of the animation.
Matthias Clasen's avatar
Matthias Clasen committed
648
649
 */
gint
650
651
gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation)
{
Matthias Clasen's avatar
Matthias Clasen committed
652
653
        gint height;

Havoc Pennington's avatar
Havoc Pennington committed
654
	g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
655

Havoc Pennington's avatar
Havoc Pennington committed
656
657
658
        height = 0;
        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
                                                              NULL, &height);
659

Havoc Pennington's avatar
Havoc Pennington committed
660
	return height;
661
662
}

Havoc Pennington's avatar
Havoc Pennington committed
663

664
/**
Havoc Pennington's avatar
Havoc Pennington committed
665
666
 * gdk_pixbuf_animation_get_iter:
 * @animation: a #GdkPixbufAnimation
667
 * @start_time: (allow-none): time when the animation starts playing
Matthias Clasen's avatar
Matthias Clasen committed
668
 *
669
670
671
672
 * Get an iterator for displaying an animation.
 *
 * The iterator provides the frames that should be displayed at a
 * given time.
Matthias Clasen's avatar
Matthias Clasen committed
673
674
675
676
677
678
 *
 * @start_time would normally come from g_get_current_time(), and marks
 * the beginning of animation playback. After creating an iterator, you
 * should immediately display the pixbuf returned by
 * gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install
 * a timeout (with g_timeout_add()) or by some other mechanism ensure
Havoc Pennington's avatar
Havoc Pennington committed
679
680
681
682
683
 * that you'll update the image after
 * gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time
 * the image is updated, you should reinstall the timeout with the new,
 * possibly-changed delay time.
 *
684
 * As a shortcut, if @start_time is `NULL`, the result of
Havoc Pennington's avatar
Havoc Pennington committed
685
 * g_get_current_time() will be used automatically.
686
 *
Havoc Pennington's avatar
Havoc Pennington committed
687
688
689
690
691
692
693
694
 * To update the image (i.e. possibly change the result of
 * gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation),
 * call gdk_pixbuf_animation_iter_advance().
 *
 * If you're using #GdkPixbufLoader, in addition to updating the image
 * after the delay time, you should also update it whenever you
 * receive the area_updated signal and
 * gdk_pixbuf_animation_iter_on_currently_loading_frame() returns
695
 * `TRUE`. In this case, the frame currently being fed into the loader
Havoc Pennington's avatar
Havoc Pennington committed
696
697
698
699
700
701
 * has received new data, so needs to be refreshed. The delay time for
 * a frame may also be modified after an area_updated signal, for
 * example if the delay time for a frame is encoded in the data after
 * the frame itself. So your timeout should be reinstalled after any
 * area_updated signal.
 *
702
 * A delay time of -1 is possible, indicating "infinite".
Matthias Clasen's avatar
Matthias Clasen committed
703
 *
Johan Dahlin's avatar
Johan Dahlin committed
704
 * Return value: (transfer full): an iterator to move over the animation
Matthias Clasen's avatar
Matthias Clasen committed
705
 */
Havoc Pennington's avatar
Havoc Pennington committed
706
707
708
GdkPixbufAnimationIter*
gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
                               const GTimeVal     *start_time)
709
{
Havoc Pennington's avatar
Havoc Pennington committed
710
        GTimeVal val;
Matthias Clasen's avatar
Matthias Clasen committed
711

Havoc Pennington's avatar
Havoc Pennington committed
712
713
        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);

714

Havoc Pennington's avatar
Havoc Pennington committed
715
716
717
718
        if (start_time)
                val = *start_time;
        else
                g_get_current_time (&val);
Matthias Clasen's avatar
Matthias Clasen committed
719

Havoc Pennington's avatar
Havoc Pennington committed
720
        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
721
}
722

723
G_DEFINE_TYPE (GdkPixbufAnimationIter, gdk_pixbuf_animation_iter, G_TYPE_OBJECT);
724

725
726
static void
gdk_pixbuf_animation_iter_class_init (GdkPixbufAnimationIterClass *klass)
727
{
728
}
729

730
731
732
static void
gdk_pixbuf_animation_iter_init (GdkPixbufAnimationIter *iter)
{
733
734
735
}

/**
Havoc Pennington's avatar
Havoc Pennington committed
736
737
 * gdk_pixbuf_animation_iter_get_delay_time:
 * @iter: an animation iterator
738
 *
Havoc Pennington's avatar
Havoc Pennington committed
739
 * Gets the number of milliseconds the current pixbuf should be displayed,
740
741
742
743
 * or -1 if the current pixbuf should be displayed forever.
 *
 * The `g_timeout_add()` function conveniently takes a timeout in milliseconds,
 * so you can use a timeout to schedule the next update.
Havoc Pennington's avatar
Havoc Pennington committed
744
 *
745
746
747
748
 * Note that some formats, like GIF, might clamp the timeout values in the
 * image file to avoid updates that are just too quick. The minimum timeout
 * for GIF images is currently 20 milliseconds.
 *
Havoc Pennington's avatar
Havoc Pennington committed
749
 * Return value: delay time in milliseconds (thousandths of a second)
Matthias Clasen's avatar
Matthias Clasen committed
750
751
 */
gint
Havoc Pennington's avatar
Havoc Pennington committed
752
gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
753
{
Havoc Pennington's avatar
Havoc Pennington committed
754
        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1);
755
756
        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time, -1);

Havoc Pennington's avatar
Havoc Pennington committed
757
        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter);
758
759
760
}

/**
Havoc Pennington's avatar
Havoc Pennington committed
761
762
 * gdk_pixbuf_animation_iter_get_pixbuf:
 * @iter: an animation iterator
Matthias Clasen's avatar
Matthias Clasen committed
763
 *
764
765
766
 * Gets the current pixbuf which should be displayed.
 *
 * The pixbuf might not be the same size as the animation itself
Matthias Clasen's avatar
Matthias Clasen committed
767
 * (gdk_pixbuf_animation_get_width(), gdk_pixbuf_animation_get_height()).
768
769
770
771
772
773
774
775
776
777
778
 *
 * This pixbuf should be displayed for gdk_pixbuf_animation_iter_get_delay_time()
 * milliseconds.
 *
 * The caller of this function does not own a reference to the returned
 * pixbuf; the returned pixbuf will become invalid when the iterator
 * advances to the next frame, which may happen anytime you call
 * gdk_pixbuf_animation_iter_advance().
 *
 * Copy the pixbuf to keep it (don't just add a reference), as it may get
 * recycled as you advance the iterator.
Havoc Pennington's avatar
Havoc Pennington committed
779
 *
Johan Dahlin's avatar
Johan Dahlin committed
780
 * Return value: (transfer none): the pixbuf to be displayed
Matthias Clasen's avatar
Matthias Clasen committed
781
 */
Havoc Pennington's avatar
Havoc Pennington committed
782
783
GdkPixbuf*
gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
784
{
Havoc Pennington's avatar
Havoc Pennington committed
785
        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
786
787
        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf, NULL);

Havoc Pennington's avatar
Havoc Pennington committed
788
        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
789
790
791
}

/**
Havoc Pennington's avatar
Havoc Pennington committed
792
793
794
795
 * gdk_pixbuf_animation_iter_on_currently_loading_frame:
 * @iter: a #GdkPixbufAnimationIter
 *
 * Used to determine how to respond to the area_updated signal on
796
 * #GdkPixbufLoader when loading an animation.
797
 *
798
799
800
801
802
 * The `::area_updated` signal is emitted for an area of the frame currently
 * streaming in to the loader. So if you're on the currently loading frame,
 * you will need to redraw the screen for the updated area.
 *
 * Return value: `TRUE` if the frame we're on is partially loaded, or the last frame
Matthias Clasen's avatar
Matthias Clasen committed
803
 */
Havoc Pennington's avatar
Havoc Pennington committed
804
805
gboolean
gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
806
{
Havoc Pennington's avatar
Havoc Pennington committed
807
        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
808
809
        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame, FALSE);

Havoc Pennington's avatar
Havoc Pennington committed
810
        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
811
812
813
}

/**
Havoc Pennington's avatar
Havoc Pennington committed
814
815
 * gdk_pixbuf_animation_iter_advance:
 * @iter: a #GdkPixbufAnimationIter
816
 * @current_time: (allow-none): current time
Havoc Pennington's avatar
Havoc Pennington committed
817
 *
818
819
820
821
 * Possibly advances an animation to a new frame.
 *
 * Chooses the frame based on the start time passed to
 * gdk_pixbuf_animation_get_iter().
822
 *
Havoc Pennington's avatar
Havoc Pennington committed
823
824
825
826
827
828
829
 * @current_time would normally come from g_get_current_time(), and
 * must be greater than or equal to the time passed to
 * gdk_pixbuf_animation_get_iter(), and must increase or remain
 * unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is
 * called. That is, you can't go backward in time; animations only
 * play forward.
 *
830
 * As a shortcut, pass `NULL` for the current time and g_get_current_time()
Havoc Pennington's avatar
Havoc Pennington committed
831
832
833
834
 * will be invoked on your behalf. So you only need to explicitly pass
 * @current_time if you're doing something odd like playing the animation
 * at double speed.
 *
835
 * If this function returns `FALSE`, there's no need to update the animation
Havoc Pennington's avatar
Havoc Pennington committed
836
 * display, assuming the display had been rendered prior to advancing;
837
 * if `TRUE`, you need to call gdk_pixbuf_animation_iter_get_pixbuf()
Matthias Clasen's avatar
Matthias Clasen committed
838
 * and update the display with the new pixbuf.
Havoc Pennington's avatar
Havoc Pennington committed
839
 *
840
 * Returns: `TRUE` if the image may need updating
Matthias Clasen's avatar
Matthias Clasen committed
841
 */
Havoc Pennington's avatar
Havoc Pennington committed
842
843
844
gboolean
gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
                                   const GTimeVal         *current_time)
845
{
Havoc Pennington's avatar
Havoc Pennington committed
846
        GTimeVal val;
847

Havoc Pennington's avatar
Havoc Pennington committed
848
        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
849
        g_return_val_if_fail (GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance, FALSE);
850

Havoc Pennington's avatar
Havoc Pennington committed
851
852
853
854
        if (current_time)
                val = *current_time;
        else
                g_get_current_time (&val);
855

Havoc Pennington's avatar
Havoc Pennington committed
856
        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val);
857
}
858

859
static void                    gdk_pixbuf_non_anim_finalize         (GObject            *object);
Havoc Pennington's avatar
Havoc Pennington committed
860
861
862
static gboolean                gdk_pixbuf_non_anim_is_static_image  (GdkPixbufAnimation *animation);
static GdkPixbuf*              gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation);
static void                    gdk_pixbuf_non_anim_get_size         (GdkPixbufAnimation *anim,
Matthias Clasen's avatar
Matthias Clasen committed
863
864
                                                                     gint               *width,
                                                                     gint               *height);
Havoc Pennington's avatar
Havoc Pennington committed
865
866
867
static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter         (GdkPixbufAnimation *anim,
                                                                     const GTimeVal     *start_time);

868
G_DEFINE_TYPE (GdkPixbufNonAnim, gdk_pixbuf_non_anim, GDK_TYPE_PIXBUF_ANIMATION);
869

Havoc Pennington's avatar
Havoc Pennington committed
870
871
static void
gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
872
{
Havoc Pennington's avatar
Havoc Pennington committed
873
874
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
Matthias Clasen's avatar
Matthias Clasen committed
875

Havoc Pennington's avatar
Havoc Pennington committed
876
877
878
879
880
881
882
883
        object_class->finalize = gdk_pixbuf_non_anim_finalize;

        anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image;
        anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image;
        anim_class->get_size = gdk_pixbuf_non_anim_get_size;
        anim_class->get_iter = gdk_pixbuf_non_anim_get_iter;
}

884
885
886
887
888
static void
gdk_pixbuf_non_anim_init (GdkPixbufNonAnim *non_anim)
{
}

Havoc Pennington's avatar
Havoc Pennington committed
889
890
891
892
893
894
static void
gdk_pixbuf_non_anim_finalize (GObject *object)
{
        GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object);

        if (non_anim->pixbuf)
895
                g_object_unref (non_anim->pixbuf);
Matthias Clasen's avatar
Matthias Clasen committed
896

897
        G_OBJECT_CLASS (gdk_pixbuf_non_anim_parent_class)->finalize (object);
Havoc Pennington's avatar
Havoc Pennington committed
898
899
900
}

GdkPixbufAnimation*
901
gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf)
Havoc Pennington's avatar
Havoc Pennington committed
902
903
904
905
906
907
908
909
{
        GdkPixbufNonAnim *non_anim;

        non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL);

        non_anim->pixbuf = pixbuf;

        if (pixbuf)
910
                g_object_ref (pixbuf);
911

Havoc Pennington's avatar
Havoc Pennington committed
912
        return GDK_PIXBUF_ANIMATION (non_anim);
913
914
}

Havoc Pennington's avatar
Havoc Pennington committed
915
static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
916
gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation)
Havoc Pennington's avatar
Havoc Pennington committed
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
{

        return TRUE;
}

static GdkPixbuf*
gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation)
{
        GdkPixbufNonAnim *non_anim;

        non_anim = GDK_PIXBUF_NON_ANIM (animation);

        return non_anim->pixbuf;
}

static void
gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
Matthias Clasen's avatar
Matthias Clasen committed
934
935
                              gint               *width,
                              gint               *height)
Havoc Pennington's avatar
Havoc Pennington committed
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
{
        GdkPixbufNonAnim *non_anim;

        non_anim = GDK_PIXBUF_NON_ANIM (anim);

        if (width)
                *width = gdk_pixbuf_get_width (non_anim->pixbuf);

        if (height)
                *height = gdk_pixbuf_get_height (non_anim->pixbuf);
}

static GdkPixbufAnimationIter*
gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
                              const GTimeVal     *start_time)
{
        GdkPixbufNonAnimIter *iter;

        iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL);

        iter->non_anim = GDK_PIXBUF_NON_ANIM (anim);

958
        g_object_ref (iter->non_anim);
Matthias Clasen's avatar
Matthias Clasen committed
959

Havoc Pennington's avatar
Havoc Pennington committed
960
961
962
        return GDK_PIXBUF_ANIMATION_ITER (iter);
}

963
static void       gdk_pixbuf_non_anim_iter_finalize                   (GObject                *object);
Matthias Clasen's avatar
Matthias Clasen committed
964
static gint       gdk_pixbuf_non_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
Havoc Pennington's avatar
Havoc Pennington committed
965
966
967
968
969
static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
static gboolean   gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
static gboolean   gdk_pixbuf_non_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
                                                                       const GTimeVal         *current_time);

Matthias Clasen's avatar
Matthias Clasen committed
970
G_DEFINE_TYPE (GdkPixbufNonAnimIter, gdk_pixbuf_non_anim_iter, GDK_TYPE_PIXBUF_ANIMATION_ITER)
Havoc Pennington's avatar
Havoc Pennington committed
971
972
973
974
975
976
977

static void
gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass)
{
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
        GdkPixbufAnimationIterClass *anim_iter_class =
                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
Matthias Clasen's avatar
Matthias Clasen committed
978

Havoc Pennington's avatar
Havoc Pennington committed
979
980
981
982
983
984
985
986
        object_class->finalize = gdk_pixbuf_non_anim_iter_finalize;

        anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time;
        anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf;
        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame;
        anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance;
}

987
988
989
990
991
static void
gdk_pixbuf_non_anim_iter_init (GdkPixbufNonAnimIter *non_iter)
{
}

Havoc Pennington's avatar
Havoc Pennington committed
992
993
static void
gdk_pixbuf_non_anim_iter_finalize (GObject *object)
994
{
Havoc Pennington's avatar
Havoc Pennington committed
995
        GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
996

997
        g_object_unref (iter->non_anim);
Matthias Clasen's avatar
Matthias Clasen committed
998

999
        G_OBJECT_CLASS (gdk_pixbuf_non_anim_iter_parent_class)->finalize (object);
Havoc Pennington's avatar
Havoc Pennington committed
1000
1001
}

Matthias Clasen's avatar
Matthias Clasen committed
1002
static gint
Havoc Pennington's avatar
Havoc Pennington committed
1003
1004
1005
1006
gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter)
{
        return -1; /* show only frame forever */
}
1007

Havoc Pennington's avatar
Havoc Pennington committed
1008
1009
1010
1011
static GdkPixbuf*
gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
{
        return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf;
1012
}
Havoc Pennington's avatar
Havoc Pennington committed
1013
1014
1015
1016
1017
1018
1019


static gboolean
gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
{
        return TRUE;
}
Matthias Clasen's avatar
Matthias Clasen committed
1020

Havoc Pennington's avatar
Havoc Pennington committed
1021
1022
1023
1024
1025
1026
1027
1028
static gboolean
gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
                                  const GTimeVal         *current_time)
{

        /* Advancing never requires a refresh */
        return FALSE;
}