#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
#include <gtk/gtk.h>
#include <stdio.h>

char data[8192];
int length;
GdkPixbufAnimation *anim = NULL;
GdkPixbuf *unanim = NULL;
GtkWidget *pix;
guint timer;
gint curframe;

static gboolean redraw_anim(gpointer data)
{
	int delay;
	GList *frames;
	GdkPixbufFrame *frame;
	GdkPixbuf *buf;
	GdkPixmap *pm; GdkBitmap *bm;
	GdkPixmap *src;
	GdkGC *gc;

	frames = gdk_pixbuf_animation_get_frames(anim);
	frame = g_list_nth_data(frames, curframe);
	switch (gdk_pixbuf_frame_get_action(frame)) {
		case GDK_PIXBUF_FRAME_RETAIN:
			buf = gdk_pixbuf_frame_get_pixbuf(frame);
			gdk_pixbuf_render_pixmap_and_mask(buf, &src, NULL, 0);
			gtk_pixmap_get(GTK_PIXMAP(pix), &pm, &bm);
			gc = gdk_gc_new(pm);
			gdk_draw_pixmap(pm, gc, src, 0, 0,
					gdk_pixbuf_frame_get_x_offset(frame),
					gdk_pixbuf_frame_get_y_offset(frame),
					-1, -1);
			gtk_pixmap_set(GTK_PIXMAP(pix), pm, bm);
			gtk_widget_queue_draw(pix);
			gdk_gc_unref(gc);
			break;
		case GDK_PIXBUF_FRAME_DISPOSE:
			buf = gdk_pixbuf_frame_get_pixbuf(frame);
			gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0);
			gtk_pixmap_set(GTK_PIXMAP(pix), pm, bm);
			gdk_pixmap_unref(pm);
			if (bm)
				gdk_bitmap_unref(bm);
			break;
		case GDK_PIXBUF_FRAME_REVERT:
			frame = frames->data;
			buf = gdk_pixbuf_frame_get_pixbuf(frame);
			gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0);
			gtk_pixmap_set(GTK_PIXMAP(pix), pm, bm);
			gdk_pixmap_unref(pm);
			if (bm)
				gdk_bitmap_unref(bm);
			break;
	}
	curframe = (curframe + 1) % g_list_length(frames);
	delay = MAX(gdk_pixbuf_frame_get_delay_time(frame), 13);
	timer = gtk_timeout_add(delay * 10, redraw_anim, NULL);
	return FALSE;
}

void des_evt(GtkObject *o, gpointer d)
{
	if (anim)
		gdk_pixbuf_animation_unref(anim);
	if (unanim)
		gdk_pixbuf_unref(unanim);
	if (timer)
		gtk_timeout_remove(timer);
	gtk_main_quit();
}

int main(int argc, char **argv)
{
	GdkPixbufLoader *load;
	GList *frames;
	GdkPixbuf *buf;
	GdkPixmap *pm;
	GdkBitmap *bm;
	char data[8192];
	int length;

	FILE *f;
	GtkWidget *win;
	GtkWidget *vbox;
	GtkWidget *hbox;

	gtk_init(&argc, &argv);

	if (argc == 2)
		f = fopen(argv[1], "r");
	else
		f = fopen("picture.id", "r");
	if (!f) return 1;

	length = fread(data, 1, 8192, f);
	fclose(f);

	load = gdk_pixbuf_loader_new();
	gdk_pixbuf_loader_write(load, data, length);
	anim = gdk_pixbuf_loader_get_animation(load);

	if (anim) {
		frames = gdk_pixbuf_animation_get_frames(anim);
		buf = gdk_pixbuf_frame_get_pixbuf(frames->data);
		gdk_pixbuf_render_pixmap_and_mask(buf, &pm, &bm, 0);

		if (gdk_pixbuf_animation_get_num_frames(anim) > 1) {
			int delay = MAX(gdk_pixbuf_frame_get_delay_time(frames->data), 13);
			curframe = 1;
			timer = gtk_timeout_add(delay * 10, redraw_anim, NULL);
		}
	} else {
		unanim = gdk_pixbuf_loader_get_pixbuf(load);
		if (!unanim) {
			gdk_pixbuf_loader_close(load);
			return 1;
		}
		gdk_pixbuf_render_pixmap_and_mask(unanim, &pm, &bm, 0);
	}

	win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_policy(GTK_WINDOW(win), TRUE, TRUE, TRUE);
	gtk_signal_connect(GTK_OBJECT(win), "destroy", GTK_SIGNAL_FUNC(des_evt), NULL);

	vbox = gtk_hbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(win), vbox);
	gtk_widget_show(vbox);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
	gtk_widget_show(hbox);

	pix = gtk_pixmap_new(pm, bm);
	gtk_box_pack_start(GTK_BOX(hbox), pix, FALSE, FALSE, 0);
	if (anim && (gdk_pixbuf_animation_get_num_frames(anim) > 1))
		gtk_widget_set_usize(pix, gdk_pixbuf_animation_get_width(anim),
				gdk_pixbuf_animation_get_height(anim));
	gtk_widget_show(pix);
	gdk_pixmap_unref(pm);
	if (bm)
		gdk_bitmap_unref(bm);

	gdk_pixbuf_loader_close(load);

	gtk_widget_show(win);

	gtk_main();

	return 0;
}
