[gthumb: 16/40] gth-image-loader: use callbacks instead of signals



commit 69f25bc5f2a846f1bc74399b9431bb0497323bec
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Mon Sep 6 23:43:19 2010 +0200

    gth-image-loader: use callbacks instead of signals
    
    this new api allows to fix some loading errors when the user
    quickly changes images.

 extensions/file_viewer/gth-file-viewer-page.c     |   58 +-
 extensions/flicker/dlg-import-from-flickr.c       |    4 +-
 extensions/image_print/gth-load-image-info-task.c |   38 +-
 extensions/image_viewer/gth-image-viewer-page.c   |   10 +-
 extensions/list_tools/gth-script.c                |   33 +-
 extensions/picasaweb/dlg-import-from-picasaweb.c  |    4 +-
 extensions/slideshow/gth-slideshow.c              |   48 +-
 extensions/webalbums/gth-web-exporter.c           |   67 +-
 gthumb/gth-file-list.c                            |  320 ++++----
 gthumb/gth-file-properties.c                      |   10 +-
 gthumb/gth-image-loader.c                         |  780 ++++-------------
 gthumb/gth-image-loader.h                         |   62 +-
 gthumb/gth-image-preloader.c                      |  570 +++++++------
 gthumb/gth-image-preloader.h                      |   17 +-
 gthumb/gth-main.c                                 |   22 +-
 gthumb/gth-main.h                                 |    2 +-
 gthumb/gth-marshal.list                           |    2 +-
 gthumb/gth-overwrite-dialog.c                     |   59 +-
 gthumb/gth-thumb-loader.c                         |  960 ++++++++++-----------
 gthumb/gth-thumb-loader.h                         |   59 +-
 20 files changed, 1385 insertions(+), 1740 deletions(-)
---
diff --git a/extensions/file_viewer/gth-file-viewer-page.c b/extensions/file_viewer/gth-file-viewer-page.c
index f2f3923..f2824d7 100644
--- a/extensions/file_viewer/gth-file-viewer-page.c
+++ b/extensions/file_viewer/gth-file-viewer-page.c
@@ -42,7 +42,6 @@ struct _GthFileViewerPagePrivate {
 	GthFileData    *file_data;
 	guint           merge_id;
 	GthThumbLoader *thumb_loader;
-	gulong          thumb_loader_ready_event;
 };
 
 
@@ -86,17 +85,6 @@ viewer_popup_menu_cb (GtkWidget         *widget,
 
 
 static void
-thumb_loader_ready_cb (GthThumbLoader    *il,
-		       GError            *error,
-		       GthFileViewerPage *self)
-{
-	if (error == NULL)
-		gtk_image_set_from_pixbuf (GTK_IMAGE (self->priv->icon), gth_thumb_loader_get_pixbuf (self->priv->thumb_loader));
-	gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), self->priv->file_data, TRUE);
-}
-
-
-static void
 gth_file_viewer_page_real_activate (GthViewerPage *base,
 				    GthBrowser    *browser)
 {
@@ -107,13 +95,7 @@ gth_file_viewer_page_real_activate (GthViewerPage *base,
 	self = (GthFileViewerPage*) base;
 
 	self->priv->browser = browser;
-
 	self->priv->thumb_loader = gth_thumb_loader_new (128);
-	self->priv->thumb_loader_ready_event =
-			g_signal_connect (G_OBJECT (self->priv->thumb_loader),
-					  "ready",
-					  G_CALLBACK (thumb_loader_ready_cb),
-					  self);
 
 	self->priv->viewer = gtk_event_box_new ();
 	gtk_widget_show (self->priv->viewer);
@@ -162,10 +144,6 @@ gth_file_viewer_page_real_deactivate (GthViewerPage *base)
 	GthFileViewerPage *self;
 
 	self = (GthFileViewerPage*) base;
-
-	g_signal_handler_disconnect (self->priv->thumb_loader, self->priv->thumb_loader_ready_event);
-	self->priv->thumb_loader_ready_event = 0;
-
 	gth_browser_set_viewer_widget (self->priv->browser, NULL);
 }
 
@@ -214,6 +192,34 @@ gth_file_viewer_page_real_can_view (GthViewerPage *base,
 
 
 static void
+thumb_loader_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
+{
+	GthFileViewerPage *self = user_data;
+	GthFileData       *file_data;
+	GdkPixbuf         *pixbuf;
+
+	if (! gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object),
+					    result,
+					    &file_data,
+					    &pixbuf,
+					    NULL))
+	{
+		return;
+	}
+
+	if (g_file_equal (self->priv->file_data->file, file_data->file)) {
+		gtk_image_set_from_pixbuf (GTK_IMAGE (self->priv->icon), pixbuf);
+		gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), self->priv->file_data, TRUE);
+	}
+
+	g_object_unref (pixbuf);
+	g_object_unref (file_data);
+}
+
+
+static void
 gth_file_viewer_page_real_view (GthViewerPage *base,
 				GthFileData   *file_data)
 {
@@ -232,8 +238,12 @@ gth_file_viewer_page_real_view (GthViewerPage *base,
 	self->priv->file_data = g_object_ref (file_data);
 
 	gth_viewer_page_focus (GTH_VIEWER_PAGE (self));
-	gth_thumb_loader_set_file (self->priv->thumb_loader, file_data);
-	gth_thumb_loader_load (self->priv->thumb_loader);
+
+	gth_thumb_loader_load (self->priv->thumb_loader,
+			       self->priv->file_data,
+			       NULL,
+			       thumb_loader_ready_cb,
+			       self);
 }
 
 
diff --git a/extensions/flicker/dlg-import-from-flickr.c b/extensions/flicker/dlg-import-from-flickr.c
index c6a1589..eee3443 100644
--- a/extensions/flicker/dlg-import-from-flickr.c
+++ b/extensions/flicker/dlg-import-from-flickr.c
@@ -560,8 +560,8 @@ dlg_import_from_flickr (FlickrServer *server,
 
 	data->file_list = gth_file_list_new (GTH_FILE_LIST_TYPE_NORMAL, FALSE);
 	thumb_loader = gth_file_list_get_thumb_loader (GTH_FILE_LIST (data->file_list));
-	gth_thumb_loader_use_cache (thumb_loader, FALSE);
-	gth_thumb_loader_set_loader (thumb_loader, flickr_thumbnail_loader);
+	gth_thumb_loader_set_use_cache (thumb_loader, FALSE);
+	gth_thumb_loader_set_loader_func (thumb_loader, flickr_thumbnail_loader);
 	gth_file_list_set_thumb_size (GTH_FILE_LIST (data->file_list), FLICKR_SIZE_THUMBNAIL);
 	gth_file_view_set_spacing (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (data->file_list))), 0);
 	gth_file_list_enable_thumbs (GTH_FILE_LIST (data->file_list), TRUE);
diff --git a/extensions/image_print/gth-load-image-info-task.c b/extensions/image_print/gth-load-image-info-task.c
index f7fd3f5..a6b84c3 100644
--- a/extensions/image_print/gth-load-image-info-task.c
+++ b/extensions/image_print/gth-load-image-info-task.c
@@ -103,13 +103,23 @@ continue_loading_image (GthLoadImageInfoTask *self)
 
 
 static void
-image_loader_ready_cb (GthImageLoader *loader,
-		       GError         *error,
-		       gpointer        user_data)
+image_loader_ready_cb (GObject      *source_object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
 {
 	GthLoadImageInfoTask *self = user_data;
 	GthImageInfo         *image_info;
 	GdkPixbuf            *pixbuf;
+	GError               *error = NULL;
+
+	gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
+					    result,
+					    NULL,
+					    NULL,
+					    &pixbuf,
+					    NULL,
+					    NULL,
+					    &error);
 
 	if (error == NULL)
 		g_cancellable_set_error_if_cancelled (gth_task_get_cancellable (GTH_TASK (self)), &error);
@@ -120,9 +130,10 @@ image_loader_ready_cb (GthImageLoader *loader,
 	}
 
 	image_info = self->priv->images[self->priv->current];
-	pixbuf = gth_image_loader_get_pixbuf (loader);
-	if (pixbuf != NULL)
+	if (pixbuf != NULL) {
 		gth_image_info_set_pixbuf (image_info, pixbuf);
+		g_object_unref (pixbuf);
+	}
 
 	continue_loading_image (self);
 }
@@ -149,10 +160,13 @@ load_current_image (GthLoadImageInfoTask *self)
 			   FALSE,
 			   ((double) self->priv->current + 0.5) / self->priv->n_images);
 
-	if (image_info->pixbuf == NULL) {
-		gth_image_loader_set_file_data (self->priv->loader, image_info->file_data);
-		gth_image_loader_load (self->priv->loader);
-	}
+	if (image_info->pixbuf == NULL)
+		gth_image_loader_load (self->priv->loader,
+				       image_info->file_data,
+				       -1,
+				       gth_task_get_cancellable (GTH_TASK (self)),
+				       image_loader_ready_cb,
+				       self);
 	else
 		call_when_idle ((DataFunc) continue_loading_image, self);
 
@@ -202,11 +216,7 @@ static void
 gth_load_image_info_task_init (GthLoadImageInfoTask *self)
 {
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_LOAD_IMAGE_INFO_TASK, GthLoadImageInfoTaskPrivate);
-	self->priv->loader = gth_image_loader_new (FALSE);
-	g_signal_connect (self->priv->loader,
-			  "ready",
-			  G_CALLBACK (image_loader_ready_cb),
-			  self);
+	self->priv->loader = gth_image_loader_new (NULL, NULL);
 }
 
 
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index b8cebc1..1c846f0 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -287,13 +287,12 @@ viewer_key_press_cb (GtkWidget          *widget,
 static void
 image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
 				    GthFileData        *requested,
-				    GthImageLoader     *image_loader,
+				    GdkPixbufAnimation *animation,
+				    int                 original_width,
+				    int                 original_height,
 				    GError             *error,
 				    GthImageViewerPage *self)
 {
-	int original_width;
-	int original_height;
-
 	if (! _g_file_equal (requested->file, self->priv->file_data->file))
 		return;
 
@@ -304,9 +303,8 @@ image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
 
 	gth_viewer_page_focus (GTH_VIEWER_PAGE (self));
 
-	gth_image_loader_get_original_size (image_loader, &original_width, &original_height);
 	gth_image_viewer_set_animation (GTH_IMAGE_VIEWER (self->priv->viewer),
-					gth_image_loader_get_animation (image_loader),
+					animation,
 					original_width,
 					original_height);
 
diff --git a/extensions/list_tools/gth-script.c b/extensions/list_tools/gth-script.c
index 90b72f4..ec230ac 100644
--- a/extensions/list_tools/gth-script.c
+++ b/extensions/list_tools/gth-script.c
@@ -590,20 +590,25 @@ get_parent_func (GthFileData *file_data)
 
 
 static void
-thumb_loader_ready_cb (GthThumbLoader *thumb_loader,
-		       GError         *error,
-		       gpointer        user_data)
+thumb_loader_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
 {
 	GtkBuilder *builder = user_data;
 	GdkPixbuf  *pixbuf;
 
-	pixbuf = gth_thumb_loader_get_pixbuf (thumb_loader);
-	if (pixbuf != NULL) {
-		GtkWidget *image;
+	if (! gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object),
+		  	 	 	    result,
+		  	 	 	    NULL,
+		  	 	 	    &pixbuf,
+		  	 	 	    NULL))
+	{
+		return;
+	}
 
-		image = _gtk_builder_get_widget (builder, "request_image");
-		if (image != NULL)
-			gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+	if (pixbuf != NULL) {
+		gtk_image_set_from_pixbuf (GTK_IMAGE (_gtk_builder_get_widget (builder, "request_image")), pixbuf);
+		g_object_unref (pixbuf);
 	}
 
 	g_object_unref (builder);
@@ -650,14 +655,16 @@ ask_value (ReplaceData  *replace_data,
 	gtk_window_set_title (GTK_WINDOW (dialog), "");
 	gtk_window_set_transient_for (GTK_WINDOW (dialog), replace_data->parent);
 	gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
-	if (! gth_script_for_each_file(replace_data->script))
+	if (! gth_script_for_each_file (replace_data->script))
 		gtk_widget_hide (_gtk_builder_get_widget (builder, "skip_button"));
 
 	g_object_ref (builder);
 	thumb_loader = gth_thumb_loader_new (128);
-	g_signal_connect (thumb_loader, "ready", G_CALLBACK (thumb_loader_ready_cb), builder);
-	gth_thumb_loader_set_file (thumb_loader, file_data);
-	gth_thumb_loader_load (thumb_loader);
+	gth_thumb_loader_load (thumb_loader,
+			       file_data,
+			       NULL,
+			       thumb_loader_ready_cb,
+			       builder);
 
 	result = gtk_dialog_run (GTK_DIALOG (dialog));
 	if (result == 2) {
diff --git a/extensions/picasaweb/dlg-import-from-picasaweb.c b/extensions/picasaweb/dlg-import-from-picasaweb.c
index 1723f7a..b60594d 100644
--- a/extensions/picasaweb/dlg-import-from-picasaweb.c
+++ b/extensions/picasaweb/dlg-import-from-picasaweb.c
@@ -975,8 +975,8 @@ dlg_import_from_picasaweb (GthBrowser *browser)
 
 	data->file_list = gth_file_list_new (GTH_FILE_LIST_TYPE_NORMAL, FALSE);
 	thumb_loader = gth_file_list_get_thumb_loader (GTH_FILE_LIST (data->file_list));
-	gth_thumb_loader_use_cache (thumb_loader, FALSE);
-	gth_thumb_loader_set_loader (thumb_loader, picasa_web_thumbnail_loader);
+	gth_thumb_loader_set_use_cache (thumb_loader, FALSE);
+	gth_thumb_loader_set_loader_func (thumb_loader, picasa_web_thumbnail_loader);
 	gth_file_list_set_thumb_size (GTH_FILE_LIST (data->file_list), PICASA_WEB_THUMB_SIZE_SMALL);
 	gth_file_view_set_spacing (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (data->file_list))), 0);
 	gth_file_list_enable_thumbs (GTH_FILE_LIST (data->file_list), TRUE);
diff --git a/extensions/slideshow/gth-slideshow.c b/extensions/slideshow/gth-slideshow.c
index 70c5d4f..8e75a9e 100644
--- a/extensions/slideshow/gth-slideshow.c
+++ b/extensions/slideshow/gth-slideshow.c
@@ -60,6 +60,7 @@ struct _GthSlideshowPrivate {
 	ClutterActor          *image1;
 	ClutterActor          *image2;
 #endif
+	GdkPixbuf             *current_pixbuf;
 	GtkWidget             *viewer;
 	guint                  next_event;
 	guint                  delay;
@@ -224,14 +225,15 @@ view_next_image_automatically (GthSlideshow *self)
 
 
 static void
-image_preloader_requested_ready_cb (GthImagePreloader *preloader,
-				    GthFileData       *requested,
-				    GthImageLoader    *image_loader,
-				    GError            *error,
-				    gpointer           user_data)
+image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
+				    GthFileData        *requested,
+				    GdkPixbufAnimation *animation,
+				    int                 original_width,
+				    int                 original_height,
+				    GError             *error,
+				    gpointer            user_data)
 {
-	GthSlideshow   *self = user_data;
-	GdkPixbuf      *pixbuf;
+	GthSlideshow *self = user_data;
 
 	if (error != NULL) {
 		g_clear_error (&error);
@@ -239,14 +241,15 @@ image_preloader_requested_ready_cb (GthImagePreloader *preloader,
 		return;
 	}
 
-	pixbuf = gth_image_loader_get_pixbuf (image_loader);
-	if (pixbuf == NULL) {
+	_g_object_unref (self->priv->current_pixbuf);
+	self->priv->current_pixbuf = gdk_pixbuf_animation_get_static_image (animation);
+	if (self->priv->current_pixbuf == NULL) {
 		_gth_slideshow_load_next_image (self);
 		return;
 	}
 
 	self->priv->one_loaded = TRUE;
-	self->priv->projector->image_ready (self, pixbuf);
+	self->priv->projector->image_ready (self, self->priv->current_pixbuf);
 }
 
 
@@ -268,6 +271,7 @@ gth_slideshow_init (GthSlideshow *self)
 	self->priv->animating = FALSE;
 	self->priv->direction = GTH_SLIDESHOW_DIRECTION_FORWARD;
 	self->priv->random_order = FALSE;
+	self->priv->current_pixbuf = NULL;
 
 	self->priv->preloader = gth_image_preloader_new (GTH_LOAD_POLICY_ONE_STEP, 3);
 	g_signal_connect (self->priv->preloader,
@@ -287,6 +291,7 @@ gth_slideshow_finalize (GObject *object)
 	if (self->priv->hide_cursor_event != 0)
 		g_source_remove (self->priv->hide_cursor_event);
 
+	_g_object_unref (self->priv->current_pixbuf);
 	_g_object_list_unref (self->priv->file_list);
 	_g_object_unref (self->priv->browser);
 	_g_object_unref (self->priv->preloader);
@@ -955,8 +960,6 @@ gth_slideshow_size_allocate_cb (GtkWidget     *widget,
 {
 	GthSlideshow   *self = user_data;
 	gfloat          stage_w, stage_h;
-	GthImageLoader *image_loader;
-	GdkPixbuf      *pixbuf;
 	GdkPixbuf      *image;
 	int             pixbuf_w, pixbuf_h;
 	int             pixbuf_x, pixbuf_y;
@@ -969,28 +972,23 @@ gth_slideshow_size_allocate_cb (GtkWidget     *widget,
 	if ((stage_w == 0) || (stage_h == 0))
 		return;
 
-	image_loader = gth_image_preloader_get_loader (self->priv->preloader, (GthFileData *) self->priv->current->data);
-	if (image_loader == NULL)
-		return;
-
-	pixbuf = gth_image_loader_get_pixbuf (image_loader);
-	if (pixbuf == NULL)
+	if (self->priv->current_pixbuf == NULL)
 		return;
 
-	image = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
+	image = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (self->priv->current_pixbuf),
 				FALSE,
-				gdk_pixbuf_get_bits_per_sample (pixbuf),
+				gdk_pixbuf_get_bits_per_sample (self->priv->current_pixbuf),
 				stage_w,
 				stage_h);
 	gdk_pixbuf_fill (image, 0x000000ff);
 
-	pixbuf_w = gdk_pixbuf_get_width (pixbuf);
-	pixbuf_h = gdk_pixbuf_get_height (pixbuf);
+	pixbuf_w = gdk_pixbuf_get_width (self->priv->current_pixbuf);
+	pixbuf_h = gdk_pixbuf_get_height (self->priv->current_pixbuf);
 	scale_keeping_ratio (&pixbuf_w, &pixbuf_h, (int) stage_w, (int) stage_h, TRUE);
 	pixbuf_x = (stage_w - pixbuf_w) / 2;
 	pixbuf_y = (stage_h - pixbuf_h) / 2;
 
-	gdk_pixbuf_composite (pixbuf,
+	gdk_pixbuf_composite (self->priv->current_pixbuf,
 			      image,
 			      pixbuf_x,
 			      pixbuf_y,
@@ -998,8 +996,8 @@ gth_slideshow_size_allocate_cb (GtkWidget     *widget,
 			      pixbuf_h,
 			      pixbuf_x,
 			      pixbuf_y,
-			      (double) pixbuf_w / gdk_pixbuf_get_width (pixbuf),
-			      (double) pixbuf_h / gdk_pixbuf_get_height (pixbuf),
+			      (double) pixbuf_w / gdk_pixbuf_get_width (self->priv->current_pixbuf),
+			      (double) pixbuf_h / gdk_pixbuf_get_height (self->priv->current_pixbuf),
 			      GDK_INTERP_BILINEAR,
 			      255);
 
diff --git a/extensions/webalbums/gth-web-exporter.c b/extensions/webalbums/gth-web-exporter.c
index 9a8978f..f9d6bec 100644
--- a/extensions/webalbums/gth-web-exporter.c
+++ b/extensions/webalbums/gth-web-exporter.c
@@ -2554,16 +2554,37 @@ create_squared_thumbnail (GdkPixbuf     *p,
 }
 
 
+static int
+image_data_cmp (gconstpointer a,
+		gconstpointer b,
+		gpointer      user_data)
+{
+	GthWebExporter *self = user_data;
+	ImageData      *idata_a = (ImageData *) a;
+	ImageData      *idata_b = (ImageData *) b;
+
+	return self->priv->sort_type->cmp_func (idata_a->file_data, idata_b->file_data);
+}
+
+
 static void
-image_loader_ready_cb (GthImageLoader *iloader,
-		       GError         *error,
-		       gpointer        data)
+image_loader_ready_cb (GObject      *source_object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
 {
-	GthWebExporter *self = data;
+	GthWebExporter *self = user_data;
 	ImageData      *idata;
 	GdkPixbuf      *pixbuf;
 
-	if (error != NULL) {
+	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
+						  result,
+						  NULL,
+						  NULL,
+						  &pixbuf,
+						  NULL,
+						  NULL,
+						  NULL))
+	{
 		load_next_file (self);
 		return;
 	}
@@ -2572,7 +2593,7 @@ image_loader_ready_cb (GthImageLoader *iloader,
 
 	/* image */
 
-	idata->image = pixbuf = g_object_ref (gth_image_loader_get_pixbuf (iloader));
+	idata->image = g_object_ref (pixbuf);
 	if (self->priv->copy_images && self->priv->resize_images) {
 		int w = gdk_pixbuf_get_width (pixbuf);
 		int h = gdk_pixbuf_get_height (pixbuf);
@@ -2594,7 +2615,7 @@ image_loader_ready_cb (GthImageLoader *iloader,
 
 	/* preview */
 
-	idata->preview = pixbuf = g_object_ref (gth_image_loader_get_pixbuf (iloader));
+	idata->preview = g_object_ref (pixbuf);
 	if ((self->priv->preview_max_width > 0) && (self->priv->preview_max_height > 0)) {
 		int w = gdk_pixbuf_get_width (pixbuf);
 		int h = gdk_pixbuf_get_height (pixbuf);
@@ -2626,7 +2647,7 @@ image_loader_ready_cb (GthImageLoader *iloader,
 
 	/* thumbnail. */
 
-	idata->thumb = pixbuf = gth_image_loader_get_pixbuf (iloader);
+	idata->thumb = g_object_ref (pixbuf);
 	g_object_ref (idata->thumb);
 
 	if ((self->priv->thumb_width > 0) && (self->priv->thumb_height > 0)) {
@@ -2691,19 +2712,8 @@ image_loader_ready_cb (GthImageLoader *iloader,
 	}
 	else
 		self->priv->saving_timeout = g_idle_add (save_image_preview, self);
-}
-
-
-static int
-image_data_cmp (gconstpointer a,
-		gconstpointer b,
-		gpointer      user_data)
-{
-	GthWebExporter *self = user_data;
-	ImageData      *idata_a = (ImageData *) a;
-	ImageData      *idata_b = (ImageData *) b;
 
-	return self->priv->sort_type->cmp_func (idata_a->file_data, idata_b->file_data);
+	g_object_unref (pixbuf);
 }
 
 
@@ -2727,8 +2737,13 @@ load_current_file (GthWebExporter *self)
 			   g_file_info_get_display_name (file_data->info),
 			   FALSE,
 			   (double) (self->priv->image + 1) / (self->priv->n_images + 1));
-	gth_image_loader_set_file_data (self->priv->iloader, file_data);
-	gth_image_loader_load (self->priv->iloader);
+
+	gth_image_loader_load (self->priv->iloader,
+			       file_data,
+			       -1,
+			       gth_task_get_cancellable (GTH_TASK (self)),
+			       image_loader_ready_cb,
+			       self);
 }
 
 
@@ -3186,13 +3201,7 @@ gth_web_exporter_init (GthWebExporter *self)
 	self->priv->file_list = NULL;
 	self->priv->tmp_dir = NULL;
 	self->priv->interrupted = FALSE;
-
-	self->priv->iloader = gth_image_loader_new (FALSE);
-	g_signal_connect (G_OBJECT (self->priv->iloader),
-			  "ready",
-			  G_CALLBACK (image_loader_ready_cb),
-			  self);
-
+	self->priv->iloader = gth_image_loader_new (NULL, NULL);
 	self->priv->error = NULL;
 }
 
diff --git a/gthumb/gth-file-list.c b/gthumb/gth-file-list.c
index b7341aa..5f34680 100644
--- a/gthumb/gth-file-list.c
+++ b/gthumb/gth-file-list.c
@@ -77,6 +77,7 @@ typedef struct {
 				  * image. */
 	guint thumb_created : 1; /* Whether a thumb has been
 				  * created for this image. */
+	GdkPixbuf *pixbuf;
 } ThumbData;
 
 
@@ -122,6 +123,8 @@ struct _GthFileListPrivateData
 
 	char           **caption_attributes_v;
 
+	gboolean         can_cancel;
+	GCancellable    *cancellable;
 	DataFunc         done_func;
 	gpointer         done_func_data;
 };
@@ -248,10 +251,12 @@ gth_file_list_finalize (GObject *object)
 	file_list = GTH_FILE_LIST (object);
 
 	if (file_list->priv != NULL) {
+		g_object_unref (file_list->priv->cancellable);
 		g_hash_table_unref (file_list->priv->thumb_data);
 		if (file_list->priv->icon_cache != NULL)
 			gth_icon_cache_free (file_list->priv->icon_cache);
 		g_strfreev (file_list->priv->caption_attributes_v);
+
 		g_free (file_list->priv);
 		file_list->priv = NULL;
 	}
@@ -340,6 +345,7 @@ thumb_data_unref (ThumbData *data)
 	data->ref--;
 	if (data->ref > 0)
 		return;
+	_g_object_unref (data->pixbuf);
 	g_free (data);
 }
 
@@ -354,6 +360,8 @@ gth_file_list_init (GthFileList *file_list)
 	file_list->priv->ignore_hidden_thumbs = FALSE;
 	file_list->priv->load_thumbs = TRUE;
 	file_list->priv->caption_attributes_v = g_strsplit ("none", ",", -1);
+	file_list->priv->cancellable = g_cancellable_new ();
+	file_list->priv->can_cancel = FALSE;
 }
 
 
@@ -361,124 +369,6 @@ static void _gth_file_list_update_next_thumb (GthFileList *file_list);
 
 
 static void
-flash_queue (GthFileList *file_list)
-{
-	if (file_list->priv->dirty) {
-		GthFileStore *file_store;
-
-		file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
-		gth_file_store_exec_set (file_store);
-		file_list->priv->dirty = FALSE;
-	}
-
-	if (file_list->priv->dirty_event != 0) {
-		g_source_remove (file_list->priv->dirty_event);
-		file_list->priv->dirty_event = 0;
-	}
-}
-
-
-static gboolean
-flash_queue_cb (gpointer data)
-{
-	flash_queue ((GthFileList *) data);
-	return FALSE;
-}
-
-
-static void
-queue_flash_updates (GthFileList *file_list)
-{
-	file_list->priv->dirty = TRUE;
-	if (file_list->priv->dirty_event == 0)
-		file_list->priv->dirty_event = g_timeout_add (UPDATE_THUMBNAILS_TIMEOUT, flash_queue_cb, file_list);
-}
-
-
-static void
-update_thumb_in_file_view (GthFileList *file_list)
-{
-	GthFileStore *file_store;
-	GdkPixbuf    *pixbuf;
-
-	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
-
-	pixbuf = gth_thumb_loader_get_pixbuf (file_list->priv->thumb_loader);
-	if (pixbuf != NULL) {
-		GtkTreeIter iter;
-
-		if (gth_file_store_get_nth_visible (file_store, file_list->priv->thumb_pos, &iter)) {
-			gth_file_store_queue_set (file_store,
-						  &iter,
-						  GTH_FILE_STORE_THUMBNAIL_COLUMN, pixbuf,
-						  GTH_FILE_STORE_IS_ICON_COLUMN, FALSE,
-						  -1);
-			queue_flash_updates (file_list);
-		}
-	}
-}
-
-
-static void
-set_mime_type_icon (GthFileList *file_list,
-		    GthFileData *file_data)
-{
-	GthFileStore *file_store;
-	GtkTreeIter   iter;
-	GIcon        *icon;
-	GdkPixbuf    *pixbuf;
-
-	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
-
-	if (! gth_file_store_find (file_store, file_data->file, &iter))
-		return;
-
-	icon = g_file_info_get_icon (file_data->info);
-	pixbuf = gth_icon_cache_get_pixbuf (file_list->priv->icon_cache, icon);
-	gth_file_store_queue_set (file_store,
-				  &iter,
-				  GTH_FILE_STORE_THUMBNAIL_COLUMN, pixbuf,
-				  GTH_FILE_STORE_IS_ICON_COLUMN, TRUE,
-				  -1);
-	queue_flash_updates (file_list);
-
-	_g_object_unref (pixbuf);
-}
-
-
-static void
-thumb_loader_ready_cb (GthThumbLoader *tloader,
-		       GError         *error,
-		       gpointer        data)
-{
-	GthFileList *file_list = data;
-
-	if (file_list->priv->thumb_fd != NULL) {
-		ThumbData *thumb_data;
-
-		thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_list->priv->thumb_fd->file);
-		if (error == NULL) {
-			thumb_data->error = FALSE;
-			thumb_data->thumb_created = TRUE;
-			if (file_list->priv->update_thumb_in_view) {
-				thumb_data->thumb_loaded = TRUE;
-				update_thumb_in_file_view (file_list);
-			}
-		}
-		else {
-			thumb_data->error = TRUE;
-			thumb_data->thumb_loaded = FALSE;
-			thumb_data->thumb_created = FALSE;
-			if (file_list->priv->update_thumb_in_view)
-				set_mime_type_icon (file_list, file_list->priv->thumb_fd);
-		}
-	}
-
-	_gth_file_list_update_next_thumb (file_list);
-}
-
-
-static void
 start_update_next_thumb (GthFileList *file_list)
 {
 	GthFileStore *file_store;
@@ -617,16 +507,7 @@ gth_file_list_construct (GthFileList     *file_list,
 	GtkCellRenderer *renderer;
 	GthFileStore    *model;
 
-	/* thumbnail loader */
-
 	file_list->priv->thumb_loader = gth_thumb_loader_new (file_list->priv->thumb_size);
-	g_signal_connect (G_OBJECT (file_list->priv->thumb_loader),
-			  "ready",
-			  G_CALLBACK (thumb_loader_ready_cb),
-			  file_list);
-
-	/* other data */
-
 	file_list->priv->icon_cache = gth_icon_cache_new (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (file_list))), file_list->priv->thumb_size / 2);
 
 	/* the main notebook */
@@ -831,18 +712,7 @@ _gth_file_list_done (GthFileList *file_list)
 	_gth_file_list_thumb_cleanup (file_list);
 	file_list->priv->loading_thumbs = FALSE;
 	file_list->priv->cancel = FALSE;
-}
-
-
-static void
-cancel_step2 (gpointer user_data)
-{
-	GthFileList *file_list = user_data;
-
-	_gth_file_list_done (file_list);
-
-	if (file_list->priv->done_func)
-		(file_list->priv->done_func) (file_list->priv->done_func_data);
+	g_cancellable_reset (file_list->priv->cancellable);
 }
 
 
@@ -855,7 +725,13 @@ gth_file_list_cancel (GthFileList *file_list,
 
 	file_list->priv->done_func = done_func;
 	file_list->priv->done_func_data = user_data;
-	gth_thumb_loader_cancel (file_list->priv->thumb_loader, cancel_step2, file_list);
+
+	if (file_list->priv->can_cancel) {
+		g_cancellable_cancel (file_list->priv->cancellable);
+		file_list->priv->can_cancel = FALSE;
+	}
+	else
+		call_when_idle (done_func, user_data);
 }
 
 
@@ -1381,10 +1257,151 @@ gth_file_list_get_vadjustment (GthFileList *file_list)
 
 
 static void
-_gth_file_list_thumbs_completed (GthFileList *file_list)
+flash_queue (GthFileList *file_list)
 {
-	flash_queue (file_list);
-	_gth_file_list_done (file_list);
+	if (file_list->priv->dirty) {
+		GthFileStore *file_store;
+
+		file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
+		gth_file_store_exec_set (file_store);
+		file_list->priv->dirty = FALSE;
+	}
+
+	if (file_list->priv->dirty_event != 0) {
+		g_source_remove (file_list->priv->dirty_event);
+		file_list->priv->dirty_event = 0;
+	}
+}
+
+
+static gboolean
+flash_queue_cb (gpointer data)
+{
+	flash_queue ((GthFileList *) data);
+	return FALSE;
+}
+
+
+static void
+queue_flash_updates (GthFileList *file_list)
+{
+	file_list->priv->dirty = TRUE;
+	if (file_list->priv->dirty_event == 0)
+		file_list->priv->dirty_event = g_timeout_add (UPDATE_THUMBNAILS_TIMEOUT, flash_queue_cb, file_list);
+}
+
+
+static void
+update_thumb_in_file_view (GthFileList *file_list,
+		    	   GthFileData *file_data)
+{
+	GthFileStore *file_store;
+	GtkTreeIter   iter;
+	ThumbData    *thumb_data;
+
+	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
+	if (! gth_file_store_find (file_store, file_data->file, &iter))
+		return;
+
+	thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
+	if (thumb_data == NULL)
+		return;
+
+	if (thumb_data->pixbuf == NULL)
+		return;
+
+	gth_file_store_queue_set (file_store,
+				  &iter,
+				  GTH_FILE_STORE_THUMBNAIL_COLUMN, thumb_data->pixbuf,
+				  GTH_FILE_STORE_IS_ICON_COLUMN, FALSE,
+				  -1);
+	queue_flash_updates (file_list);
+}
+
+
+static void
+set_mime_type_icon (GthFileList *file_list,
+		    GthFileData *file_data)
+{
+	GthFileStore *file_store;
+	GtkTreeIter   iter;
+	GIcon        *icon;
+	GdkPixbuf    *pixbuf;
+
+	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
+	if (! gth_file_store_find (file_store, file_data->file, &iter))
+		return;
+
+	icon = g_file_info_get_icon (file_data->info);
+	pixbuf = gth_icon_cache_get_pixbuf (file_list->priv->icon_cache, icon);
+	gth_file_store_queue_set (file_store,
+				  &iter,
+				  GTH_FILE_STORE_THUMBNAIL_COLUMN, pixbuf,
+				  GTH_FILE_STORE_IS_ICON_COLUMN, TRUE,
+				  -1);
+	queue_flash_updates (file_list);
+
+	_g_object_unref (pixbuf);
+}
+
+
+static void
+thumb_loader_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
+{
+	GthFileList *file_list = user_data;
+	ThumbData   *thumb_data;
+	GthFileData *file_data;
+	GdkPixbuf   *pixbuf;
+	GError      *error = NULL;
+
+	file_list->priv->can_cancel = FALSE;
+
+	if (file_list->priv->thumb_fd == NULL) {
+		_gth_file_list_update_next_thumb (file_list);
+		return;
+	}
+
+	thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_list->priv->thumb_fd->file);
+	if (thumb_data == NULL) {
+		_gth_file_list_update_next_thumb (file_list);
+		return;
+	}
+
+	_g_object_unref (thumb_data->pixbuf);
+	thumb_data->pixbuf = NULL;
+
+	if (! gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object),
+					    result,
+					    &file_data,
+					    &pixbuf,
+					    &error))
+	{
+		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+			_gth_file_list_done (file_list);
+			if (file_list->priv->done_func)
+				(file_list->priv->done_func) (file_list->priv->done_func_data);
+			return;
+		}
+
+		thumb_data->error = TRUE;
+		thumb_data->thumb_loaded = FALSE;
+		thumb_data->thumb_created = FALSE;
+		if (file_list->priv->update_thumb_in_view)
+			set_mime_type_icon (file_list, file_list->priv->thumb_fd);
+	}
+	else {
+		thumb_data->error = FALSE;
+		thumb_data->thumb_created = TRUE;
+		thumb_data->pixbuf = pixbuf;
+		if (file_list->priv->update_thumb_in_view) {
+			thumb_data->thumb_loaded = TRUE;
+			update_thumb_in_file_view (file_list, file_list->priv->thumb_fd);
+		}
+	}
+
+	_gth_file_list_update_next_thumb (file_list);
 }
 
 
@@ -1420,8 +1437,21 @@ static void
 _gth_file_list_update_current_thumb (GthFileList *file_list)
 {
 	set_loading_icon (file_list, file_list->priv->thumb_fd);
-	gth_thumb_loader_set_file (file_list->priv->thumb_loader, file_list->priv->thumb_fd);
-	gth_thumb_loader_load (file_list->priv->thumb_loader);
+
+	file_list->priv->can_cancel = TRUE;
+	gth_thumb_loader_load (file_list->priv->thumb_loader,
+			       file_list->priv->thumb_fd,
+			       file_list->priv->cancellable,
+			       thumb_loader_ready_cb,
+			       file_list);
+}
+
+
+static void
+_gth_file_list_thumbs_completed (GthFileList *file_list)
+{
+	flash_queue (file_list);
+	_gth_file_list_done (file_list);
 }
 
 
diff --git a/gthumb/gth-file-properties.c b/gthumb/gth-file-properties.c
index f18d98a..ae03162 100644
--- a/gthumb/gth-file-properties.c
+++ b/gthumb/gth-file-properties.c
@@ -92,8 +92,8 @@ gth_file_properties_real_set_file (GthPropertyView *base,
 {
 	GthFileProperties *self;
 	GHashTable        *category_hash;
-	GPtrArray         *metadata_info;
-	int                i;
+	GList             *metadata_info;
+	GList             *scan;
 	GtkTextBuffer     *text_buffer;
 	char              *comment;
 
@@ -107,14 +107,13 @@ gth_file_properties_real_set_file (GthPropertyView *base,
 
 	category_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
 	metadata_info = gth_main_get_all_metadata_info ();
-	for (i = 0; i < metadata_info->len; i++) {
-		GthMetadataInfo     *info;
+	for (scan = metadata_info; scan; scan = scan->next) {
+		GthMetadataInfo     *info = scan->data;
 		char                *value;
 		char                *tooltip;
 		GthMetadataCategory *category;
 		GtkTreeIter          iter;
 
-		info = g_ptr_array_index (metadata_info, i);
 		if ((info->flags & GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW) != GTH_METADATA_ALLOW_IN_PROPERTIES_VIEW)
 			continue;
 
@@ -163,6 +162,7 @@ gth_file_properties_real_set_file (GthPropertyView *base,
 		g_free (tooltip);
 		g_free (value);
 	}
+	g_list_free (metadata_info);
 
 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->priv->tree_model), POS_COLUMN, GTK_SORT_ASCENDING);
 	gtk_tree_view_expand_all (GTK_TREE_VIEW (self->priv->tree_view));
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index 5ae3106..c047ddb 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -24,329 +24,49 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gtk/gtk.h>
 #include "gth-file-data.h"
-#include "glib-utils.h"
-#include "gth-error.h"
 #include "gth-image-loader.h"
 #include "gth-main.h"
 
-/*
-#include "file-utils.h"
-#include "glib-utils.h"
-#include "gconf-utils.h"
-#include "gth-exif-utils.h"
-#include "pixbuf-utils.h"
-#include "preferences.h"
-*/
-
-#define REFRESH_RATE 5
-#define GTH_IMAGE_LOADER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTH_TYPE_IMAGE_LOADER, GthImageLoaderPrivate))
-G_LOCK_DEFINE_STATIC (pixbuf_loader_lock);
-
 
 struct _GthImageLoaderPrivate {
-	GthFileData        *file;
-	int                 requested_size;
-	GdkPixbuf          *pixbuf;
-	GdkPixbufAnimation *animation;
-	int                 original_width;
-	int                 original_height;
-
-	gboolean            as_animation; /* Whether to load the image in a
-					   * GdkPixbufAnimation structure. */
-	gboolean            ready;
-	GError             *error;
-	gboolean            loader_ready;
-	gboolean            cancelled;
-	gboolean            loading;
-	gboolean            emit_signal;
-
-	DataFunc            done_func;
-	gpointer            done_func_data;
-
-	guint               check_id;
-	guint               idle_id;
-
-	GThread            *thread;
-
-	GMutex             *data_mutex;
-
-	gboolean            exit_thread;
-	GMutex             *exit_thread_mutex;
-
-	gboolean            start_loading;
-	GMutex             *start_loading_mutex;
-	GCond              *start_loading_cond;
-
-	PixbufLoader        loader;
-	gpointer            loader_data;
-	GCancellable       *cancellable;
-};
-
-
-enum {
-	READY,
-	LAST_SIGNAL
+	gboolean     as_animation;  /* Whether to load the image in a
+				     * GdkPixbufAnimation structure. */
+	PixbufLoader loader_func;
+	gpointer     loader_data;
 };
 
 
 static gpointer parent_class = NULL;
-static guint gth_image_loader_signals[LAST_SIGNAL] = { 0 };
-
-
-static void
-gth_image_loader_finalize__step2 (GObject *object)
-{
-	GthImageLoader *self;
-
-	self = GTH_IMAGE_LOADER (object);
-
-	g_mutex_lock (self->priv->data_mutex);
-	if (self->priv->file != NULL) {
-		g_object_unref (self->priv->file);
-		self->priv->file = NULL;
-	}
-	if (self->priv->pixbuf != NULL) {
-		g_object_unref (G_OBJECT (self->priv->pixbuf));
-		self->priv->pixbuf = NULL;
-	}
-
-	if (self->priv->animation != NULL) {
-		g_object_unref (G_OBJECT (self->priv->animation));
-		self->priv->animation = NULL;
-	}
-	g_mutex_unlock (self->priv->data_mutex);
-
-	g_mutex_lock (self->priv->exit_thread_mutex);
-	self->priv->exit_thread = TRUE;
-	g_mutex_unlock (self->priv->exit_thread_mutex);
-
-	g_mutex_lock (self->priv->start_loading_mutex);
-	self->priv->start_loading = TRUE;
-	g_cond_signal (self->priv->start_loading_cond);
-	g_mutex_unlock (self->priv->start_loading_mutex);
-
-	g_thread_join (self->priv->thread);
-
-	g_cond_free  (self->priv->start_loading_cond);
-	g_mutex_free (self->priv->data_mutex);
-	g_mutex_free (self->priv->start_loading_mutex);
-	g_mutex_free (self->priv->exit_thread_mutex);
-
-	g_object_unref (self->priv->cancellable);
-
-	/* Chain up */
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-
-static void _gth_image_loader_stop (GthImageLoader *self,
-				    DataFunc        done_func,
-				    gpointer        done_func_data,
-				    gboolean        emit_sig,
-				    gboolean        use_idle_cb);
 
 
 static void
 gth_image_loader_finalize (GObject *object)
 {
-	GthImageLoader *self;
-
-	g_return_if_fail (object != NULL);
-	g_return_if_fail (GTH_IS_IMAGE_LOADER (object));
-
-	self = GTH_IMAGE_LOADER (object);
-
-	if (self->priv->idle_id != 0) {
-		g_source_remove (self->priv->idle_id);
-		self->priv->idle_id = 0;
-	}
-
-	if (self->priv->check_id != 0) {
-		g_source_remove (self->priv->check_id);
-		self->priv->check_id = 0;
-	}
-
-	_gth_image_loader_stop (self,
-				(DataFunc) gth_image_loader_finalize__step2,
-				object,
-				FALSE,
-				FALSE);
+	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 
 static void
 gth_image_loader_class_init (GthImageLoaderClass *class)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (class);
+	GObjectClass *object_class;
 
 	parent_class = g_type_class_peek_parent (class);
 	g_type_class_add_private (class, sizeof (GthImageLoaderPrivate));
 
+	object_class = G_OBJECT_CLASS (class);
 	object_class->finalize = gth_image_loader_finalize;
 
-	gth_image_loader_signals[READY] =
-		g_signal_new ("ready",
-			      G_TYPE_FROM_CLASS (class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (GthImageLoaderClass, ready),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE,
-			      1,
-			      G_TYPE_POINTER);
-}
-
-
-static void *
-load_image_thread (void *thread_data)
-{
-	GthImageLoader     *self = thread_data;
-	GdkPixbufAnimation *animation;
-	GError             *error;
-
-	for (;;) {
-		GthFileData *file;
-		gboolean     exit_thread;
-		int          requested_size;
-		int          original_width;
-		int          original_height;
-
-		g_mutex_lock (self->priv->start_loading_mutex);
-		while (! self->priv->start_loading)
-			g_cond_wait (self->priv->start_loading_cond, self->priv->start_loading_mutex);
-		self->priv->start_loading = FALSE;
-		g_mutex_unlock (self->priv->start_loading_mutex);
-
-		g_mutex_lock (self->priv->exit_thread_mutex);
-		exit_thread = self->priv->exit_thread;
-		requested_size = self->priv->requested_size;
-		g_mutex_unlock (self->priv->exit_thread_mutex);
-
-		if (exit_thread)
-			break;
-
-		file = gth_image_loader_get_file (self);
-
-		G_LOCK (pixbuf_loader_lock);
-
-		original_width = -1;
-		original_height = -1;
-		animation = NULL;
-		if (file != NULL) {
-			error = NULL;
-			if (self->priv->loader != NULL) {
-				animation = (*self->priv->loader) (file,
-								      requested_size,
-								      &original_width,
-								      &original_height,
-								      self->priv->loader_data,
-								      self->priv->cancellable,
-								      &error);
-			}
-			else  {
-				PixbufLoader loader;
-
-				loader = gth_main_get_pixbuf_loader (gth_file_data_get_mime_type (file));
-				if (loader != NULL)
-					animation = loader (file,
-							    requested_size,
-							    &original_width,
-							    &original_height,
-							    NULL,
-							    self->priv->cancellable,
-							    &error);
-				else
-					error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("No suitable loader available for this file type"));
-			}
-		}
-
-		G_UNLOCK (pixbuf_loader_lock);
-
-		g_mutex_lock (self->priv->data_mutex);
-
-		self->priv->loader_ready = TRUE;
-
-		if ((animation == NULL) || (error != NULL)) {
-			self->priv->error = error;
-			self->priv->ready = FALSE;
-		}
-		else if ((self->priv->file != NULL)
-			 && _g_file_equal_uris (file->file, self->priv->file->file)
-			 && (requested_size == self->priv->requested_size))
-		{
-			_g_object_unref (self->priv->animation);
-			self->priv->animation = g_object_ref (animation);
-			self->priv->original_width = original_width;
-			self->priv->original_height = original_height;
-
-			self->priv->error = NULL;
-			self->priv->ready = TRUE;
-		}
-
-		_g_object_unref (animation);
-
-		g_mutex_unlock (self->priv->data_mutex);
-
-		g_object_unref (file);
-	}
-
-	return NULL;
 }
 
 
 static void
 gth_image_loader_init (GthImageLoader *self)
 {
-	self->priv = GTH_IMAGE_LOADER_GET_PRIVATE (self);
-
-	self->priv->pixbuf = NULL;
-	self->priv->animation = NULL;
-	self->priv->file = NULL;
-	self->priv->requested_size = -1;
-
-	self->priv->ready = FALSE;
-	self->priv->error = NULL;
-	self->priv->loader_ready = FALSE;
-	self->priv->cancelled = FALSE;
-
-	self->priv->done_func = NULL;
-	self->priv->done_func_data = NULL;
-
-	self->priv->check_id = 0;
-	self->priv->idle_id = 0;
-
-	self->priv->data_mutex = g_mutex_new ();
-
-	self->priv->exit_thread = FALSE;
-	self->priv->exit_thread_mutex = g_mutex_new ();
-
-	self->priv->start_loading = FALSE;
-	self->priv->start_loading_mutex = g_mutex_new ();
-	self->priv->start_loading_cond = g_cond_new ();
-
-	self->priv->loader = NULL;
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_IMAGE_LOADER, GthImageLoaderPrivate);
+	self->priv->as_animation = FALSE;
+	self->priv->loader_func = NULL;
 	self->priv->loader_data = NULL;
-
-	self->priv->cancellable = g_cancellable_new ();
-
-	/*self->priv->thread = g_thread_create (load_image_thread, self, TRUE, NULL);*/
-
-	/* The g_thread_create function assigns a very large default stacksize for each
-	   thread (10 MB on FC6), which is probably excessive. 16k seems to be
-	   sufficient. To be conversative, we'll try 32k. Use g_thread_create_full to
-	   manually specify a small stack size. See Bug 310749 - Memory usage.
-	   This reduces the virtual memory requirements, and the "writeable/private"
-	   figure reported by "pmap -d". */
-
-	/* Update: 32k caused crashes with svg images. Boosting to 512k. Bug 410827. */
-
-	self->priv->thread = g_thread_create_full (load_image_thread,
-						      self,
-						      (512 * 1024),
-						      TRUE,
-						      TRUE,
-						      G_THREAD_PRIORITY_NORMAL,
-						      NULL);
 }
 
 
@@ -379,399 +99,219 @@ gth_image_loader_get_type (void)
 
 
 GthImageLoader *
-gth_image_loader_new (gboolean as_animation)
+gth_image_loader_new (PixbufLoader loader_func,
+		      gpointer     loader_data)
 {
 	GthImageLoader *self;
 
 	self = g_object_new (GTH_TYPE_IMAGE_LOADER, NULL);
-	g_mutex_lock (self->priv->data_mutex);
-	self->priv->as_animation = as_animation;
-	g_mutex_unlock (self->priv->data_mutex);
+	gth_image_loader_set_loader_func (self, loader_func, loader_data);
 
 	return self;
 }
 
 
 void
-gth_image_loader_set_loader (GthImageLoader *self,
-			     PixbufLoader    loader,
-			     gpointer        loader_data)
+gth_image_loader_set_loader_func (GthImageLoader *self,
+				  PixbufLoader    loader_func,
+				  gpointer        loader_data)
 {
 	g_return_if_fail (self != NULL);
 
-	g_mutex_lock (self->priv->data_mutex);
-	self->priv->loader = loader;
+	self->priv->loader_func = loader_func;
 	self->priv->loader_data = loader_data;
-	g_mutex_unlock (self->priv->data_mutex);
 }
 
 
-void
-gth_image_loader_set_file_data (GthImageLoader *self,
-				GthFileData    *file)
-{
-	g_mutex_lock (self->priv->data_mutex);
-	_g_object_unref (self->priv->file);
-	self->priv->file = NULL;
-	if (file != NULL)
-		self->priv->file = gth_file_data_dup (file);
-	g_mutex_unlock (self->priv->data_mutex);
-}
+typedef struct {
+	GthFileData *file_data;
+	int          requested_size;
+} LoadData;
 
 
-GthFileData *
-gth_image_loader_get_file (GthImageLoader *self)
+static LoadData *
+load_data_new (GthFileData *file_data,
+	       int          requested_size)
 {
-	GthFileData *file = NULL;
+	LoadData *load_data;
 
-	g_mutex_lock (self->priv->data_mutex);
-	if (self->priv->file != NULL)
-		file = gth_file_data_dup (self->priv->file);
-	g_mutex_unlock (self->priv->data_mutex);
+	load_data = g_new0 (LoadData, 1);
+	load_data->file_data = g_object_ref (file_data);
+	load_data->requested_size = requested_size;
 
-	return file;
-}
-
-
-void
-gth_image_loader_set_pixbuf (GthImageLoader *self,
-			     GdkPixbuf      *pixbuf)
-{
-	g_return_if_fail (self != NULL);
-
-	g_mutex_lock (self->priv->data_mutex);
-
-	if (self->priv->animation != NULL) {
-		g_object_unref (self->priv->animation);
-		self->priv->animation = NULL;
-	}
-
-	if (self->priv->pixbuf != NULL) {
-		g_object_unref (self->priv->pixbuf);
-		self->priv->pixbuf = NULL;
-	}
-
-	self->priv->pixbuf = pixbuf;
-	if (pixbuf != NULL)
-		g_object_ref (pixbuf);
-
-	g_mutex_unlock (self->priv->data_mutex);
+	return load_data;
 }
 
 
 static void
-_gth_image_loader_sync_pixbuf (GthImageLoader *self)
+load_data_unref (LoadData *load_data)
 {
-	GdkPixbuf *pixbuf;
-
-	g_mutex_lock (self->priv->data_mutex);
-
-	if (self->priv->animation == NULL) {
-		if (self->priv->pixbuf != NULL)
-			g_object_unref (self->priv->pixbuf);
-		self->priv->pixbuf = NULL;
-		g_mutex_unlock (self->priv->data_mutex);
-		return;
-	}
-
-	pixbuf = gdk_pixbuf_animation_get_static_image (self->priv->animation);
-	g_object_ref (pixbuf);
-
-	if (self->priv->pixbuf == pixbuf) {
-		g_object_unref (pixbuf);
-		g_mutex_unlock (self->priv->data_mutex);
-		return;
-	}
-
-	if (self->priv->pixbuf != NULL) {
-		g_object_unref (self->priv->pixbuf);
-		self->priv->pixbuf = NULL;
-	}
-
-	if (pixbuf != NULL) {
-		g_object_ref (pixbuf);
-		self->priv->pixbuf = pixbuf;
-	}
-
-	g_object_unref (pixbuf);
-
-	g_mutex_unlock (self->priv->data_mutex);
+	g_object_unref (load_data->file_data);
+	g_free (load_data);
 }
 
 
-static void
-_gth_image_loader_cancelled (GthImageLoader *self)
-{
-	g_mutex_lock (self->priv->data_mutex);
-	self->priv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "");
-	g_mutex_unlock (self->priv->data_mutex);
-
-	_gth_image_loader_stop (self,
-				self->priv->done_func,
-				self->priv->done_func_data,
-				TRUE,
-				TRUE);
-}
+typedef struct {
+	GthFileData        *file_data;
+	int                 requested_size;
+	GdkPixbufAnimation *animation;
+	int                 original_width;
+	int                 original_height;
+} LoadResult;
 
 
 static void
-_gth_image_loader_ready (GthImageLoader *self)
+load_result_unref (LoadResult *load_result)
 {
-	g_mutex_lock (self->priv->data_mutex);
-	self->priv->error = NULL;
-	g_mutex_unlock (self->priv->data_mutex);
-
-	_gth_image_loader_stop (self, NULL, NULL, TRUE, TRUE);
+	g_object_unref (load_result->file_data);
+	if (load_result->animation != NULL)
+		g_object_unref (load_result->animation);
+	g_free (load_result);
 }
 
 
 static void
-_gth_image_loader_error (GthImageLoader *self,
-			 GError         *error)
+load_pixbuf_thread (GSimpleAsyncResult *result,
+		    GObject            *object,
+		    GCancellable       *cancellable)
 {
-	g_mutex_lock (self->priv->data_mutex);
-
-	if (self->priv->error != error) {
-		if (self->priv->error != NULL) {
-			g_error_free (self->priv->error);
-			self->priv->error = NULL;
-		}
-		self->priv->error = error;
-	}
-
-	g_mutex_unlock (self->priv->data_mutex);
-
-	_gth_image_loader_stop (self, NULL, NULL, TRUE, TRUE);
-}
-
-
-static gboolean
-check_thread (gpointer data)
-{
-	GthImageLoader *self = data;
-	gboolean        ready, loader_done;
-	GError         *error = NULL;
-
-	/* Remove check. */
-
-	g_source_remove (self->priv->check_id);
-	self->priv->check_id = 0;
-
-	/**/
-
-	g_mutex_lock (self->priv->data_mutex);
-
-	ready = self->priv->ready;
-	if (self->priv->error != NULL)
-		error = g_error_copy (self->priv->error);
-	loader_done = self->priv->loader_ready;
-
-	g_mutex_unlock (self->priv->data_mutex);
-
-	/**/
-
-	if (loader_done && self->priv->cancelled)
-		_gth_image_loader_cancelled (self);
-
-	else if (loader_done && ready)
-		_gth_image_loader_ready (self);
-
-	else if (loader_done && (error != NULL))
-		_gth_image_loader_error (self, error);
-
-	else	/* Add the check again. */
-		self->priv->check_id = g_timeout_add (REFRESH_RATE, check_thread, self);
-
-	return FALSE;
-}
-
-
-static void
-_gth_image_loader_load__step2 (GthImageLoader *self)
-{
-	g_mutex_lock (self->priv->data_mutex);
-
-	self->priv->ready = FALSE;
-	self->priv->error = NULL;
-	self->priv->loader_ready = FALSE;
-	self->priv->loading = TRUE;
-	if (self->priv->pixbuf != NULL) {
-		g_object_unref (self->priv->pixbuf);
-		self->priv->pixbuf = NULL;
+	GthImageLoader     *self = GTH_IMAGE_LOADER (object);
+	LoadData           *load_data;
+	GdkPixbufAnimation *animation;
+	int                 original_width;
+	int                 original_height;
+	GError             *error = NULL;
+	LoadResult         *load_result;
+
+	load_data = g_simple_async_result_get_op_res_gpointer (result);
+	animation = NULL;
+	original_width = -1;
+	original_height = -1;
+
+	if (self->priv->loader_func != NULL) {
+		animation = (*self->priv->loader_func) (load_data->file_data,
+						        load_data->requested_size,
+						        &original_width,
+						        &original_height,
+						        self->priv->loader_data,
+						        cancellable,
+						        &error);
 	}
-	if (self->priv->animation != NULL) {
-		g_object_unref (self->priv->animation);
-		self->priv->animation = NULL;
+	else  {
+		PixbufLoader loader_func;
+
+		loader_func = gth_main_get_pixbuf_loader (gth_file_data_get_mime_type (load_data->file_data));
+		if (loader_func != NULL)
+			animation = loader_func (load_data->file_data,
+				        	 load_data->requested_size,
+				        	 &original_width,
+				        	 &original_height,
+				        	 NULL,
+				        	 cancellable,
+				        	 &error);
+		else
+			error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("No suitable loader available for this file type"));
 	}
-	g_cancellable_reset (self->priv->cancellable);
-
-	g_mutex_unlock (self->priv->data_mutex);
-
-	/**/
-
-	g_mutex_lock (self->priv->start_loading_mutex);
-
-	self->priv->start_loading = TRUE;
-	g_cond_signal (self->priv->start_loading_cond);
-
-	g_mutex_unlock (self->priv->start_loading_mutex);
 
-	/**/
+	load_result = g_new0 (LoadResult, 1);
+	load_result->file_data = g_object_ref (load_data->file_data);
+	load_result->requested_size = load_data->requested_size;
+	load_result->animation = animation;
+	load_result->original_width = original_width;
+	load_result->original_height = original_height;
 
-	self->priv->check_id = g_timeout_add (REFRESH_RATE,
-						 check_thread,
-						 self);
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (result, error);
+		g_error_free (error);
+	}
+	else
+		g_simple_async_result_set_op_res_gpointer (result, load_result, (GDestroyNotify) load_result_unref);
 }
 
 
 void
-gth_image_loader_load (GthImageLoader *self)
+gth_image_loader_load (GthImageLoader      *loader,
+		       GthFileData         *file_data,
+		       int                  requested_size,
+		       GCancellable        *cancellable,
+		       GAsyncReadyCallback  callback,
+		       gpointer             user_data)
 {
-	gth_image_loader_load_at_size (self, -1);
+	GSimpleAsyncResult *result;
+
+	result = g_simple_async_result_new (G_OBJECT (loader), callback, user_data, gth_image_loader_load);
+	g_simple_async_result_set_op_res_gpointer (result,
+						   load_data_new (file_data, requested_size),
+						   (GDestroyNotify) load_data_unref);
+	g_simple_async_result_run_in_thread (result,
+					     load_pixbuf_thread,
+					     G_PRIORITY_DEFAULT,
+					     cancellable);
+	g_object_unref (result);
 }
 
 
-void
-gth_image_loader_load_at_size (GthImageLoader *self,
-			       int             requested_size)
+gboolean
+gth_image_loader_load_animation_finish (GthImageLoader      *loader,
+					GAsyncResult        *result,
+					GthFileData        **file_data,
+					int                 *requested_size,
+					GdkPixbufAnimation **animation,
+					int                 *original_width,
+					int                 *original_height,
+					GError             **error)
 {
-	gboolean no_file = FALSE;
-
-	g_return_if_fail (self != NULL);
+	  GSimpleAsyncResult *simple;
+	  LoadResult         *load_result;
 
-	g_mutex_lock (self->priv->data_mutex);
-	if (self->priv->file == NULL)
-		no_file = TRUE;
-	self->priv->requested_size = requested_size;
-	g_mutex_unlock (self->priv->data_mutex);
-
-	if (no_file)
-		return;
-
-	_gth_image_loader_stop (self,
-				(DataFunc) _gth_image_loader_load__step2,
-				self,
-				FALSE,
-				TRUE);
-}
+	  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (loader), gth_image_loader_load), FALSE);
 
+	  simple = G_SIMPLE_ASYNC_RESULT (result);
 
+	  if (g_simple_async_result_propagate_error (simple, error))
+		  return FALSE;
 
-/* -- gth_image_loader_stop -- */
+	  load_result = g_simple_async_result_get_op_res_gpointer (simple);
+	  if (file_data != NULL)
+		  *file_data = g_object_ref (load_result->file_data);
+	  if (requested_size != NULL)
+	  	  *requested_size = load_result->requested_size;
+	  if (animation != NULL)
+		  *animation = g_object_ref (load_result->animation);
+	  if (original_width != NULL)
+	  	  *original_width = load_result->original_width;
+	  if (original_height != NULL)
+	  	  *original_height = load_result->original_height;
 
-
-static void
-_gth_image_loader_stop__step2 (GthImageLoader *self,
-			       gboolean        use_idle_cb)
-{
-	DataFunc  done_func;
-	GError   *error;
-
-	g_mutex_lock (self->priv->data_mutex);
-	error = self->priv->error;
-	self->priv->error = NULL;
-	self->priv->ready = TRUE;
-	g_mutex_unlock (self->priv->data_mutex);
-
-	if ((error == NULL) && ! self->priv->cancelled && self->priv->loading)
-		_gth_image_loader_sync_pixbuf (self);
-	self->priv->loading = FALSE;
-
-	done_func = self->priv->done_func;
-	self->priv->done_func = NULL;
-	if (done_func != NULL) {
-		IdleCall *call;
-
-		call = idle_call_new (done_func, self->priv->done_func_data);
-		if (self->priv->idle_id != 0)
-			g_source_remove (self->priv->idle_id);
-		self->priv->idle_id = idle_call_exec (call, use_idle_cb);
-	}
-
-	if (! self->priv->emit_signal || self->priv->cancelled) {
-		self->priv->cancelled = FALSE;
-		return;
-	}
-	self->priv->cancelled = FALSE;
-
-	g_signal_emit (G_OBJECT (self),
-		       gth_image_loader_signals[READY],
-		       0,
-		       error);
+	  return TRUE;
 }
 
 
-static void
-_gth_image_loader_stop (GthImageLoader *self,
-			DataFunc        done_func,
-			gpointer        done_func_data,
-			gboolean        emit_signal,
-			gboolean        use_idle_cb)
-{
-	self->priv->done_func = done_func;
-	self->priv->done_func_data = done_func_data;
-	self->priv->emit_signal = emit_signal;
-
-	_gth_image_loader_stop__step2 (self, use_idle_cb);
-}
-
-
-void
-gth_image_loader_cancel (GthImageLoader *self,
-			 DataFunc        done_func,
-			 gpointer        done_func_data)
-{
-	g_mutex_lock (self->priv->data_mutex);
-	self->priv->error = FALSE;
-	g_mutex_unlock (self->priv->data_mutex);
-
-	if (self->priv->loading) {
-		self->priv->emit_signal = TRUE;
-		self->priv->cancelled = TRUE;
-		self->priv->done_func = done_func;
-		self->priv->done_func_data = done_func_data;
-		g_cancellable_cancel (self->priv->cancellable);
-	}
-	else
-		_gth_image_loader_stop (self,
-					done_func,
-					done_func_data,
-					FALSE,
-					TRUE);
-}
-
-
-GdkPixbuf *
-gth_image_loader_get_pixbuf (GthImageLoader *self)
-{
-	return self->priv->pixbuf;
-}
-
-
-GdkPixbufAnimation *
-gth_image_loader_get_animation (GthImageLoader *self)
+gboolean
+gth_image_loader_load_image_finish (GthImageLoader  *loader,
+				    GAsyncResult    *res,
+				    GthFileData    **file_data,
+				    int             *requested_size,
+				    GdkPixbuf      **pixbuf,
+				    int             *original_width,
+				    int             *original_height,
+				    GError         **error)
 {
 	GdkPixbufAnimation *animation;
 
-	g_mutex_lock (self->priv->data_mutex);
-	animation = self->priv->animation;
-	if (animation != NULL)
-		g_object_ref (animation);
-	g_mutex_unlock (self->priv->data_mutex);
-
-	return animation;
-}
+	if (! gth_image_loader_load_animation_finish (loader,
+						      res,
+						      file_data,
+						      requested_size,
+						      &animation,
+						      original_width,
+						      original_height,
+						      error))
+	{
+		return FALSE;
+	}
 
+	*pixbuf = gdk_pixbuf_animation_get_static_image (animation);
 
-void
-gth_image_loader_get_original_size (GthImageLoader *self,
-				    int            *width,
-				    int            *height)
-{
-	g_mutex_lock (self->priv->data_mutex);
-	if (width != NULL)
-		*width = self->priv->original_width;
-	if (height != NULL)
-		*height = self->priv->original_height;
-	g_mutex_unlock (self->priv->data_mutex);
+	return TRUE;
 }
diff --git a/gthumb/gth-image-loader.h b/gthumb/gth-image-loader.h
index 36fff43..31d9c2b 100644
--- a/gthumb/gth-image-loader.h
+++ b/gthumb/gth-image-loader.h
@@ -3,7 +3,7 @@
 /*
  *  GThumb
  *
- *  Copyright (C) 2001-2008 The Free Software Foundation, Inc.
+ *  Copyright (C) 2001-2010 The Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -41,43 +41,43 @@ typedef struct _GthImageLoader        GthImageLoader;
 typedef struct _GthImageLoaderClass   GthImageLoaderClass;
 typedef struct _GthImageLoaderPrivate GthImageLoaderPrivate;
 
-struct _GthImageLoader
-{
+struct _GthImageLoader {
 	GObject __parent;
 	GthImageLoaderPrivate *priv;
 };
 
-struct _GthImageLoaderClass
-{
+struct _GthImageLoaderClass {
 	GObjectClass __parent_class;
-
-	/* -- Signals -- */
-
-	void (* ready) (GthImageLoader *iloader,
-			GError         *error);
 };
 
-GType                gth_image_loader_get_type                (void);
-GthImageLoader *     gth_image_loader_new                     (gboolean           as_animation);
-void                 gth_image_loader_set_loader              (GthImageLoader    *iloader,
-							       PixbufLoader       loader,
-						               gpointer           data);
-void                 gth_image_loader_set_file_data           (GthImageLoader    *iloader,
-						               GthFileData       *file);
-GthFileData *        gth_image_loader_get_file                (GthImageLoader    *iloader);
-void                 gth_image_loader_set_pixbuf              (GthImageLoader    *iloader,
-						               GdkPixbuf         *pixbuf);
-GdkPixbuf *          gth_image_loader_get_pixbuf              (GthImageLoader    *iloader);
-GdkPixbufAnimation * gth_image_loader_get_animation           (GthImageLoader    *iloader);
-void                 gth_image_loader_get_original_size       (GthImageLoader    *iloader,
-							       int               *width,
-							       int               *height);
-void                 gth_image_loader_load                    (GthImageLoader    *iloader);
-void                 gth_image_loader_load_at_size            (GthImageLoader    *iloader,
-							       int                requested_size);
-void                 gth_image_loader_cancel                  (GthImageLoader    *iloader,
-						               DataFunc           done_func,
-						               gpointer           done_func_data);
+GType             gth_image_loader_get_type               (void);
+GthImageLoader *  gth_image_loader_new                    (PixbufLoader          loader_func,
+							   gpointer              loader_data);
+void              gth_image_loader_set_loader_func        (GthImageLoader       *loader,
+							   PixbufLoader          loader_func,
+						           gpointer              loader_data);
+void              gth_image_loader_load                   (GthImageLoader       *loader,
+							   GthFileData          *file_data,
+							   int                   requested_size,
+							   GCancellable         *cancellable,
+							   GAsyncReadyCallback   callback,
+							   gpointer              user_data);
+gboolean          gth_image_loader_load_animation_finish  (GthImageLoader       *loader,
+							   GAsyncResult         *res,
+							   GthFileData         **file_data,
+							   int                  *requested_size,
+							   GdkPixbufAnimation  **animation,
+							   int                  *original_width,
+							   int                  *original_height,
+							   GError              **error);
+gboolean          gth_image_loader_load_image_finish      (GthImageLoader       *loader,
+						  	   GAsyncResult         *res,
+							   GthFileData         **file_data,
+							   int                  *requested_size,
+							   GdkPixbuf           **pixbuf,
+							   int                  *original_width,
+							   int                  *original_height,
+							   GError              **error);
 
 G_END_DECLS
 
diff --git a/gthumb/gth-image-preloader.c b/gthumb/gth-image-preloader.c
index 184c37a..314e255 100644
--- a/gthumb/gth-image-preloader.c
+++ b/gthumb/gth-image-preloader.c
@@ -41,12 +41,16 @@ enum {
 
 
 typedef struct {
+	GthImagePreloader  *self;
 	GthFileData        *file_data;
 	int                 requested_size;
-	GthImageLoader     *loader;
 	gboolean            loaded;
 	gboolean            error;
-	GthImagePreloader  *self;
+	GthImageLoader     *loader;
+	GdkPixbufAnimation *animation;
+	int                 original_width;
+	int                 original_height;
+	guint               token;
 } Preloader;
 
 
@@ -67,10 +71,11 @@ struct _GthImagePreloaderPrivate {
 					        * any signal. */
 	GFile        *requested_file;
 	int           requested_size;
-	GthFileData **files;
 	int           current;                 /* This is the loader that has
 					        * a loading underway. */
 	guint         load_id;
+	GCancellable *cancellable;
+	guint         token;
 };
 
 
@@ -80,89 +85,6 @@ static guint gth_image_preloader_signals[LAST_SIGNAL] = { 0 };
 
 /* -- Preloader -- */
 
-static void        start_next_loader   (GthImagePreloader *self);
-static Preloader * current_preloader   (GthImagePreloader *self);
-static Preloader * requested_preloader (GthImagePreloader *self);
-
-
-static gboolean
-load_next (gpointer data)
-{
-	GthImagePreloader *self = data;
-
-	if (self->priv->load_id != 0) {
-		g_source_remove (self->priv->load_id);
-		self->priv->load_id = 0;
-	}
-
-	start_next_loader (self);
-
-	return FALSE;
-}
-
-
-static gboolean
-preloader_need_second_step (Preloader *preloader)
-{
-	int                 original_width;
-	int                 original_height;
-	GdkPixbufAnimation *animation;
-
-	gth_image_loader_get_original_size (preloader->loader, &original_width, &original_height);
-	animation = gth_image_loader_get_animation (preloader->loader);
-
-	return (! preloader->error
-		&& (preloader->requested_size != -1)
-		&& ((original_width > preloader->requested_size) || (original_height > preloader->requested_size))
-		&& (animation != NULL)
-		&& gdk_pixbuf_animation_is_static_image (animation));
-}
-
-
-static void
-image_loader_ready_cb (GthImageLoader *iloader,
-		       GError         *error,
-		       Preloader      *preloader)
-{
-	GthImagePreloader *self = preloader->self;
-	int                interval = NEXT_LOAD_SMALL_TIMEOUT;
-
-	preloader->loaded = (error == NULL);
-	preloader->error  = (error != NULL);
-
-	g_object_ref (self);
-
-	if (_g_file_equal (preloader->file_data->file, self->priv->requested_file)) {
-#if DEBUG_PRELOADER
-		debug (DEBUG_INFO, "[requested] %s => %s [size: %d]", (error == NULL) ? "ready" : "error", g_file_get_uri (preloader->file_data->file), preloader->requested_size);
-#endif
-
-		g_signal_emit (G_OBJECT (self),
-			       gth_image_preloader_signals[REQUESTED_READY],
-			       0,
-			       preloader->file_data,
-			       preloader->loader,
-			       error);
-
-		/* Reload only if the original size is bigger then the
-		 * requested size, and if the image is not an animation. */
-
-		if ((self->priv->load_policy == GTH_LOAD_POLICY_TWO_STEPS)
-		    && preloader_need_second_step (preloader))
-		{
-			/* Reload the image at the original size */
-			preloader->loaded = FALSE;
-			preloader->requested_size = -1;
-		}
-
-		interval = NEXT_LOAD_BIG_TIMEOUT;
-	}
-
-	self->priv->load_id = g_timeout_add (interval, load_next, self);
-
-	g_object_unref (self);
-}
-
 
 static Preloader *
 preloader_new (GthImagePreloader *self)
@@ -170,16 +92,14 @@ preloader_new (GthImagePreloader *self)
 	Preloader *preloader;
 
 	preloader = g_new0 (Preloader, 1);
+	preloader->self = self;
 	preloader->file_data = NULL;
 	preloader->loaded = FALSE;
 	preloader->error = FALSE;
-	preloader->loader = GTH_IMAGE_LOADER (gth_image_loader_new (TRUE));
-	preloader->self = self;
-
-	g_signal_connect (G_OBJECT (preloader->loader),
-			  "ready",
-			  G_CALLBACK (image_loader_ready_cb),
-			  preloader);
+	preloader->loader = gth_image_loader_new (NULL, NULL);
+	preloader->animation = NULL;
+	preloader->original_width = -1;
+	preloader->original_height = -1;
 
 	return preloader;
 }
@@ -190,6 +110,7 @@ preloader_free (Preloader *preloader)
 {
 	if (preloader == NULL)
 		return;
+	_g_object_unref (preloader->animation);
 	_g_object_unref (preloader->loader);
 	_g_object_unref (preloader->file_data);
 	g_free (preloader);
@@ -207,16 +128,53 @@ preloader_set_file_data (Preloader    *preloader,
 		preloader->file_data = NULL;
 	}
 
-	if (file_data != NULL) {
+	if (file_data != NULL)
 		preloader->file_data = g_object_ref (file_data);
-		gth_image_loader_set_file_data (preloader->loader, preloader->file_data);
-	}
 
 	preloader->loaded = FALSE;
 	preloader->error = FALSE;
 }
 
 
+static gboolean
+preloader_has_valid_content_for_file (Preloader   *preloader,
+				      GthFileData *file_data)
+{
+	return ((preloader->file_data != NULL)
+		&& preloader->loaded
+		&& ! preloader->error
+		&& (preloader->animation != NULL)
+	        && g_file_equal (preloader->file_data->file, file_data->file)
+	        && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
+	        		     gth_file_data_get_modification_time (preloader->file_data)) == 0));
+}
+
+
+static gboolean
+preloader_needs_to_load (Preloader *preloader)
+{
+	return ((preloader->token == preloader->self->priv->token)
+		 && (preloader->file_data != NULL)
+		 && ! preloader->error
+		 && ! preloader->loaded);
+}
+
+
+static gboolean
+preloader_needs_second_step (Preloader *preloader)
+{
+	if (preloader->self->priv->load_policy != GTH_LOAD_POLICY_TWO_STEPS)
+		return FALSE;
+
+	return ((preloader->token == preloader->self->priv->token)
+		&& ! preloader->error
+		&& (preloader->requested_size != -1)
+		&& ((preloader->original_width > preloader->requested_size) || (preloader->original_height > preloader->requested_size))
+		&& (preloader->animation != NULL)
+		&& gdk_pixbuf_animation_is_static_image (preloader->animation));
+}
+
+
 /* -- GthImagePreloader -- */
 
 
@@ -241,18 +199,9 @@ gth_image_preloader_finalize (GObject *object)
 		self->priv->loader[i] = NULL;
 	}
 	g_free (self->priv->loader);
-	self->priv->loader = NULL;
-
 	_g_object_unref (self->priv->requested_file);
+	g_object_unref (self->priv->cancellable);
 
-	for (i = 0; i < self->priv->n_preloaders; i++) {
-		_g_object_unref (self->priv->files[i]);
-		self->priv->files[i] = NULL;
-	}
-	g_free (self->priv->files);
-	self->priv->files = NULL;
-
-	/* Chain up */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -271,11 +220,13 @@ gth_image_preloader_class_init (GthImagePreloaderClass *class)
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (GthImagePreloaderClass, requested_ready),
 			      NULL, NULL,
-			      gth_marshal_VOID__OBJECT_OBJECT_POINTER,
+			      gth_marshal_VOID__OBJECT_OBJECT_INT_INT_POINTER,
 			      G_TYPE_NONE,
-			      3,
+			      5,
 			      G_TYPE_OBJECT,
 			      G_TYPE_OBJECT,
+			      G_TYPE_INT,
+			      G_TYPE_INT,
 			      G_TYPE_POINTER);
 
 	object_class = G_OBJECT_CLASS (class);
@@ -291,8 +242,9 @@ gth_image_preloader_init (GthImagePreloader *self)
 	self->priv->requested = -1;
 	self->priv->requested_file = NULL;
 	self->priv->current = -1;
-	self->priv->files = NULL;
 	self->priv->load_policy = GTH_LOAD_POLICY_ONE_STEP;
+	self->priv->cancellable = g_cancellable_new ();
+	self->priv->token = 0;
 }
 
 
@@ -340,82 +292,248 @@ gth_image_preloader_new (GthLoadPolicy load_policy,
 	self->priv->loader = g_new0 (Preloader *, self->priv->n_preloaders);
 	for (i = 0; i < self->priv->n_preloaders; i++)
 		self->priv->loader[i] = preloader_new (self);
-	self->priv->files = g_new0 (GthFileData *, self->priv->n_preloaders);
 
 	return self;
 }
 
 
+void
+gth_image_prelaoder_set_load_policy (GthImagePreloader *self,
+				     GthLoadPolicy      policy)
+{
+	self->priv->load_policy = policy;
+}
+
+
+/* -- gth_image_preloader_load -- */
+
+
+static void start_next_loader (GthImagePreloader *self);
+
+
+static gboolean
+load_next (gpointer data)
+{
+	GthImagePreloader *self = data;
+
+	if (self->priv->load_id != 0) {
+		g_source_remove (self->priv->load_id);
+		self->priv->load_id = 0;
+	}
+	start_next_loader (self);
+
+	return FALSE;
+}
+
+
+static void
+image_loader_ready_cb (GObject      *source_object,
+		       GAsyncResult *result,
+		       gpointer      user_data)
+{
+	Preloader          *preloader = user_data;
+	GthImagePreloader  *self = preloader->self;
+	GthFileData        *file_data;
+	int                 requested_size;
+	GdkPixbufAnimation *animation;
+	int                 original_width;
+	int                 original_height;
+	GError             *error = NULL;
+	gboolean            success;
+	int                 interval;
+
+	success = gth_image_loader_load_animation_finish  (GTH_IMAGE_LOADER (source_object),
+							   result,
+							   &file_data,
+							   &requested_size,
+							   &animation,
+							   &original_width,
+							   &original_height,
+							   &error);
+
+	if (! g_file_equal (file_data->file, preloader->file_data->file)
+	    || (preloader->token != self->priv->token))
+	{
+		g_object_unref (file_data);
+		g_object_unref (animation);
+		if (error != NULL)
+			g_error_free (error);
+		return;
+	}
+
+	interval = NEXT_LOAD_SMALL_TIMEOUT;
+
+	_g_object_unref (preloader->animation);
+	preloader->animation = g_object_ref (animation);
+	preloader->original_width = original_width;
+	preloader->original_height = original_height;
+	preloader->loaded = success;
+	preloader->error  = ! success;
+	preloader->requested_size = requested_size;
+
+	if (_g_file_equal (file_data->file, self->priv->requested_file)) {
+#if DEBUG_PRELOADER
+		debug (DEBUG_INFO, "[requested] %s => %s [size: %d]", (error == NULL) ? "ready" : "error", g_file_get_uri (preloader->file_data->file), preloader->requested_size);
+#endif
+
+		g_signal_emit (G_OBJECT (self),
+			       gth_image_preloader_signals[REQUESTED_READY],
+			       0,
+			       preloader->file_data,
+			       preloader->animation,
+			       preloader->original_width,
+			       preloader->original_height,
+			       error);
+
+		/* Reload only if the original size is bigger then the
+		 * requested size, and if the image is not an animation. */
+
+		if (preloader_needs_second_step (preloader)) {
+			/* Reload the image at the original size */
+			preloader->loaded = FALSE;
+			preloader->requested_size = -1;
+		}
+
+		interval = NEXT_LOAD_BIG_TIMEOUT;
+	}
+
+	if (self->priv->load_id == 0)
+		self->priv->load_id = g_timeout_add (interval, load_next, self);
+
+	g_object_unref (file_data);
+	g_object_unref (animation);
+}
+
+
 static Preloader *
 current_preloader (GthImagePreloader *self)
 {
-	if (self->priv->current == -1)
-		return NULL;
-	else
-		return self->priv->loader[self->priv->current];
+	return (self->priv->current == -1) ? NULL : self->priv->loader[self->priv->current];
 }
 
 
 static Preloader *
 requested_preloader (GthImagePreloader *self)
 {
-	if (self->priv->requested == -1)
-		return NULL;
-	else
-		return self->priv->loader[self->priv->requested];
+	return (self->priv->requested == -1) ? NULL : self->priv->loader[self->priv->requested];
 }
 
 
-/* -- gth_image_preloader_load -- */
+static void
+start_next_loader (GthImagePreloader *self)
+{
+	int        i;
+	Preloader *preloader;
+
+	i = -1;
+
+	if (preloader_needs_to_load (requested_preloader (self))) {
+		i = self->priv->requested;
+	}
+	else {
+		int n = 0;
+
+		if  (self->priv->current == -1)
+			i = 0;
+		else
+			i = (self->priv->current + 1) % self->priv->n_preloaders;
+
+		for (i = 0; n < self->priv->n_preloaders; i = (i + 1) % self->priv->n_preloaders) {
+			if (preloader_needs_to_load (self->priv->loader[i]))
+				break;
+			n++;
+		}
+
+		if (n >= self->priv->n_preloaders)
+			i = -1;
+	}
+
+	self->priv->current = i;
+	preloader = current_preloader (self);
+
+	if (preloader != NULL) {
+#if DEBUG_PRELOADER
+		{
+			char *uri;
+
+			uri = g_file_get_uri (preloader->file_data->file);
+			debug (DEBUG_INFO, "load %s [size: %d]", uri, preloader->requested_size);
+			g_free (uri);
+		}
+#endif
+
+		_g_object_unref (preloader->animation);
+		preloader->animation = NULL;
+
+		g_cancellable_reset (preloader->self->priv->cancellable);
+		gth_image_loader_load (preloader->loader,
+				       preloader->file_data,
+				       preloader->requested_size,
+				       preloader->self->priv->cancellable,
+				       image_loader_ready_cb,
+				       preloader);
+	}
+#if DEBUG_PRELOADER
+	else
+		debug (DEBUG_INFO, "done");
+#endif
+}
 
 
 typedef struct {
-	GthImagePreloader *self;
-	GthFileData       *requested;
-	int                requested_size;
+	GthImagePreloader  *self;
+	GthFileData        *requested;
+	int                 requested_size;
+	GthFileData       **files;
+	int                 n_files;
+	guint               token;
 } LoadData;
 
 
 static void
 load_data_free (LoadData *load_data)
 {
+	int i;
+
 	if (load_data == NULL)
 		return;
 
-	_g_object_unref (load_data->requested);
+	for (i = 0; i < load_data->n_files; i++)
+		g_object_unref (load_data->files[i]);
+	g_free (load_data->files);
 	g_free (load_data);
 }
 
 
-void
-gth_image_preloader_load__step2 (LoadData *load_data)
+static void
+assign_loaders (LoadData *load_data)
 {
 	GthImagePreloader *self = load_data->self;
 	gboolean          *file_assigned;
 	gboolean          *loader_assigned;
-	GthFileData       *requested;
 	int                i, j;
 
-	if (! _g_file_equal (load_data->requested->file, self->priv->requested_file)
-	    || (load_data->requested_size != self->priv->requested_size))
-	{
+	if (load_data->token != self->priv->token) {
 		load_data_free (load_data);
 		return;
 	}
 
-	requested = load_data->requested;
-
 	file_assigned = g_new (gboolean, self->priv->n_preloaders);
 	loader_assigned = g_new (gboolean, self->priv->n_preloaders);
 	for (i = 0; i < self->priv->n_preloaders; i++) {
+		Preloader *preloader = self->priv->loader[i];
+
 		loader_assigned[i] = FALSE;
 		file_assigned[i] = FALSE;
+
+		if (preloader->loaded && ! preloader->error)
+			preloader->token = load_data->token;
 	}
 
 	self->priv->requested = -1;
 
-	for (j = 0; j < self->priv->n_preloaders; j++) {
-		GthFileData *file_data = self->priv->files[j];
+	for (j = 0; j < load_data->n_files; j++) {
+		GthFileData *file_data = load_data->files[j];
 
 		if (file_data == NULL)
 			continue;
@@ -425,29 +543,27 @@ gth_image_preloader_load__step2 (LoadData *load_data)
 		for (i = 0; i < self->priv->n_preloaders; i++) {
 			Preloader *preloader = self->priv->loader[i];
 
-			if ((preloader->file_data != NULL)
-			    && g_file_equal (preloader->file_data->file, file_data->file)
-			    && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
-			    			 gth_file_data_get_modification_time (preloader->file_data)) == 0)
-			    && preloader->loaded)
-			{
+			if (preloader_has_valid_content_for_file (preloader, file_data)) {
 				loader_assigned[i] = TRUE;
 				file_assigned[j] = TRUE;
-				if ((requested != NULL) && g_file_equal (file_data->file, requested->file)) {
+
+				if (file_data == load_data->requested) {
 					self->priv->requested = i;
+
 					g_signal_emit (G_OBJECT (self),
 							gth_image_preloader_signals[REQUESTED_READY],
 							0,
 							preloader->file_data,
-							preloader->loader,
+							preloader->animation,
+							preloader->original_width,
+							preloader->original_height,
 							NULL);
+
 #if DEBUG_PRELOADER
 					debug (DEBUG_INFO, "[requested] preloaded");
 #endif
 
-					if ((self->priv->load_policy == GTH_LOAD_POLICY_TWO_STEPS)
-					    && preloader_need_second_step (preloader))
-					{
+					if (preloader_needs_second_step (preloader)) {
 						/* Reload the image at the original size */
 						preloader->loaded = FALSE;
 						preloader->requested_size = -1;
@@ -469,10 +585,10 @@ gth_image_preloader_load__step2 (LoadData *load_data)
 		}
 	}
 
-	/* assign remaining files */
+	/* assign the remaining files */
 
-	for (j = 0; j < self->priv->n_preloaders; j++) {
-		GthFileData *file_data = self->priv->files[j];
+	for (j = 0; j < load_data->n_files; j++) {
+		GthFileData *file_data = load_data->files[j];
 		Preloader   *preloader;
 		int          k;
 
@@ -488,13 +604,16 @@ gth_image_preloader_load__step2 (LoadData *load_data)
 
 		g_return_if_fail (k < self->priv->n_preloaders);
 
-		preloader = self->priv->loader[k];
 		loader_assigned[k] = TRUE;
+
+		preloader = self->priv->loader[k];
 		preloader_set_file_data (preloader, file_data);
 		preloader->requested_size = load_data->requested_size;
+		preloader->token = load_data->token;
 
-		if ((requested != NULL) && g_file_equal (file_data->file, requested->file)) {
+		if (file_data == load_data->requested) {
 			self->priv->requested = k;
+
 #if DEBUG_PRELOADER
 			{
 				char *uri;
@@ -507,17 +626,18 @@ gth_image_preloader_load__step2 (LoadData *load_data)
 		}
 
 #if DEBUG_PRELOADER
-		uri = g_file_get_uri (file_data->file);
-		debug (DEBUG_INFO, "[+] [%d] <- %s", k, uri);
-		g_free (uri);
+		{
+			char *uri;
+
+			uri = g_file_get_uri (file_data->file);
+			debug (DEBUG_INFO, "[+] [%d] <- %s", k, uri);
+			g_free (uri);
+		}
 #endif
 	}
 
-	load_data_free (load_data);
 	g_free (loader_assigned);
 	g_free (file_assigned);
-
-	start_next_loader (self);
 }
 
 
@@ -543,43 +663,38 @@ gth_image_preloader_load (GthImagePreloader *self,
 			  int                requested_size,
 			  ...)
 {
-	int          i;
+	LoadData    *load_data;
 	int          n;
 	va_list      args;
 	GthFileData *file_data;
-	LoadData    *load_data;
 
-	_g_object_unref (self->priv->requested_file);
-	self->priv->requested_file = g_object_ref (requested->file);
-	self->priv->requested_size = requested_size;
-	self->priv->requested = -1;
-
-	for (i = 0; i < self->priv->n_preloaders; i++) {
-		_g_object_unref (self->priv->files[i]);
-		self->priv->files[i] = NULL;
-	}
+	self->priv->token++;
 
-	self->priv->files[0] = gth_file_data_dup (requested);
-	n = 1;
-	va_start (args, requested_size);
-	while ((n < self->priv->n_preloaders) && (file_data = va_arg (args, GthFileData *)) != NULL)
-		self->priv->files[n++] = check_file (file_data);
-	va_end (args);
+	_g_object_unref (self->priv->requested_file);
+	self->priv->requested_file = g_file_dup (requested->file);
 
 	load_data = g_new0 (LoadData, 1);
 	load_data->self = self;
+	load_data->token = self->priv->token;
 	load_data->requested = gth_file_data_dup (requested);
 	load_data->requested_size = requested_size;
+	load_data->files = g_new0 (GthFileData *, self->priv->n_preloaders);
 
-	gth_image_preloader_stop (self, (DataFunc) gth_image_preloader_load__step2, load_data);
-}
+	n = 0;
+	load_data->files[n++] = load_data->requested;
+	va_start (args, requested_size);
+	while ((n < self->priv->n_preloaders) && (file_data = va_arg (args, GthFileData *)) != NULL) {
+		GthFileData *checked_file_data = check_file (file_data);
+		if (checked_file_data != NULL)
+			load_data->files[n++] = checked_file_data;
+	}
+	va_end (args);
+	load_data->n_files = n;
 
+	assign_loaders (load_data);
+	start_next_loader (self);
 
-void
-gth_image_prelaoder_set_load_policy (GthImagePreloader *self,
-				     GthLoadPolicy      policy)
-{
-	self->priv->load_policy = policy;
+	load_data_free (load_data);
 }
 
 
@@ -597,14 +712,8 @@ gth_image_preloader_get_loader (GthImagePreloader *self,
 	for (i = 0; i < self->priv->n_preloaders; i++) {
 		Preloader *preloader = self->priv->loader[i];
 
-		if ((preloader->file_data != NULL)
-		    && g_file_equal (preloader->file_data->file, file_data->file)
-		    && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
-			    		 gth_file_data_get_modification_time (preloader->file_data)) == 0)
-		    && preloader->loaded)
-		{
+		if (preloader_has_valid_content_for_file (preloader, file_data))
 			return preloader->loader;
-		}
 	}
 
 	return NULL;
@@ -617,92 +726,5 @@ gth_image_preloader_get_requested (GthImagePreloader *self)
 	Preloader *preloader;
 
 	preloader = requested_preloader (self);
-	if (preloader == NULL)
-		return NULL;
-	else
-		return preloader->file_data;
-}
-
-
-static void
-start_next_loader (GthImagePreloader *self)
-{
-	Preloader *preloader;
-	int        i;
-
-	preloader = requested_preloader (self);
-	if ((preloader != NULL)
-	    && (preloader->file_data != NULL)
-	    && ! preloader->error
-	    && ! preloader->loaded)
-	{
-		i = self->priv->requested;
-	}
-	else {
-		int n = 0;
-
-		if  (self->priv->current == -1)
-			i = 0;
-		else
-			i = (self->priv->current + 1) % self->priv->n_preloaders;
-
-		for (i = 0; n < self->priv->n_preloaders; i = (i + 1) % self->priv->n_preloaders) {
-			preloader = self->priv->loader[i];
-
-			if ((preloader != NULL)
-			    && (preloader->file_data != NULL)
-			    && ! preloader->error
-			    && ! preloader->loaded)
-			{
-				break;
-			}
-
-			n++;
-		}
-
-		if (n >= self->priv->n_preloaders) {
-			self->priv->current = -1;
-#if DEBUG_PRELOADER
-			debug (DEBUG_INFO, "done");
-#endif
-			return;
-		}
-	}
-
-	self->priv->current = i;
-	preloader = current_preloader (self);
-
-#if DEBUG_PRELOADER
-	{
-		char *uri;
-
-		uri = g_file_get_uri (preloader->file_data->file);
-		debug (DEBUG_INFO, "load %s [size: %d]", uri, preloader->requested_size);
-		g_free (uri);
-	}
-#endif
-
-	gth_image_loader_load_at_size (preloader->loader, preloader->requested_size);
-}
-
-
-void
-gth_image_preloader_stop (GthImagePreloader *self,
-			  DataFunc           done_func,
-			  gpointer           done_func_data)
-{
-	Preloader *preloader;
-
-	preloader = current_preloader (self);
-
-	if (preloader == NULL) {
-#if DEBUG_PRELOADER
-		debug (DEBUG_INFO, "stopped");
-#endif
-		call_when_idle (done_func, done_func_data);
-		return;
-	}
-
-	self->priv->current = -1;
-	gth_image_loader_cancel (preloader->loader, done_func, done_func_data);
+	return (preloader != NULL) ? preloader->file_data : NULL;
 }
diff --git a/gthumb/gth-image-preloader.h b/gthumb/gth-image-preloader.h
index a5dc3cf..46fdbff 100644
--- a/gthumb/gth-image-preloader.h
+++ b/gthumb/gth-image-preloader.h
@@ -54,25 +54,24 @@ struct _GthImagePreloaderClass {
 
 	/*< signals >*/
 
-	void      (* requested_ready)  (GthImagePreloader *preloader,
-					GthFileData       *requested,
-					GthImageLoader    *image_loader,
-					GError            *error);
+	void      (* requested_ready)  (GthImagePreloader  *preloader,
+					GthFileData        *requested,
+					GdkPixbufAnimation *animation,
+					int                 original_width,
+					int                 original_height,
+					GError             *error);
 };
 
 
 GType               gth_image_preloader_get_type         (void) G_GNUC_CONST;
 GthImagePreloader * gth_image_preloader_new              (GthLoadPolicy       load_policy,
 							  int                 max_preloaders);
+void                gth_image_prelaoder_set_load_policy  (GthImagePreloader  *self,
+						          GthLoadPolicy       policy);
 void                gth_image_preloader_load             (GthImagePreloader  *self,
 						          GthFileData        *requested,
 						          int                 requested_size,
 						          ...);
-void                gth_image_prelaoder_set_load_policy  (GthImagePreloader  *self,
-						          GthLoadPolicy       policy);
-void                gth_image_preloader_stop             (GthImagePreloader  *self,
-						          DataFunc            done_func,
-						          gpointer            done_func_data);
 GthImageLoader *    gth_image_preloader_get_loader       (GthImagePreloader  *self,
 						          GthFileData        *file_data);
 GthFileData *       gth_image_preloader_get_requested    (GthImagePreloader  *self);
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index 7457c6c..e47aa8c 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -494,6 +494,8 @@ gth_main_get_metadata_attributes (const char *mask)
 	GList                  *scan;
 	char                  **values;
 
+	g_static_mutex_lock (&metadata_info_mutex);
+
 	if (! Main->priv->metadata_info_sorted) {
 		g_ptr_array_sort (Main->priv->metadata_info, metadata_info_sort_func);
 		Main->priv->metadata_info_sorted = TRUE;
@@ -510,6 +512,8 @@ gth_main_get_metadata_attributes (const char *mask)
 	}
 	list = g_list_reverse (list);
 
+	g_static_mutex_unlock (&metadata_info_mutex);
+
 	values = g_new (char *, n + 1);
 	for (i = 0, scan = list; scan; i++, scan = scan->next)
 		values[i] = g_strdup (scan->data);
@@ -598,10 +602,24 @@ gth_main_get_metadata_info (const char *id)
 }
 
 
-GPtrArray *
+GList *
 gth_main_get_all_metadata_info (void)
 {
-	return Main->priv->metadata_info;
+	GList *list = NULL;
+	int    i;
+
+	g_static_mutex_lock (&metadata_info_mutex);
+
+	for (i = 0; i < Main->priv->metadata_info->len; i++) {
+		GthMetadataInfo *metadata_info = g_ptr_array_index (Main->priv->metadata_info, i);
+
+		list = g_list_prepend (list, metadata_info);
+	}
+	list = g_list_reverse (list);
+
+	g_static_mutex_unlock (&metadata_info_mutex);
+
+	return list;
 }
 
 
diff --git a/gthumb/gth-main.h b/gthumb/gth-main.h
index 89c09d0..f428755 100644
--- a/gthumb/gth-main.h
+++ b/gthumb/gth-main.h
@@ -88,7 +88,7 @@ GthMetadataProvider *  gth_main_get_metadata_writer           (const char
 							       const char           *mime_type);
 GthMetadataCategory *  gth_main_get_metadata_category         (const char           *id);
 GthMetadataInfo *      gth_main_get_metadata_info             (const char           *id);
-GPtrArray *            gth_main_get_all_metadata_info         (void);
+GList *                gth_main_get_all_metadata_info         (void);
 void                   gth_main_register_sort_type            (GthFileDataSort      *sort_type);
 GthFileDataSort *      gth_main_get_sort_type                 (const char           *name);
 GList *                gth_main_get_all_sort_types            (void);
diff --git a/gthumb/gth-marshal.list b/gthumb/gth-marshal.list
index b83cc20..3ab5c7d 100644
--- a/gthumb/gth-marshal.list
+++ b/gthumb/gth-marshal.list
@@ -4,7 +4,7 @@ VOID:INT, INT
 VOID:OBJECT, BOOLEAN
 VOID:OBJECT, BOXED, ENUM
 VOID:OBJECT, OBJECT
-VOID:OBJECT, OBJECT, POINTER
+VOID:OBJECT, OBJECT, INT, INT, POINTER
 VOID:OBJECT, POINTER
 VOID:OBJECT, STRING
 VOID:OBJECT, UINT
diff --git a/gthumb/gth-overwrite-dialog.c b/gthumb/gth-overwrite-dialog.c
index 4ed5f98..9160c82 100644
--- a/gthumb/gth-overwrite-dialog.c
+++ b/gthumb/gth-overwrite-dialog.c
@@ -118,22 +118,34 @@ gth_overwrite_dialog_get_type (void)
 
 
 static void
-image_loader_ready_cb (GthImageLoader *image_loader,
-		       GError         *error,
-		       gpointer        user_data)
+image_loader_ready_cb (GObject      *source_object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
 {
 	GthOverwriteDialog *self = user_data;
-	GtkWidget         *viewer;
-
-	if (error != NULL)
+	GError             *error;
+	GdkPixbuf          *pixbuf;
+	GtkWidget          *viewer;
+
+	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
+						  result,
+						  NULL,
+						  NULL,
+						  &pixbuf,
+						  NULL,
+						  NULL,
+						  &error))
+	{
 		return;
+	}
 
-	if (image_loader == self->priv->old_image_loader)
+	if (GTH_IMAGE_LOADER (source_object) == self->priv->old_image_loader)
 		viewer = self->priv->old_image_viewer;
 	else
 		viewer = self->priv->new_image_viewer;
+	gth_image_viewer_set_pixbuf (GTH_IMAGE_VIEWER (viewer), pixbuf, -1, -1);
 
-	gth_image_viewer_set_pixbuf (GTH_IMAGE_VIEWER (viewer), gth_image_loader_get_pixbuf (image_loader), -1, -1);
+	g_object_unref (pixbuf);
 }
 
 
@@ -181,8 +193,13 @@ info_ready_cb (GList    *files,
 		gtk_widget_show (_gtk_builder_get_widget (self->priv->builder, "new_filename_label"));
 		gtk_widget_show (_gtk_builder_get_widget (self->priv->builder, "new_size_label"));
 		gtk_widget_show (_gtk_builder_get_widget (self->priv->builder, "new_modified_label"));
-		gth_image_loader_set_file_data (self->priv->new_image_loader, self->priv->source_data);
-		gth_image_loader_load_at_size (GTH_IMAGE_LOADER (self->priv->new_image_loader), PREVIEW_SIZE);
+
+		gth_image_loader_load (GTH_IMAGE_LOADER (self->priv->new_image_loader),
+				       self->priv->source_data,
+				       PREVIEW_SIZE,
+				       NULL, /* FIXME: make this cancellable */
+				       image_loader_ready_cb,
+				       self);
 	}
 	else if (self->priv->source_pixbuf != NULL) {
 		gtk_widget_hide (_gtk_builder_get_widget (self->priv->builder, "new_filename_label"));
@@ -219,8 +236,13 @@ info_ready_cb (GList    *files,
 		gth_image_viewer_set_pixbuf (GTH_IMAGE_VIEWER (self->priv->old_image_viewer), pixbuf, -1, -1);
 		g_object_unref (pixbuf);
 	}
-	gth_image_loader_set_file_data (self->priv->old_image_loader, self->priv->destination_data);
-	gth_image_loader_load_at_size (GTH_IMAGE_LOADER (self->priv->old_image_loader), PREVIEW_SIZE);
+
+	gth_image_loader_load (GTH_IMAGE_LOADER (self->priv->old_image_loader),
+			       self->priv->destination_data,
+			       PREVIEW_SIZE,
+			       NULL, /* FIXME: make this cancellable */
+			       image_loader_ready_cb,
+			       self);
 }
 
 
@@ -311,17 +333,8 @@ gth_overwrite_dialog_construct (GthOverwriteDialog   *self,
 			  G_CALLBACK (overwrite_rename_radiobutton_toggled_cb),
 			  self);
 
-	self->priv->old_image_loader = gth_image_loader_new (FALSE);
-	g_signal_connect (self->priv->old_image_loader,
-			  "ready",
-			  G_CALLBACK (image_loader_ready_cb),
-			  self);
-
-	self->priv->new_image_loader = gth_image_loader_new (FALSE);
-	g_signal_connect (self->priv->new_image_loader,
-			  "ready",
-			  G_CALLBACK (image_loader_ready_cb),
-			  self);
+	self->priv->old_image_loader = gth_image_loader_new (NULL, NULL);
+	self->priv->new_image_loader = gth_image_loader_new (NULL, NULL);
 
 	files = NULL;
 	if (self->priv->source != NULL)
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index b78fec4..1f2efb5 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -45,15 +45,11 @@
 #define THUMBNAIL_DIR_PERMISSIONS 0700
 #define MAX_THUMBNAILER_LIFETIME  2000   /* kill the thumbnailer after this amount of time*/
 
-struct _GthThumbLoaderPrivateData
+struct _GthThumbLoaderPrivate
 {
-	GthFileData      *file_data;
 	GthImageLoader   *iloader;
-	GdkPixbuf        *pixbuf;	   	 /* Contains the final (scaled
-						  * if necessary) image when
-						  * done. */
+	GthImageLoader   *tloader;
 	guint             use_cache : 1;
-	guint             loading_from_cache : 1;
 	guint             save_thumbnails : 1;
 	int               requested_size;
 	int               cache_max_size;
@@ -65,10 +61,6 @@ struct _GthThumbLoaderPrivateData
 			  thumb_size;
 	GnomeDesktopThumbnailFactory
 			 *thumb_factory;
-	char             *thumbnailer_tmpfile;
-	GPid              thumbnailer_pid;
-	guint             thumbnailer_watch;
-	guint             thumbnailer_timeout;
 };
 
 
@@ -79,7 +71,6 @@ enum {
 
 
 static GObjectClass *parent_class = NULL;
-static guint gth_thumb_loader_signals[LAST_SIGNAL] = { 0 };
 
 
 static void
@@ -87,21 +78,10 @@ gth_thumb_loader_finalize (GObject *object)
 {
 	GthThumbLoader *self;
 
-	g_return_if_fail (object != NULL);
-	g_return_if_fail (GTH_IS_THUMB_LOADER (object));
-
 	self = GTH_THUMB_LOADER (object);
+	_g_object_unref (self->priv->iloader);
+	_g_object_unref (self->priv->tloader);
 
-	if (self->priv != NULL) {
-		g_free (self->priv->thumbnailer_tmpfile);
-		_g_object_unref (self->priv->pixbuf);
-		_g_object_unref (self->priv->iloader);
-		_g_object_unref (self->priv->file_data);
-		g_free (self->priv);
-		self->priv = NULL;
-	}
-
-	/* Chain up */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -109,34 +89,22 @@ gth_thumb_loader_finalize (GObject *object)
 static void
 gth_thumb_loader_class_init (GthThumbLoaderClass *class)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (class);
+	GObjectClass *object_class;
 
 	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GthThumbLoaderPrivate));
 
+	object_class = G_OBJECT_CLASS (class);
 	object_class->finalize = gth_thumb_loader_finalize;
-
-	gth_thumb_loader_signals[READY] =
-		g_signal_new ("ready",
-			      G_TYPE_FROM_CLASS (class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (GthThumbLoaderClass, ready),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE,
-			      1,
-			      G_TYPE_POINTER);
 }
 
 
 static void
 gth_thumb_loader_init (GthThumbLoader *self)
 {
-	self->priv = g_new0 (GthThumbLoaderPrivateData, 1);
-	self->priv->file_data = NULL;
-	self->priv->pixbuf = NULL;
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_THUMB_LOADER, GthThumbLoaderPrivate);
 	self->priv->use_cache = TRUE;
 	self->priv->save_thumbnails = TRUE;
-	self->priv->loading_from_cache = FALSE;
 	self->priv->max_file_size = 0;
 }
 
@@ -169,54 +137,281 @@ gth_thumb_loader_get_type (void)
 }
 
 
-static int
-normalize_thumb (int *width,
-		 int *height,
-		 int  max_size,
-		 int  cache_max_size)
+static GdkPixbufAnimation *
+load_thumbnail (GthFileData   *file_data,
+	        int            requested_size,
+	        int           *original_width,
+	        int           *original_height,
+	        gpointer       user_data,
+	        GCancellable  *cancellable,
+	        GError       **error)
 {
-	gboolean modified;
-	float    max_w = max_size;
-	float    max_h = max_size;
-	float    w = *width;
-	float    h = *height;
-	float    factor;
-	int      new_width, new_height;
+	GthThumbLoader     *self = user_data;
+	GdkPixbuf          *pixbuf = NULL;
+	GdkPixbufAnimation *animation;
+	char               *uri;
 
-	if (max_size > cache_max_size) {
-		if ((*width < cache_max_size - 1) && (*height < cache_max_size - 1))
-			return FALSE;
+	if (original_width != NULL)
+		*original_width = -1;
+
+	if (original_height != NULL)
+		*original_height = -1;
+
+	animation = NULL;
+	uri = g_file_get_uri (file_data->file);
+	pixbuf = gnome_desktop_thumbnail_factory_generate_no_script (self->priv->thumb_factory,
+								     uri,
+								     gth_file_data_get_mime_type (file_data));
+	if (pixbuf == NULL) {
+		PixbufLoader thumbnailer;
+
+		thumbnailer = gth_main_get_pixbuf_loader (gth_file_data_get_mime_type (file_data));
+		if (thumbnailer != NULL)
+			animation = thumbnailer (file_data,
+						 self->priv->cache_max_size,
+						 original_width,
+						 original_height,
+						 NULL,
+						 cancellable,
+						 error);
 	}
-	else if ((*width < max_size - 1) && (*height < max_size - 1))
-		return FALSE;
 
-	factor = MIN (max_w / w, max_h / h);
-	new_width  = MAX ((int) (w * factor), 1);
-	new_height = MAX ((int) (h * factor), 1);
+	if (pixbuf != NULL) {
+		g_clear_error (error);
+		animation = gdk_pixbuf_non_anim_new (pixbuf);
+		g_object_unref (pixbuf);
+	}
 
-	modified = (new_width != *width) || (new_height != *height);
+	if (animation == NULL)
+		*error = g_error_new_literal (GTH_ERROR, 0, "Cannot generate the thumbnail");
 
-	*width = new_width;
-	*height = new_height;
+	g_free (uri);
 
-	return modified;
+	return animation;
+}
+
+
+static void
+gth_thumb_loader_construct (GthThumbLoader *self,
+			    int             requested_size)
+{
+	gth_thumb_loader_set_requested_size (self, requested_size);
+	self->priv->tloader = gth_image_loader_new (load_thumbnail, self);
+	self->priv->iloader = gth_image_loader_new (NULL, NULL);
+}
+
+
+GthThumbLoader *
+gth_thumb_loader_new (int requested_size)
+{
+	GthThumbLoader *self;
+
+	self = g_object_new (GTH_TYPE_THUMB_LOADER, NULL);
+	gth_thumb_loader_construct (self, requested_size);
+
+	return self;
+}
+
+
+void
+gth_thumb_loader_set_loader_func (GthThumbLoader *self,
+			          PixbufLoader    loader_func)
+{
+	gth_image_loader_set_loader_func (self->priv->iloader,
+					  (loader_func != NULL) ? loader_func : load_thumbnail,
+					  self);
+}
+
+
+void
+gth_thumb_loader_set_requested_size (GthThumbLoader *self,
+				     int             size)
+{
+	if (self->priv->thumb_factory != NULL) {
+		g_object_unref (self->priv->thumb_factory);
+		self->priv->thumb_factory = NULL;
+	}
+
+	self->priv->requested_size = size;
+	if (self->priv->requested_size <= THUMBNAIL_NORMAL_SIZE) {
+		self->priv->cache_max_size = THUMBNAIL_NORMAL_SIZE;
+		self->priv->thumb_size = GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL;
+	}
+	else {
+		self->priv->cache_max_size = THUMBNAIL_LARGE_SIZE;
+		self->priv->thumb_size = GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE;
+	}
+	self->priv->thumb_factory = gnome_desktop_thumbnail_factory_new (self->priv->thumb_size);
+}
+
+
+int
+gth_thumb_loader_get_requested_size (GthThumbLoader *self)
+{
+	return self->priv->requested_size;
+}
+
+
+void
+gth_thumb_loader_use_cache (GthThumbLoader *self,
+			    gboolean        use)
+{
+	g_return_if_fail (self != NULL);
+	self->priv->use_cache = use;
+}
+
+
+void
+gth_thumb_loader_save_thumbnails (GthThumbLoader *self,
+				  gboolean        save)
+{
+	g_return_if_fail (self != NULL);
+	self->priv->save_thumbnails = save;
+}
+
+
+void
+gth_thumb_loader_set_max_file_size (GthThumbLoader *self,
+				    goffset         size)
+{
+	g_return_if_fail (self != NULL);
+	self->priv->max_file_size = size;
+}
+
+
+typedef struct {
+	GthThumbLoader     *thumb_loader;
+	GthFileData        *file_data;
+	int                 requested_size;
+	GSimpleAsyncResult *simple;
+	GCancellable       *cancellable;
+	char               *thumbnailer_tmpfile;
+	GPid                thumbnailer_pid;
+	guint               thumbnailer_watch;
+	guint               thumbnailer_timeout;
+} LoadData;
+
+
+static LoadData *
+load_data_new (GthFileData *file_data,
+	       int          requested_size)
+{
+	LoadData *load_data;
+
+	load_data = g_new0 (LoadData, 1);
+	load_data->file_data = g_object_ref (file_data);
+	load_data->requested_size = requested_size;
+
+	return load_data;
+}
+
+
+static void
+load_data_unref (LoadData *load_data)
+{
+	g_object_unref (load_data->thumb_loader);
+	g_object_unref (load_data->file_data);
+	_g_object_unref (load_data->cancellable);
+	g_free (load_data);
+}
+
+
+typedef struct {
+	GthFileData *file_data;
+	GdkPixbuf   *pixbuf;
+} LoadResult;
+
+
+static void
+load_result_unref (LoadResult *load_result)
+{
+	g_object_unref (load_result->file_data);
+	_g_object_unref (load_result->pixbuf);
+	g_free (load_result);
+}
+
+
+static void
+original_image_ready_cb (GObject      *source_object,
+		         GAsyncResult *res,
+		         gpointer      user_data);
+
+
+static void
+cache_image_ready_cb (GObject      *source_object,
+		      GAsyncResult *res,
+		      gpointer      user_data)
+{
+	LoadData       *load_data = user_data;
+	GthThumbLoader *self = load_data->thumb_loader;
+	GdkPixbuf      *pixbuf;
+	int             width;
+	int             height;
+	gboolean        modified;
+	LoadResult     *load_result;
+
+	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
+						  res,
+						  NULL,
+						  NULL,
+						  &pixbuf,
+						  NULL,
+						  NULL,
+						  NULL))
+	{
+		/* error loading the thumbnail from the cache, try to generate
+		 * the thumbnail loading the original image. */
+
+		gth_image_loader_load (self->priv->tloader,
+				       load_data->file_data,
+				       load_data->requested_size,
+				       load_data->cancellable,
+				       original_image_ready_cb,
+				       load_data);
+
+		return;
+	}
+
+	/* Thumbnail correctly loaded from the cache. Scale if the user wants
+	 * a different size. */
+
+	width = gdk_pixbuf_get_width (pixbuf);
+	height = gdk_pixbuf_get_height (pixbuf);
+	modified = scale_keeping_ratio (&width,
+					&height,
+					self->priv->requested_size,
+					self->priv->requested_size,
+					FALSE);
+	if (modified) {
+		GdkPixbuf *tmp = pixbuf;
+		pixbuf = gdk_pixbuf_scale_simple (tmp, width, height, GDK_INTERP_BILINEAR);
+		g_object_unref (tmp);
+	}
+
+	load_result = g_new0 (LoadResult, 1);
+	load_result->file_data = g_object_ref (load_data->file_data);
+	load_result->pixbuf = pixbuf;
+	g_simple_async_result_set_op_res_gpointer (load_data->simple, load_result, (GDestroyNotify) load_result_unref);
+	g_simple_async_result_complete_in_idle (load_data->simple);
 }
 
 
 static gboolean
-_gth_thumb_loader_save_to_cache (GthThumbLoader *self)
+_gth_thumb_loader_save_to_cache (GthThumbLoader *self,
+				 GthFileData    *file_data,
+				 GdkPixbuf      *pixbuf)
 {
 	char  *uri;
 	char  *cache_path;
 	GFile *cache_file;
 	GFile *cache_dir;
 
-	if ((self == NULL) || (self->priv->pixbuf == NULL))
+	if ((self == NULL) || (pixbuf == NULL))
 		return FALSE;
 
-	uri = g_file_get_uri (self->priv->file_data->file);
+	uri = g_file_get_uri (file_data->file);
 
-	if (g_file_is_native (self->priv->file_data->file)) {
+	if (g_file_is_native (file_data->file)) {
 		char *cache_base_uri;
 
 		/* Do not save thumbnails from the user's thumbnail directory,
@@ -243,11 +438,11 @@ _gth_thumb_loader_save_to_cache (GthThumbLoader *self)
 	if (_g_directory_make (cache_dir, THUMBNAIL_DIR_PERMISSIONS, NULL)) {
 		char *uri;
 
-		uri = g_file_get_uri (self->priv->file_data->file);
+		uri = g_file_get_uri (file_data->file);
 		gnome_desktop_thumbnail_factory_save_thumbnail (self->priv->thumb_factory,
-								self->priv->pixbuf,
+								pixbuf,
 								uri,
-								gth_file_data_get_mtime (self->priv->file_data));
+								gth_file_data_get_mtime (file_data));
 		g_free (uri);
 	}
 
@@ -260,44 +455,59 @@ _gth_thumb_loader_save_to_cache (GthThumbLoader *self)
 }
 
 
-static void
-image_loader_loaded (GthImageLoader *iloader,
-		     GdkPixbuf      *pixbuf,
-		     gpointer        data)
+static int
+normalize_thumb (int *width,
+		 int *height,
+		 int  max_size,
+		 int  cache_max_size)
 {
-	GthThumbLoader *self = data;
-	int             width, height;
-	gboolean        modified;
+	gboolean modified;
+	float    max_w = max_size;
+	float    max_h = max_size;
+	float    w = *width;
+	float    h = *height;
+	float    factor;
+	int      new_width, new_height;
 
-	if (self->priv->pixbuf != NULL) {
-		g_object_unref (self->priv->pixbuf);
-		self->priv->pixbuf = NULL;
+	if (max_size > cache_max_size) {
+		if ((*width < cache_max_size - 1) && (*height < cache_max_size - 1))
+			return FALSE;
 	}
+	else if ((*width < max_size - 1) && (*height < max_size - 1))
+		return FALSE;
 
-	if (pixbuf == NULL) {
-		char *uri;
+	factor = MIN (max_w / w, max_h / h);
+	new_width  = MAX ((int) (w * factor), 1);
+	new_height = MAX ((int) (h * factor), 1);
 
-		uri = g_file_get_uri (self->priv->file_data->file);
-		gnome_desktop_thumbnail_factory_create_failed_thumbnail (self->priv->thumb_factory,
-									 uri,
-									 gth_file_data_get_mtime (self->priv->file_data));
-		g_signal_emit (G_OBJECT (self), gth_thumb_loader_signals[READY], 0, NULL);
-		g_free (uri);
+	modified = (new_width != *width) || (new_height != *height);
+
+	*width = new_width;
+	*height = new_height;
+
+	return modified;
+}
 
-		return;
-	}
 
-	g_object_ref (pixbuf);
-	self->priv->pixbuf = pixbuf;
+static void
+original_image_loaded_correctly (GthThumbLoader *self,
+				 LoadData        *load_data,
+				 GdkPixbuf       *pixbuf)
+{
+	int         width;
+	int         height;
+	gboolean    modified;
+	LoadResult *load_result;
 
 	width = gdk_pixbuf_get_width (pixbuf);
 	height = gdk_pixbuf_get_height (pixbuf);
 
-	if (self->priv->use_cache) {
-		/* Thumbnails are always saved with the same size, then
-		 * scaled if necessary. */
+	if (self->priv->save_thumbnails) {
+		gboolean modified;
 
-		/* Check whether to scale. */
+		/* Thumbnails are always saved in the cache max size, then
+		 * scaled a second time if the user requested a different
+		 * size. */
 
 		modified = scale_keeping_ratio (&width,
 						&height,
@@ -305,91 +515,67 @@ image_loader_loaded (GthImageLoader *iloader,
 						self->priv->cache_max_size,
 						FALSE);
 		if (modified) {
-			g_object_unref (self->priv->pixbuf);
-			self->priv->pixbuf = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
+			GdkPixbuf *tmp = pixbuf;
+			pixbuf = _gdk_pixbuf_scale_simple_safe (tmp, width, height, GDK_INTERP_BILINEAR);
+			g_object_unref (tmp);
 		}
 
-		/* Save the thumbnail if necessary. */
-
-		if (self->priv->save_thumbnails && ! self->priv->loading_from_cache)
-			_gth_thumb_loader_save_to_cache (self);
+		_gth_thumb_loader_save_to_cache (self, load_data->file_data, pixbuf);
+	}
 
-		/* Scale if the user wants a different size. */
+	/* Scale if the user wants a different size. */
 
-		modified = normalize_thumb (&width,
-					    &height,
-					    self->priv->requested_size,
-					    self->priv->cache_max_size);
-		if (modified) {
-			pixbuf = self->priv->pixbuf;
-			self->priv->pixbuf = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
-			g_object_unref (pixbuf);
-		}
-	}
-	else {
-		modified = scale_keeping_ratio (&width,
-						&height,
-						self->priv->requested_size,
-						self->priv->requested_size,
-						FALSE);
-		if (modified) {
-			g_object_unref (self->priv->pixbuf);
-			self->priv->pixbuf = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
-		}
+	modified = normalize_thumb (&width,
+				    &height,
+				    self->priv->requested_size,
+				    self->priv->cache_max_size);
+	if (modified) {
+		GdkPixbuf *tmp = pixbuf;
+		pixbuf = gdk_pixbuf_scale_simple (tmp, width, height, GDK_INTERP_BILINEAR);
+		g_object_unref (tmp);
 	}
 
-	g_signal_emit (G_OBJECT (self), gth_thumb_loader_signals[READY], 0, NULL);
+	load_result = g_new0 (LoadResult, 1);
+	load_result->file_data = g_object_ref (load_data->file_data);
+	load_result->pixbuf = g_object_ref (pixbuf);
+	g_simple_async_result_set_op_res_gpointer (load_data->simple, load_result, (GDestroyNotify) load_result_unref);
+	g_simple_async_result_complete_in_idle (load_data->simple);
 }
 
 
 static void
-image_loader_error (GthImageLoader *iloader,
-		    GError         *error,
-		    gpointer        data)
+failed_to_load_original_image (GthThumbLoader *self,
+			       LoadData       *load_data)
 {
-	GthThumbLoader *self = data;
-
-	g_return_if_fail (error != NULL);
+	char   *uri;
+	GError *error = NULL;
 
-	if (! self->priv->loading_from_cache) {
-		char *uri;
+	uri = g_file_get_uri (load_data->file_data->file);
+	gnome_desktop_thumbnail_factory_create_failed_thumbnail (self->priv->thumb_factory,
+								 uri,
+								 gth_file_data_get_mtime (load_data->file_data));
 
-		if (self->priv->pixbuf != NULL) {
-			g_object_unref (self->priv->pixbuf);
-			self->priv->pixbuf = NULL;
-		}
+	error = g_error_new_literal (GTH_ERROR, 0, "failed to generate the thumbnail");
+	g_simple_async_result_set_from_error (load_data->simple, error);
+	g_simple_async_result_complete_in_idle (load_data->simple);
 
-		uri = g_file_get_uri (self->priv->file_data->file);
-		gnome_desktop_thumbnail_factory_create_failed_thumbnail (self->priv->thumb_factory,
-									 uri,
-									 gth_file_data_get_mtime (self->priv->file_data));
-		g_free (uri);
-		g_signal_emit (G_OBJECT (self), gth_thumb_loader_signals[READY], 0, error);
-	}
-	else {
-		/* ! loading_from_cache : try to load the original image if
-		 * the cache version failed. */
-
-		g_error_free (error);
-		self->priv->loading_from_cache = FALSE;
-		gth_image_loader_set_file_data (self->priv->iloader, self->priv->file_data);
-		gth_image_loader_load (self->priv->iloader);
-	}
+	g_error_free (error);
+	g_free (uri);
 }
 
 
 static gboolean
-kill_thumbnailer_cb (gpointer data)
+kill_thumbnailer_cb (gpointer user_data)
 {
-	GthThumbLoader *self = data;
+	LoadData *load_data = user_data;
 
-	if (self->priv->thumbnailer_timeout != 0) {
-		g_source_remove (self->priv->thumbnailer_timeout);
-		self->priv->thumbnailer_timeout = 0;
+	if (load_data->thumbnailer_timeout != 0) {
+		g_source_remove (load_data->thumbnailer_timeout);
+		load_data->thumbnailer_timeout = 0;
 	}
 
-	if (self->priv->thumbnailer_pid != 0)
-		kill (self->priv->thumbnailer_pid, SIGTERM);
+	if (load_data->thumbnailer_pid != 0)
+		kill (load_data->thumbnailer_pid, SIGTERM);
 
 	return FALSE;
 }
@@ -398,387 +584,197 @@ kill_thumbnailer_cb (gpointer data)
 static void
 watch_thumbnailer_cb (GPid     pid,
 		      int      status,
-		      gpointer data)
+		      gpointer user_data)
 {
-	GthThumbLoader *self = data;
-	GdkPixbuf      *pixbuf = NULL;
+	LoadData       *load_data = user_data;
+	GthThumbLoader *self = load_data->thumb_loader;
+	GdkPixbuf      *pixbuf;
 
-	if (self->priv->thumbnailer_timeout != 0) {
-		g_source_remove (self->priv->thumbnailer_timeout);
-		self->priv->thumbnailer_timeout = 0;
+	if (load_data->thumbnailer_timeout != 0) {
+		g_source_remove (load_data->thumbnailer_timeout);
+		load_data->thumbnailer_timeout = 0;
 	}
 
 	g_spawn_close_pid (pid);
-	self->priv->thumbnailer_pid = 0;
-	self->priv->thumbnailer_watch = 0;
+	load_data->thumbnailer_pid = 0;
+	load_data->thumbnailer_watch = 0;
 
+	pixbuf = NULL;
 	if (status == 0)
 		pixbuf = gnome_desktop_thumbnail_factory_load_from_tempfile (self->priv->thumb_factory,
-									     &self->priv->thumbnailer_tmpfile);
+									     &load_data->thumbnailer_tmpfile);
 
 	if (pixbuf != NULL) {
-		image_loader_loaded (NULL, pixbuf, data);
+		original_image_loaded_correctly (self, load_data, pixbuf);
 		g_object_unref (pixbuf);
 	}
-	else {
-		GError *error;
-
-		error = g_error_new_literal (GTH_ERROR, 0, "Cannot generate the thumbnail");
-		image_loader_error (NULL, error, self);
-	}
+	else
+		failed_to_load_original_image (self, load_data);
 }
 
 
 static void
-image_loader_ready_cb (GthImageLoader *iloader,
-		       GError         *error,
-		       gpointer        data)
+original_image_ready_cb (GObject      *source_object,
+		         GAsyncResult *res,
+		         gpointer      user_data)
 {
-	GthThumbLoader *self = data;
-	char           *uri;
-
-	if (error == NULL) {
-		image_loader_loaded (iloader, gth_image_loader_get_pixbuf (self->priv->iloader), data);
-		return;
-	}
-
-	/* error != NULL */
-
-	if (self->priv->loading_from_cache) {
-		image_loader_error (iloader, error, data);
-		return;
-	}
-
-	/* not loading from the cache: try with the system thumbnailer */
-
-	g_clear_error (&error);
-	g_free (self->priv->thumbnailer_tmpfile);
-	self->priv->thumbnailer_tmpfile = NULL;
-	uri = g_file_get_uri (self->priv->file_data->file);
-	if (gnome_desktop_thumbnail_factory_generate_from_script (self->priv->thumb_factory,
-								  uri,
-								  gth_file_data_get_mime_type (self->priv->file_data),
-								  &self->priv->thumbnailer_pid,
-								  &self->priv->thumbnailer_tmpfile,
-								  &error))
+	LoadData       *load_data = user_data;
+	GthThumbLoader *self = load_data->thumb_loader;
+	GdkPixbuf      *pixbuf;
+	GError         *error = NULL;
+
+	if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
+						  res,
+						  NULL,
+						  NULL,
+						  &pixbuf,
+						  NULL,
+						  NULL,
+						  &error))
 	{
-		self->priv->thumbnailer_watch = g_child_watch_add (self->priv->thumbnailer_pid,
-								   watch_thumbnailer_cb,
-								   self);
-		self->priv->thumbnailer_timeout = g_timeout_add (MAX_THUMBNAILER_LIFETIME,
-								 kill_thumbnailer_cb,
-								 self);
-	}
-	else
-		image_loader_error (iloader, error, data);
-
-	g_free (uri);
-}
-
-
-static GdkPixbufAnimation *
-thumb_loader (GthFileData   *file_data,
-	      int            requested_size,
-	      int           *original_width,
-	      int           *original_height,
-	      gpointer       data,
-	      GCancellable  *cancellable,
-	      GError       **error)
-{
-	GthThumbLoader     *self = data;
-	GdkPixbuf          *pixbuf = NULL;
-	GdkPixbufAnimation *animation;
-
-	if (original_width != NULL)
-		*original_width = -1;
+		/* error loading the original image, try with the system
+		 * thumbnailer */
 
-	if (original_height != NULL)
-		*original_height = -1;
-
-	animation = NULL;
-	if (! self->priv->loading_from_cache) {
 		char *uri;
 
-		uri = g_file_get_uri (file_data->file);
-		pixbuf = gnome_desktop_thumbnail_factory_generate_no_script (self->priv->thumb_factory,
-									     uri,
-									     gth_file_data_get_mime_type (file_data));
-		if (pixbuf == NULL) {
-			PixbufLoader thumbnailer;
-
-			thumbnailer = gth_main_get_pixbuf_loader (gth_file_data_get_mime_type (file_data));
-			if (thumbnailer != NULL)
-				animation = thumbnailer (file_data,
-							 self->priv->cache_max_size,
-							 original_width,
-							 original_height,
-							 NULL,
-							 cancellable,
-							 error);
+		g_clear_error (&error);
+
+		uri = g_file_get_uri (load_data->file_data->file);
+		if (gnome_desktop_thumbnail_factory_generate_from_script (self->priv->thumb_factory,
+									  uri,
+									  gth_file_data_get_mime_type (load_data->file_data),
+									  &load_data->thumbnailer_pid,
+									  &load_data->thumbnailer_tmpfile,
+									  &error))
+		{
+			load_data->thumbnailer_watch = g_child_watch_add (load_data->thumbnailer_pid,
+									  watch_thumbnailer_cb,
+									  load_data);
+			load_data->thumbnailer_timeout = g_timeout_add (MAX_THUMBNAILER_LIFETIME,
+									kill_thumbnailer_cb,
+									load_data);
 		}
+		else
+			failed_to_load_original_image (self, load_data);
 
 		g_free (uri);
-	}
-	else
-		pixbuf = gth_pixbuf_new_from_file (file_data,
-						   -1,
-						   original_width,
-						   original_height,
-						   FALSE,
-						   cancellable,
-						   error);
-
-	if (pixbuf != NULL) {
-		g_clear_error (error);
-		animation = gdk_pixbuf_non_anim_new (pixbuf);
-		g_object_unref (pixbuf);
-	}
-
-	if (animation == NULL)
-		*error = g_error_new_literal (GTH_ERROR, 0, "Cannot generate the thumbnail");
-
-	return animation;
-}
-
-
-static void
-gth_thumb_loader_construct (GthThumbLoader *self,
-			    int             size)
-{
-	gth_thumb_loader_set_requested_size (self, size);
-
-	self->priv->iloader = gth_image_loader_new (FALSE);
-	g_signal_connect (G_OBJECT (self->priv->iloader),
-			  "ready",
-			  G_CALLBACK (image_loader_ready_cb),
-			  self);
-	gth_image_loader_set_loader (self->priv->iloader, thumb_loader, self);
-}
-
-
-GthThumbLoader *
-gth_thumb_loader_new (int size)
-{
-	GthThumbLoader *self;
-
-	self = g_object_new (GTH_TYPE_THUMB_LOADER, NULL);
-	gth_thumb_loader_construct (self, size);
-
-	return self;
-}
-
 
-void
-gth_thumb_loader_set_loader (GthThumbLoader *self,
-			     PixbufLoader    loader)
-{
-	if (loader != NULL)
-		gth_image_loader_set_loader (self->priv->iloader, loader, self);
-	else
-		gth_image_loader_set_loader (self->priv->iloader, thumb_loader, self);
-}
-
-
-void
-gth_thumb_loader_set_requested_size (GthThumbLoader *self,
-				     int             size)
-{
-	if (self->priv->thumb_factory != NULL) {
-		g_object_unref (self->priv->thumb_factory);
-		self->priv->thumb_factory = NULL;
-	}
-
-	self->priv->requested_size = size;
-	if (self->priv->requested_size <= THUMBNAIL_NORMAL_SIZE) {
-		self->priv->cache_max_size = THUMBNAIL_NORMAL_SIZE;
-		self->priv->thumb_size = GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL;
-	}
-	else {
-		self->priv->cache_max_size = THUMBNAIL_LARGE_SIZE;
-		self->priv->thumb_size = GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE;
+		return;
 	}
-	self->priv->thumb_factory = gnome_desktop_thumbnail_factory_new (self->priv->thumb_size);
-}
-
-
-int
-gth_thumb_loader_get_requested_size (GthThumbLoader *self)
-{
-	return self->priv->requested_size;
-}
-
-
-void
-gth_thumb_loader_use_cache (GthThumbLoader *self,
-			    gboolean        use)
-{
-	g_return_if_fail (self != NULL);
-	self->priv->use_cache = use;
-}
-
-
-void
-gth_thumb_loader_save_thumbnails (GthThumbLoader *self,
-				  gboolean        save)
-{
-	g_return_if_fail (self != NULL);
-	self->priv->save_thumbnails = save;
-}
-
-
-void
-gth_thumb_loader_set_max_file_size (GthThumbLoader *self,
-				    goffset         size)
-{
-	g_return_if_fail (self != NULL);
-	self->priv->max_file_size = size;
-}
-
-
-void
-gth_thumb_loader_set_file (GthThumbLoader *self,
-			   GthFileData    *file_data)
-{
-	g_return_if_fail (self != NULL);
-
-	_g_object_unref (self->priv->file_data);
-	self->priv->file_data = NULL;
 
-	if (file_data != NULL) {
-		GFile  *real_file = NULL;
-		GError *error = NULL;
+	original_image_loaded_correctly (self, load_data, pixbuf);
 
-		self->priv->file_data = gth_file_data_dup (file_data);
-
-		real_file = _g_file_resolve_all_symlinks (self->priv->file_data->file, &error);
-		if (real_file == NULL) {
-			g_warning ("%s", error->message);
-			g_clear_error (&error);
-			return;
-		}
-
-		gth_file_data_set_file (self->priv->file_data, real_file);
-
-		g_object_unref (real_file);
-	}
-
-	gth_image_loader_set_file_data (self->priv->iloader, self->priv->file_data);
+	g_object_unref (pixbuf);
 }
 
 
 void
-gth_thumb_loader_set_uri (GthThumbLoader *self,
-			  const char     *uri,
-			  const char     *mime_type)
+gth_thumb_loader_load (GthThumbLoader      *self,
+		       GthFileData         *file_data,
+		       GCancellable        *cancellable,
+		       GAsyncReadyCallback  callback,
+		       gpointer             user_data)
 {
-	GFile       *file;
-	GthFileData *file_data;
+	GSimpleAsyncResult *simple;
+	char               *cache_path;
+	LoadData           *load_data;
 
-	g_return_if_fail (self != NULL);
-	g_return_if_fail (uri != NULL);
-
-	file = g_file_new_for_uri (uri);
-	file_data = gth_file_data_new (file, NULL);
-	gth_file_data_update_info (file_data, NULL);
-	gth_file_data_set_mime_type (file_data, mime_type);
-
-	gth_thumb_loader_set_file (self, file_data);
-
-	g_object_unref (file);
-}
-
-
-GdkPixbuf *
-gth_thumb_loader_get_pixbuf (GthThumbLoader *self)
-{
-	g_return_val_if_fail (self != NULL, NULL);
-	return self->priv->pixbuf;
-}
-
-
-static void
-gth_thumb_loader_load__step2 (GthThumbLoader *self)
-{
-	char *cache_path = NULL;
+	simple = g_simple_async_result_new (G_OBJECT (self),
+					    callback,
+					    user_data,
+					    gth_thumb_loader_load);
 
+	cache_path = NULL;
 	if (self->priv->use_cache) {
 		char   *uri;
 		time_t  mtime;
 
-		uri = g_file_get_uri (self->priv->file_data->file);
-		mtime = gth_file_data_get_mtime (self->priv->file_data);
+		uri = g_file_get_uri (file_data->file);
+		mtime = gth_file_data_get_mtime (file_data);
 		cache_path = gnome_desktop_thumbnail_factory_lookup (self->priv->thumb_factory, uri, mtime);
-		if ((cache_path == NULL)
-		    && gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (self->priv->thumb_factory, uri, mtime))
-		{
-			g_signal_emit (G_OBJECT (self),
-				       gth_thumb_loader_signals[READY],
-				       0,
-				       g_error_new_literal (GTH_ERROR, 0, "failed thumbnail"));
+
+		if ((cache_path == NULL) && gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (self->priv->thumb_factory, uri, mtime)) {
+			GError *error;
+
+			error = g_error_new_literal (GTH_ERROR, 0, "failed thumbnail");
+			g_simple_async_result_set_from_error (simple, error);
+			g_simple_async_result_complete_in_idle (simple);
+
+			g_error_free (error);
 			g_free (uri);
+
 			return;
 		}
 
 		g_free (uri);
 	}
 
-	if (cache_path != NULL) {
-		GFile       *file;
-		GthFileData *file_data;
+	load_data = load_data_new (file_data, self->priv->requested_size);
+	load_data->thumb_loader = g_object_ref (self);
+	load_data->cancellable = _g_object_ref (cancellable);
+	load_data->simple = simple;
 
-		self->priv->loading_from_cache = TRUE;
-
-		file = g_file_new_for_path (cache_path);
-		file_data = gth_file_data_new (file, NULL);
-		gth_file_data_set_mime_type (file_data, "image/png");
-		gth_image_loader_set_file_data (self->priv->iloader, file_data);
-
-		g_object_unref (file_data);
-		g_object_unref (file);
+	if (cache_path != NULL) {
+		GFile       *cache_file;
+		GthFileData *cache_file_data;
+
+		cache_file = g_file_new_for_path (cache_path);
+		cache_file_data = gth_file_data_new (cache_file, NULL);
+		gth_file_data_set_mime_type (cache_file_data, "image/png");
+		gth_image_loader_load (self->priv->iloader,
+				       cache_file_data,
+				       -1,
+				       cancellable,
+				       cache_image_ready_cb,
+				       load_data);
+
+		g_object_unref (cache_file_data);
+		g_object_unref (cache_file);
 		g_free (cache_path);
 	}
-	else {
-		self->priv->loading_from_cache = FALSE;
-		gth_image_loader_set_file_data (self->priv->iloader, self->priv->file_data);
+	else if ((self->priv->max_file_size > 0) && (g_file_info_get_size (file_data->info) > self->priv->max_file_size)) {
+		GError *error;
 
-		/* Check file dimensions. */
+		load_data_unref (load_data);
 
-		if ((self->priv->max_file_size > 0)
-		    && (g_file_info_get_size (self->priv->file_data->info) > self->priv->max_file_size))
-		{
-			_g_clear_object (&self->priv->pixbuf);
-			g_signal_emit (G_OBJECT (self),
-				       gth_thumb_loader_signals[READY],
-				       0,
-				       NULL);
-			return;
-		}
-	}
+		error = g_error_new_literal (GTH_ERROR, 0, "file too big to generate the thumbnail");
+		g_simple_async_result_set_from_error (simple, error);
+		g_simple_async_result_complete_in_idle (simple);
 
-	gth_image_loader_load (self->priv->iloader);
+		g_error_free (error);
+	}
+	else
+		gth_image_loader_load (self->priv->tloader,
+				       file_data,
+				       self->priv->requested_size,
+				       cancellable,
+				       original_image_ready_cb,
+				       load_data);
 }
 
 
-void
-gth_thumb_loader_load (GthThumbLoader *self)
+gboolean
+gth_thumb_loader_load_finish (GthThumbLoader  *self,
+			      GAsyncResult    *result,
+			      GthFileData    **file_data,
+			      GdkPixbuf      **pixbuf,
+			      GError         **error)
 {
-	gth_thumb_loader_cancel (self, (DataFunc) gth_thumb_loader_load__step2, self);
-}
+	  GSimpleAsyncResult *simple;
+	  LoadResult         *load_result;
 
+	  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), gth_thumb_loader_load), FALSE);
 
-void
-gth_thumb_loader_cancel (GthThumbLoader *self,
-			 DataFunc        done_func,
-			 gpointer        done_func_data)
-{
-	g_return_if_fail (self->priv->iloader != NULL);
+	  simple = G_SIMPLE_ASYNC_RESULT (result);
 
-	if (self->priv->thumbnailer_watch != 0) {
-		/* kill the thumbnailer script */
-		g_source_remove (self->priv->thumbnailer_watch);
-		self->priv->thumbnailer_watch = 0;
-		kill_thumbnailer_cb (self);
-	}
+	  if (g_simple_async_result_propagate_error (simple, error))
+		  return FALSE;
+
+	  load_result = g_simple_async_result_get_op_res_gpointer (simple);
+	  if (file_data != NULL)
+  		  *file_data = g_object_ref (load_result->file_data);
+	  if (pixbuf != NULL)
+		  *pixbuf = g_object_ref (load_result->pixbuf);
 
-	gth_image_loader_cancel (self->priv->iloader, done_func, done_func_data);
+	  return TRUE;
 }
diff --git a/gthumb/gth-thumb-loader.h b/gthumb/gth-thumb-loader.h
index e92feb5..855cac6 100644
--- a/gthumb/gth-thumb-loader.h
+++ b/gthumb/gth-thumb-loader.h
@@ -37,49 +37,44 @@ G_BEGIN_DECLS
 #define GTH_IS_THUMB_LOADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_THUMB_LOADER))
 #define GTH_THUMB_LOADER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_THUMB_LOADER, GthThumbLoaderClass))
 
-typedef struct _GthThumbLoader            GthThumbLoader;
-typedef struct _GthThumbLoaderClass       GthThumbLoaderClass;
-typedef struct _GthThumbLoaderPrivateData GthThumbLoaderPrivateData;
+typedef struct _GthThumbLoader        GthThumbLoader;
+typedef struct _GthThumbLoaderClass   GthThumbLoaderClass;
+typedef struct _GthThumbLoaderPrivate GthThumbLoaderPrivate;
 
 struct _GthThumbLoader
 {
 	GObject  __parent;
-	GthThumbLoaderPrivateData *priv;
+	GthThumbLoaderPrivate *priv;
 };
 
 struct _GthThumbLoaderClass
 {
 	GObjectClass __parent_class;
-
-	/*< signals >*/
-
-	void (* ready) (GthThumbLoader *tl,
-			GError         *error);
 };
 
-GType            gth_thumb_loader_get_type           (void);
-GthThumbLoader * gth_thumb_loader_new                (int             size);
-void             gth_thumb_loader_set_loader         (GthThumbLoader *self,
-						      PixbufLoader    loader);
-void             gth_thumb_loader_set_requested_size (GthThumbLoader *self,
-					              int             size);
-int              gth_thumb_loader_get_requested_size (GthThumbLoader *self);
-void             gth_thumb_loader_use_cache          (GthThumbLoader *self,
-					              gboolean        use);
-void             gth_thumb_loader_save_thumbnails    (GthThumbLoader *self,
-					              gboolean        save);
-void             gth_thumb_loader_set_max_file_size  (GthThumbLoader *self,
-					              goffset         size);
-void             gth_thumb_loader_set_file           (GthThumbLoader *self,
-					              GthFileData    *file_data);
-void             gth_thumb_loader_set_uri            (GthThumbLoader *self,
-					              const char     *uri,
-					              const char     *mime_type);
-GdkPixbuf *      gth_thumb_loader_get_pixbuf         (GthThumbLoader *self);
-void             gth_thumb_loader_load               (GthThumbLoader *self);
-void             gth_thumb_loader_cancel             (GthThumbLoader *self,
-					              DataFunc        func,
-					              gpointer        data);
+GType             gth_thumb_loader_get_type             (void);
+GthThumbLoader *  gth_thumb_loader_new                  (int                   requested_size);
+void              gth_thumb_loader_set_loader_func      (GthThumbLoader       *self,
+						         PixbufLoader          loader_func);
+void              gth_thumb_loader_set_requested_size   (GthThumbLoader       *self,
+					                 int                   size);
+int               gth_thumb_loader_get_requested_size   (GthThumbLoader       *self);
+void              gth_thumb_loader_set_use_cache        (GthThumbLoader       *self,
+					                 gboolean              use);
+void              gth_thumb_loader_set_save_thumbnails  (GthThumbLoader       *self,
+					                 gboolean              save);
+void              gth_thumb_loader_set_max_file_size    (GthThumbLoader       *self,
+					                 goffset               size);
+void              gth_thumb_loader_load                 (GthThumbLoader       *self,
+						         GthFileData          *file_data,
+						         GCancellable         *cancellable,
+						         GAsyncReadyCallback   callback,
+						         gpointer              user_data);
+gboolean          gth_thumb_loader_load_finish          (GthThumbLoader       *self,
+						  	 GAsyncResult         *res,
+							 GthFileData         **file_data,
+							 GdkPixbuf           **pixbuf,
+							 GError              **error);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]