+ if (frame != newframe)
+ gtk_spin_button_set_value(spin, newframe);
+}
+
+static gboolean timeout(gpointer data)
+{
+ static double lasttime = INFINITY;
+ static GTimer *timer;
+
+ if (isinf(lasttime)) {
+ timer = g_timer_new();
+ if (timer) {
+ lasttime = 0;
+ }
+ } else {
+ double time = g_timer_elapsed(timer, NULL);
+
+ tick(data, time - lasttime);
+ lasttime = time;
+ }
+
+ return TRUE;
+}
+
+gboolean canvas_expose(GtkWidget *canvas, GdkEventExpose *event, gpointer data)
+{
+ if (!framebuf)
+ return FALSE;
+
+ gdk_draw_rectangle(canvas->window, bg_gc, TRUE,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ gdk_draw_pixbuf(canvas->window, NULL, framebuf,
+ event->area.x, event->area.y, event->area.x, event->area.y,
+ event->area.width, event->area.height,
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+
+ return TRUE;
+}
+
+static int alloc_framebuffer(struct lbx_image *image)
+{
+ GtkSpinButton *spin;
+
+ if (framebuf)
+ g_object_unref(framebuf);
+
+ framebuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
+ image->width, image->height);
+ g_return_val_if_fail(framebuf, -1);
+
+ spin = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "framespin"));
+ gtk_spin_button_set_range(spin, 0, image->frames-1);
+ gtk_spin_button_set_value(spin, 0);
+
+ gtk_widget_set_size_request(canvas, image->width, image->height);