[gthumb: 3/40] Use a two step policy to load images



commit df17e42bddb38955609dd338e3dd84151c9f07b0
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Thu Sep 2 13:29:59 2010 +0200

    Use a two step policy to load images
    
    In the first step the image is loaded at a smaller size to minimize load time, in the second step it is loaded at full size to maximize quality.

 extensions/file_viewer/gth-file-viewer-page.c      |    8 +-
 extensions/flicker/dlg-import-from-flickr.c        |   10 +-
 extensions/gstreamer_tools/gth-media-viewer-page.c |    2 +-
 extensions/image_viewer/gth-image-viewer-page.c    |   73 +++-
 extensions/picasaweb/dlg-import-from-picasaweb.c   |   10 +-
 extensions/raw_files/main.c                        |    3 +
 extensions/slideshow/gth-slideshow.c               |   27 +-
 gthumb/glib-utils.c                                |   22 +-
 gthumb/glib-utils.h                                |    2 +
 gthumb/gth-image-loader.c                          |   60 +++-
 gthumb/gth-image-loader.h                          |   10 +-
 gthumb/gth-image-preloader.c                       |  479 ++++++++++++--------
 gthumb/gth-image-preloader.h                       |   38 +-
 gthumb/gth-main.h                                  |    3 +
 gthumb/gth-marshal.list                            |    1 +
 gthumb/gth-thumb-loader.c                          |   31 +-
 gthumb/gth-thumb-loader.h                          |    2 +-
 gthumb/gth-viewer-page.c                           |   10 +-
 gthumb/gth-viewer-page.h                           |    2 +
 gthumb/pixbuf-io.c                                 |   52 ++-
 gthumb/pixbuf-io.h                                 |    6 +
 21 files changed, 593 insertions(+), 258 deletions(-)
---
diff --git a/extensions/file_viewer/gth-file-viewer-page.c b/extensions/file_viewer/gth-file-viewer-page.c
index 10a95cb..f2f3923 100644
--- a/extensions/file_viewer/gth-file-viewer-page.c
+++ b/extensions/file_viewer/gth-file-viewer-page.c
@@ -39,6 +39,7 @@ struct _GthFileViewerPagePrivate {
 	GtkWidget      *viewer;
 	GtkWidget      *icon;
 	GtkWidget      *label;
+	GthFileData    *file_data;
 	guint           merge_id;
 	GthThumbLoader *thumb_loader;
 	gulong          thumb_loader_ready_event;
@@ -91,7 +92,7 @@ thumb_loader_ready_cb (GthThumbLoader    *il,
 {
 	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), TRUE);
+	gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), self->priv->file_data, TRUE);
 }
 
 
@@ -227,6 +228,9 @@ gth_file_viewer_page_real_view (GthViewerPage *base,
 	if (icon != NULL)
 		gtk_image_set_from_gicon (GTK_IMAGE (self->priv->icon), icon, GTK_ICON_SIZE_DIALOG);
 
+	_g_object_unref (self->priv->file_data);
+	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);
@@ -280,6 +284,7 @@ gth_file_viewer_page_finalize (GObject *obj)
 
 	self = GTH_FILE_VIEWER_PAGE (obj);
 
+	_g_object_unref (self->priv->file_data);
 	_g_object_unref (self->priv->thumb_loader);
 
 	G_OBJECT_CLASS (gth_file_viewer_page_parent_class)->finalize (obj);
@@ -318,6 +323,7 @@ gth_file_viewer_page_instance_init (GthFileViewerPage *self)
 {
 	self->priv = GTH_FILE_VIEWER_PAGE_GET_PRIVATE (self);
 	self->priv->thumb_loader = NULL;
+	self->priv->file_data = NULL;
 }
 
 
diff --git a/extensions/flicker/dlg-import-from-flickr.c b/extensions/flicker/dlg-import-from-flickr.c
index 6f86cea..4d82082 100644
--- a/extensions/flicker/dlg-import-from-flickr.c
+++ b/extensions/flicker/dlg-import-from-flickr.c
@@ -427,12 +427,14 @@ photoset_combobox_changed_cb (GtkComboBox *widget,
 
 static GdkPixbufAnimation *
 flickr_thumbnail_loader (GthFileData  *file_data,
-		         GError      **error,
-		         gpointer      data)
+			 int           requested_size,
+			 int          *original_width,
+			 int          *original_height,
+			 gpointer      user_data,
+		         GError      **error)
 {
 	GdkPixbufAnimation *animation = NULL;
-	GthThumbLoader     *thumb_loader = data;
-	int                 requested_size;
+	GthThumbLoader     *thumb_loader = user_data;
 	FlickrPhoto        *photo;
 	const char         *uri = NULL;
 
diff --git a/extensions/gstreamer_tools/gth-media-viewer-page.c b/extensions/gstreamer_tools/gth-media-viewer-page.c
index 30bbf47..af7f6f4 100644
--- a/extensions/gstreamer_tools/gth-media-viewer-page.c
+++ b/extensions/gstreamer_tools/gth-media-viewer-page.c
@@ -1065,7 +1065,7 @@ gth_media_viewer_page_real_view (GthViewerPage *base,
 
 	/**/
 
-	gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), TRUE);
+	gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), self->priv->file_data, TRUE);
 	g_signal_handlers_block_by_func(GET_WIDGET ("adjustment_position"), position_value_changed_cb, self);
 	gtk_adjustment_set_value (GTK_ADJUSTMENT (GET_WIDGET ("adjustment_position")), 0.0);
 	g_signal_handlers_unblock_by_func(GET_WIDGET ("adjustment_position"), position_value_changed_cb, self);
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index 3e5ceeb..adcc574 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -45,6 +45,7 @@ struct _GthImageViewerPagePrivate {
 	guint              motion_signal;
 	gboolean           pixbuf_changed;
 	gboolean           shrink_wrap;
+	GFile             *last_loaded;
 };
 
 static gpointer gth_image_viewer_page_parent_class = NULL;
@@ -203,6 +204,22 @@ static GtkToggleActionEntry image_viewer_toggle_action_entries[] = {
 
 
 static void
+gth_image_viewer_page_file_loaded (GthImageViewerPage *self,
+				   gboolean            success)
+{
+	if (_g_file_equal (self->priv->last_loaded, self->priv->file_data->file))
+		return;
+
+	_g_object_unref (self->priv->last_loaded);
+	self->priv->last_loaded = g_object_ref (self->priv->file_data->file);
+
+	gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self),
+				     self->priv->file_data,
+				     success);
+}
+
+
+static void
 viewer_image_ready_cb (GtkWidget          *widget,
 		       GthImageViewerPage *self)
 {
@@ -213,7 +230,7 @@ viewer_image_ready_cb (GtkWidget          *widget,
 	gth_image_history_add_image (self->priv->history,
 				     gth_image_viewer_get_current_pixbuf (GTH_IMAGE_VIEWER (self->priv->viewer)),
 				     FALSE);
-	gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), TRUE);
+	gth_image_viewer_page_file_loaded (self, TRUE);
 }
 
 
@@ -284,24 +301,20 @@ viewer_key_press_cb (GtkWidget          *widget,
 
 static void
 image_preloader_requested_ready_cb (GthImagePreloader  *preloader,
+				    GthFileData        *requested,
+				    GthImageLoader     *image_loader,
 				    GError             *error,
 				    GthImageViewerPage *self)
 {
-	GthImageLoader *image_loader;
-
-	if (error != NULL) {
-		gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), FALSE);
+	if (! _g_file_equal (requested->file, self->priv->file_data->file))
 		return;
-	}
 
-	image_loader = gth_image_preloader_get_loader (self->priv->preloader, gth_image_preloader_get_requested (self->priv->preloader));
-	if (image_loader == NULL) {
-		gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), FALSE);
+	if (error != NULL) {
+		gth_image_viewer_page_file_loaded (self, FALSE);
 		return;
 	}
 
 	gth_viewer_page_focus (GTH_VIEWER_PAGE (self));
-
 	gth_image_viewer_load_from_image_loader (GTH_IMAGE_VIEWER (self->priv->viewer), image_loader);
 }
 
@@ -629,19 +642,25 @@ gth_image_viewer_page_real_view (GthViewerPage *base,
 	GthFileStore       *file_store;
 	GtkTreeIter         iter;
 	GthFileData        *next_file_data = NULL;
+	GthFileData        *next2_file_data = NULL;
 	GthFileData        *prev_file_data = NULL;
+	GtkAllocation       allocation;
+	int                 window_width;
+	int                 window_height;
 
 	self = (GthImageViewerPage*) base;
 	g_return_if_fail (file_data != NULL);
 
 	gth_viewer_page_focus (GTH_VIEWER_PAGE (self));
 
+	_g_clear_object (&self->priv->last_loaded);
+
 	if ((self->priv->file_data != NULL)
 	    && g_file_equal (file_data->file, self->priv->file_data->file)
 	    && (gth_file_data_get_mtime (file_data) == gth_file_data_get_mtime (self->priv->file_data))
 	    && ! self->priv->pixbuf_changed)
 	{
-		gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), TRUE);
+		gth_image_viewer_page_file_loaded (self, TRUE);
 		return;
 	}
 
@@ -649,22 +668,46 @@ gth_image_viewer_page_real_view (GthViewerPage *base,
 	self->priv->file_data = gth_file_data_dup (file_data);
 
 	file_store = gth_browser_get_file_store (self->priv->browser);
-	if (gth_file_store_find_visible (file_store, file_data->file, &iter)) {
+	if (gth_file_store_find_visible (file_store, self->priv->file_data->file, &iter)) {
 		GtkTreeIter iter2;
+		GtkTreeIter iter3;
 
 		iter2 = iter;
 		if (gth_file_store_get_next_visible (file_store, &iter2))
 			next_file_data = gth_file_store_get_file (file_store, &iter2);
 
+		iter3 = iter2;
+		if (gth_file_store_get_next_visible (file_store, &iter3))
+			next2_file_data = gth_file_store_get_file (file_store, &iter3);
+
 		iter2 = iter;
 		if (gth_file_store_get_prev_visible (file_store, &iter2))
 			prev_file_data = gth_file_store_get_file (file_store, &iter2);
 	}
 
+	window_width = -1;
+	window_height = -1;
+
+	gtk_widget_get_allocation (self->priv->viewer, &allocation);
+	if ((allocation.width > 1) && (allocation.height > 1)) {
+		window_width = allocation.width;
+		window_height = allocation.height;
+	}
+	else {
+		GtkWidget *toplevel;
+
+		toplevel = gtk_widget_get_toplevel (self->priv->viewer);
+		if (gtk_widget_is_toplevel (toplevel))
+			gtk_window_get_size (GTK_WINDOW (toplevel), &window_width, &window_height);
+	}
+
 	gth_image_preloader_load (self->priv->preloader,
-				  file_data,
+				  self->priv->file_data,
+				  MAX (window_width, window_height),
 				  next_file_data,
-				  prev_file_data);
+				  next2_file_data,
+				  prev_file_data,
+				  NULL);
 }
 
 
@@ -1007,6 +1050,7 @@ gth_image_viewer_page_finalize (GObject *obj)
 
 	g_object_unref (self->priv->history);
 	_g_object_unref (self->priv->file_data);
+	_g_object_unref (self->priv->last_loaded);
 
 	G_OBJECT_CLASS (gth_image_viewer_page_parent_class)->finalize (obj);
 }
@@ -1048,6 +1092,7 @@ gth_image_viewer_page_instance_init (GthImageViewerPage *self)
 	self->priv = GTH_IMAGE_VIEWER_PAGE_GET_PRIVATE (self);
 	self->priv->history = gth_image_history_new ();
 	self->priv->shrink_wrap = FALSE;
+	self->priv->last_loaded = NULL;
 }
 
 
diff --git a/extensions/picasaweb/dlg-import-from-picasaweb.c b/extensions/picasaweb/dlg-import-from-picasaweb.c
index f795814..15df4d8 100644
--- a/extensions/picasaweb/dlg-import-from-picasaweb.c
+++ b/extensions/picasaweb/dlg-import-from-picasaweb.c
@@ -843,12 +843,14 @@ album_combobox_changed_cb (GtkComboBox *widget,
 
 GdkPixbufAnimation *
 picasa_web_thumbnail_loader (GthFileData  *file_data,
-			     GError      **error,
-			     gpointer      data)
+			     int           requested_size,
+			     int          *original_width,
+			     int          *original_height,
+			     gpointer      user_data,
+			     GError      **error)
 {
 	GdkPixbufAnimation *animation = NULL;
-	GthThumbLoader     *thumb_loader = data;
-	int                 requested_size;
+	GthThumbLoader     *thumb_loader = user_data;
 	PicasaWebPhoto     *photo;
 	const char         *uri;
 
diff --git a/extensions/raw_files/main.c b/extensions/raw_files/main.c
index bab5a42..1adac9e 100644
--- a/extensions/raw_files/main.c
+++ b/extensions/raw_files/main.c
@@ -271,6 +271,9 @@ get_file_mtime (const char *path)
 static GdkPixbufAnimation *
 openraw_pixbuf_animation_new_from_file (GthFileData  *file_data,
 					int           requested_size,
+					int          *original_width,
+					int          *original_height,
+					gpointer      user_data,
 					GError      **error)
 {
 	GdkPixbufAnimation *animation;
diff --git a/extensions/slideshow/gth-slideshow.c b/extensions/slideshow/gth-slideshow.c
index bdcff06..e4a1c13 100644
--- a/extensions/slideshow/gth-slideshow.c
+++ b/extensions/slideshow/gth-slideshow.c
@@ -125,6 +125,9 @@ _gth_slideshow_load_current_image (GthSlideshow *self)
 	GthFileData *requested_file;
 	GthFileData *next_file;
 	GthFileData *prev_file;
+	int          screen_width;
+	int          screen_height;
+	GdkScreen   *screen;
 
 	if (self->priv->next_event != 0) {
 		g_source_remove (self->priv->next_event);
@@ -148,10 +151,21 @@ _gth_slideshow_load_current_image (GthSlideshow *self)
 		prev_file = (GthFileData *) self->priv->current->prev->data;
 	else
 		prev_file = NULL;
+
+	screen_width = -1;
+	screen_height = -1;
+	screen = gtk_widget_get_screen (GTK_WIDGET (self));
+	if (screen != NULL) {
+		screen_width = gdk_screen_get_width (screen);
+		screen_height = gdk_screen_get_height (screen);
+	}
+
 	gth_image_preloader_load (self->priv->preloader,
 				  requested_file,
+				  MAX (screen_width, screen_height),
 				  next_file,
-				  prev_file);
+				  prev_file,
+				  NULL);
 }
 
 
@@ -211,11 +225,12 @@ 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)
 {
 	GthSlideshow   *self = user_data;
-	GthImageLoader *image_loader;
 	GdkPixbuf      *pixbuf;
 
 	if (error != NULL) {
@@ -224,12 +239,6 @@ image_preloader_requested_ready_cb (GthImagePreloader *preloader,
 		return;
 	}
 
-	image_loader = gth_image_preloader_get_loader (self->priv->preloader, (GthFileData *) self->priv->current->data);
-	if (image_loader == NULL) {
-		_gth_slideshow_load_next_image (self);
-		return;
-	}
-
 	pixbuf = gth_image_loader_get_pixbuf (image_loader);
 	if (pixbuf == NULL) {
 		_gth_slideshow_load_next_image (self);
@@ -260,7 +269,7 @@ gth_slideshow_init (GthSlideshow *self)
 	self->priv->direction = GTH_SLIDESHOW_DIRECTION_FORWARD;
 	self->priv->random_order = FALSE;
 
-	self->priv->preloader = gth_image_preloader_new ();
+	self->priv->preloader = gth_image_preloader_new (GTH_LOAD_POLICY_ONE_STEP, 3);
 	g_signal_connect (self->priv->preloader,
 			  "requested_ready",
 			  G_CALLBACK (image_preloader_requested_ready_cb),
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index 437407e..7fec8b1 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -19,6 +19,7 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -2263,7 +2264,26 @@ int
 _g_file_cmp_uris (GFile *a,
 		  GFile *b)
 {
-	return g_file_equal (a, b) ? 0 : 1;
+	char *uri_a;
+	char *uri_b;
+	int   result;
+
+	uri_a = g_file_get_uri (a);
+	uri_b = g_file_get_uri (b);
+	result = g_strcmp0 (uri_a, uri_b);
+
+	g_free (uri_b);
+	g_free (uri_a);
+
+	return result;
+}
+
+
+gboolean
+_g_file_equal_uris (GFile *a,
+		    GFile *b)
+{
+	return _g_file_cmp_uris (a, b) == 0;
 }
 
 
diff --git a/gthumb/glib-utils.h b/gthumb/glib-utils.h
index d1f71b6..692ee45 100644
--- a/gthumb/glib-utils.h
+++ b/gthumb/glib-utils.h
@@ -260,6 +260,8 @@ void            _g_file_get_modification_time    (GFile      *file,
 time_t          _g_file_get_mtime                (GFile      *file);
 int             _g_file_cmp_uris                 (GFile      *a,
 						  GFile      *b);
+gboolean        _g_file_equal_uris               (GFile      *a,
+		  	  	  	  	  GFile      *b);
 int             _g_file_cmp_modification_time    (GFile      *a,
 						  GFile      *b);
 goffset         _g_file_get_size                 (GFile      *info);
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index ccf966d..d2606ba 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -45,8 +45,11 @@ 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. */
@@ -74,7 +77,7 @@ struct _GthImageLoaderPrivate {
 	GMutex             *start_loading_mutex;
 	GCond              *start_loading_cond;
 
-	LoaderFunc          loader;
+	PixbufLoader        loader;
 	gpointer            loader_data;
 };
 
@@ -201,6 +204,9 @@ load_image_thread (void *thread_data)
 	for (;;) {
 		GthFileData *file;
 		gboolean     exit_thread;
+		int          requested_size;
+		int          original_width;
+		int          original_height;
 
 		g_mutex_lock (iloader->priv->start_loading_mutex);
 		while (! iloader->priv->start_loading)
@@ -210,6 +216,7 @@ load_image_thread (void *thread_data)
 
 		g_mutex_lock (iloader->priv->exit_thread_mutex);
 		exit_thread = iloader->priv->exit_thread;
+		requested_size = iloader->priv->requested_size;
 		g_mutex_unlock (iloader->priv->exit_thread_mutex);
 
 		if (exit_thread)
@@ -219,18 +226,30 @@ load_image_thread (void *thread_data)
 
 		G_LOCK (pixbuf_loader_lock);
 
+		original_width = -1;
+		original_height = -1;
 		animation = NULL;
 		if (file != NULL) {
 			error = NULL;
 			if (iloader->priv->loader != NULL) {
-				animation = (*iloader->priv->loader) (file, &error, iloader->priv->loader_data);
+				animation = (*iloader->priv->loader) (file,
+								      requested_size,
+								      &original_width,
+								      &original_height,
+								      iloader->priv->loader_data,
+								      &error);
 			}
 			else  {
 				PixbufLoader loader;
 
 				loader = gth_main_get_pixbuf_loader (gth_file_data_get_mime_type (file));
 				if (loader != NULL)
-					animation = loader (file, -1, &error);
+					animation = loader (file,
+							    requested_size,
+							    &original_width,
+							    &original_height,
+							    NULL,
+							    &error);
 				else
 					error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("No suitable loader available for this file type"));
 			}
@@ -244,11 +263,14 @@ load_image_thread (void *thread_data)
 		if (iloader->priv->animation != NULL)
 			g_object_unref (iloader->priv->animation);
 		iloader->priv->animation = animation;
+		iloader->priv->original_width = original_width;
+		iloader->priv->original_height = original_height;
+
 		if ((animation == NULL) || (error != NULL)) {
 			iloader->priv->error = error;
 			iloader->priv->ready = FALSE;
 		}
-		else {
+		else if (requested_size == iloader->priv->requested_size) {
 			iloader->priv->error = NULL;
 			iloader->priv->ready = TRUE;
 		}
@@ -270,6 +292,7 @@ gth_image_loader_init (GthImageLoader *iloader)
 	iloader->priv->pixbuf = NULL;
 	iloader->priv->animation = NULL;
 	iloader->priv->file = NULL;
+	iloader->priv->requested_size = -1;
 
 	iloader->priv->ready = FALSE;
 	iloader->priv->error = NULL;
@@ -359,7 +382,7 @@ gth_image_loader_new (gboolean as_animation)
 
 void
 gth_image_loader_set_loader (GthImageLoader *iloader,
-			     LoaderFunc      loader,
+			     PixbufLoader    loader,
 			     gpointer        loader_data)
 {
 	g_return_if_fail (iloader != NULL);
@@ -664,6 +687,14 @@ _gth_image_loader_load__step2 (GthImageLoader *iloader)
 void
 gth_image_loader_load (GthImageLoader *iloader)
 {
+	gth_image_loader_load_at_size (iloader, -1);
+}
+
+
+void
+gth_image_loader_load_at_size (GthImageLoader *iloader,
+			       int             requested_size)
+{
 	gboolean no_file = FALSE;
 
 	g_return_if_fail (iloader != NULL);
@@ -671,6 +702,7 @@ gth_image_loader_load (GthImageLoader *iloader)
 	g_mutex_lock (iloader->priv->data_mutex);
 	if (iloader->priv->file == NULL)
 		no_file = TRUE;
+	iloader->priv->requested_size = requested_size;
 	g_mutex_unlock (iloader->priv->data_mutex);
 
 	if (no_file)
@@ -684,6 +716,7 @@ gth_image_loader_load (GthImageLoader *iloader)
 }
 
 
+
 /* -- gth_image_loader_stop -- */
 
 
@@ -691,7 +724,7 @@ static void
 _gth_image_loader_stop__step2 (GthImageLoader *iloader,
 			       gboolean        use_idle_cb)
 {
-	DataFunc  done_func = iloader->priv->done_func;
+	DataFunc  done_func;
 	GError   *error;
 
 	g_mutex_lock (iloader->priv->data_mutex);
@@ -704,6 +737,7 @@ _gth_image_loader_stop__step2 (GthImageLoader *iloader,
 		_gth_image_loader_sync_pixbuf (iloader);
 	iloader->priv->loading = FALSE;
 
+	done_func = iloader->priv->done_func;
 	iloader->priv->done_func = NULL;
 	if (done_func != NULL) {
 		IdleCall *call;
@@ -744,7 +778,7 @@ _gth_image_loader_stop (GthImageLoader *iloader,
 
 void
 gth_image_loader_cancel (GthImageLoader *iloader,
-			  DataFunc        done_func,
+			 DataFunc        done_func,
 			 gpointer        done_func_data)
 {
 	g_mutex_lock (iloader->priv->data_mutex);
@@ -801,6 +835,18 @@ gth_image_loader_get_animation (GthImageLoader *iloader)
 }
 
 
+void
+gth_image_loader_get_original_size (GthImageLoader *iloader,
+				    int            *width,
+				    int            *height)
+{
+	g_mutex_lock (iloader->priv->data_mutex);
+	*width = iloader->priv->original_width;
+	*height = iloader->priv->original_height;
+	g_mutex_unlock (iloader->priv->data_mutex);
+}
+
+
 gboolean
 gth_image_loader_is_ready (GthImageLoader *iloader)
 {
diff --git a/gthumb/gth-image-loader.h b/gthumb/gth-image-loader.h
index 69ae22b..3ed6b77 100644
--- a/gthumb/gth-image-loader.h
+++ b/gthumb/gth-image-loader.h
@@ -26,6 +26,7 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include "typedefs.h"
 #include "gth-file-data.h"
+#include "gth-main.h"
 
 G_BEGIN_DECLS
 
@@ -56,12 +57,10 @@ struct _GthImageLoaderClass
 			GError         *error);
 };
 
-typedef GdkPixbufAnimation * (*LoaderFunc) (GthFileData *file, GError **error, gpointer data);
-
 GType                gth_image_loader_get_type                (void);
 GthImageLoader *     gth_image_loader_new                     (gboolean           as_animation);
 void                 gth_image_loader_set_loader              (GthImageLoader    *iloader,
-						               LoaderFunc         loader,
+							       PixbufLoader       loader,
 						               gpointer           data);
 void                 gth_image_loader_set_file_data           (GthImageLoader    *iloader,
 						               GthFileData       *file);
@@ -73,8 +72,13 @@ void                 gth_image_loader_set_pixbuf              (GthImageLoader
 						               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);
 gboolean             gth_image_loader_is_ready                (GthImageLoader    *iloader);
 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);
diff --git a/gthumb/gth-image-preloader.c b/gthumb/gth-image-preloader.c
index 9005732..d05f220 100644
--- a/gthumb/gth-image-preloader.c
+++ b/gthumb/gth-image-preloader.c
@@ -25,12 +25,13 @@
 #include <glib.h>
 #include "glib-utils.h"
 #include "gth-image-preloader.h"
+#include "gth-marshal.h"
 
 
+#undef DEBUG_PRELOADER
 #define GTH_IMAGE_PRELOADER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTH_TYPE_IMAGE_PRELOADER, GthImagePreloaderPrivate))
 #define NEXT_LOAD_SMALL_TIMEOUT 100
-#define NEXT_LOAD_BIG_TIMEOUT 400
-#define N_LOADERS 3
+#define NEXT_LOAD_BIG_TIMEOUT 300
 
 
 enum {
@@ -41,29 +42,35 @@ enum {
 
 typedef struct {
 	GthFileData        *file_data;
+	int                 requested_size;
 	GthImageLoader     *loader;
 	gboolean            loaded;
 	gboolean            error;
-	GthImagePreloader  *image_preloader;
+	GthImagePreloader  *self;
 } Preloader;
 
 
 struct _GthImagePreloaderPrivate {
-	Preloader   *loader[N_LOADERS];       /* Array of loaders, each loader
-					       * will load an image. */
-	int          requested;               /* This is the loader with the
-					       * requested image.  The
-					       * requested image is the image
-					       * the user has expressly
-					       * requested to view, when this
-					       * image is loaded a
-					       * requested_ready signal is
-					       * emitted.
-					       * Other images do not trigger
-					       * any signal. */
-	int          current;                 /* This is the loader that has
-					       * a loading underway. */
-	guint        load_id;
+	GthLoadPolicy load_policy;
+	int           n_preloaders;
+	Preloader   **loader;                  /* Array of loaders, each loader
+					        * will load an image. */
+	int           requested;               /* This is the loader with the
+					        * requested image.  The
+					        * requested image is the image
+					        * the user has expressly
+					        * requested to view, when this
+					        * image is loaded a
+					        * requested_ready signal is
+					        * emitted.
+					        * Other images do not trigger
+					        * any signal. */
+	GFile        *requested_file;
+	int           requested_size;
+	GthFileData **files;
+	int           current;                 /* This is the loader that has
+					        * a loading underway. */
+	guint         load_id;
 };
 
 
@@ -73,57 +80,89 @@ static guint gth_image_preloader_signals[LAST_SIGNAL] = { 0 };
 
 /* -- Preloader -- */
 
-static void        start_next_loader   (GthImagePreloader *image_preloader);
-static Preloader * current_preloader   (GthImagePreloader *image_preloader);
-static Preloader * requested_preloader (GthImagePreloader *image_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 *image_preloader = data;
+	GthImagePreloader *self = data;
 
-	if (image_preloader->priv->load_id != 0) {
-		g_source_remove (image_preloader->priv->load_id);
-		image_preloader->priv->load_id = 0;
+	if (self->priv->load_id != 0) {
+		g_source_remove (self->priv->load_id);
+		self->priv->load_id = 0;
 	}
 
-	start_next_loader (image_preloader);
+	start_next_loader (self);
 
 	return FALSE;
 }
 
 
+static gboolean
+preloader_need_second_step (Preloader *preloader)
+{
+	int original_width;
+	int original_height;
+
+	gth_image_loader_get_original_size (preloader->loader, &original_width, &original_height);
+
+	return (! preloader->error
+		&& (preloader->requested_size != -1)
+		&& ((original_width > preloader->requested_size) || (original_height > preloader->requested_size))
+		&& gdk_pixbuf_animation_is_static_image (gth_image_loader_get_animation (preloader->loader)));
+}
+
+
 static void
-image_loader_ready_cb (GthImageLoader *il,
+image_loader_ready_cb (GthImageLoader *iloader,
 		       GError         *error,
 		       Preloader      *preloader)
 {
-	GthImagePreloader *image_preloader = preloader->image_preloader;
-	int                timeout = NEXT_LOAD_SMALL_TIMEOUT;
+	GthImagePreloader *self = preloader->self;
+	int                interval = NEXT_LOAD_SMALL_TIMEOUT;
 
 	preloader->loaded = (error == NULL);
 	preloader->error  = (error != NULL);
 
-	g_object_ref (image_preloader);
+	g_object_ref (self);
 
-	if (preloader == requested_preloader (image_preloader)) {
-		g_signal_emit (G_OBJECT (image_preloader),
+	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);
-		debug (DEBUG_INFO, "[requested] error");
-		timeout = NEXT_LOAD_BIG_TIMEOUT;
+
+		/* 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;
 	}
 
-	image_preloader->priv->load_id = g_idle_add (load_next, image_preloader);
+	self->priv->load_id = g_timeout_add (interval, load_next, self);
 
-	g_object_unref (image_preloader);
+	g_object_unref (self);
 }
 
 
-static Preloader*
-preloader_new (GthImagePreloader *image_preloader)
+static Preloader *
+preloader_new (GthImagePreloader *self)
 {
 	Preloader *preloader;
 
@@ -132,7 +171,7 @@ preloader_new (GthImagePreloader *image_preloader)
 	preloader->loaded = FALSE;
 	preloader->error = FALSE;
 	preloader->loader = GTH_IMAGE_LOADER (gth_image_loader_new (TRUE));
-	preloader->image_preloader = image_preloader;
+	preloader->self = self;
 
 	g_signal_connect (G_OBJECT (preloader->loader),
 			  "ready",
@@ -181,23 +220,34 @@ preloader_set_file_data (Preloader    *preloader,
 static void
 gth_image_preloader_finalize (GObject *object)
 {
-	GthImagePreloader *image_preloader;
+	GthImagePreloader *self;
 	int                i;
 
 	g_return_if_fail (object != NULL);
 	g_return_if_fail (GTH_IS_IMAGE_PRELOADER (object));
 
-	image_preloader = GTH_IMAGE_PRELOADER (object);
+	self = GTH_IMAGE_PRELOADER (object);
 
-	if (image_preloader->priv->load_id != 0) {
-		g_source_remove (image_preloader->priv->load_id);
-		image_preloader->priv->load_id = 0;
+	if (self->priv->load_id != 0) {
+		g_source_remove (self->priv->load_id);
+		self->priv->load_id = 0;
 	}
 
-	for (i = 0; i < N_LOADERS; i++) {
-		preloader_free (image_preloader->priv->loader[i]);
-		image_preloader->priv->loader[i] = NULL;
+	for (i = 0; i < self->priv->n_preloaders; i++) {
+		preloader_free (self->priv->loader[i]);
+		self->priv->loader[i] = NULL;
 	}
+	g_free (self->priv->loader);
+	self->priv->loader = NULL;
+
+	_g_object_unref (self->priv->requested_file);
+
+	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);
@@ -218,9 +268,11 @@ gth_image_preloader_class_init (GthImagePreloaderClass *class)
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (GthImagePreloaderClass, requested_ready),
 			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
+			      gth_marshal_VOID__OBJECT_OBJECT_POINTER,
 			      G_TYPE_NONE,
-			      1,
+			      3,
+			      G_TYPE_OBJECT,
+			      G_TYPE_OBJECT,
 			      G_TYPE_POINTER);
 
 	object_class = G_OBJECT_CLASS (class);
@@ -229,16 +281,15 @@ gth_image_preloader_class_init (GthImagePreloaderClass *class)
 
 
 static void
-gth_image_preloader_init (GthImagePreloader *image_preloader)
+gth_image_preloader_init (GthImagePreloader *self)
 {
-	int i;
-
-	image_preloader->priv = GTH_IMAGE_PRELOADER_GET_PRIVATE (image_preloader);
-
-	for (i = 0; i < N_LOADERS; i++)
-		image_preloader->priv->loader[i] = preloader_new (image_preloader);
-	image_preloader->priv->requested = -1;
-	image_preloader->priv->current = -1;
+	self->priv = GTH_IMAGE_PRELOADER_GET_PRIVATE (self);
+	self->priv->loader = NULL;
+	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;
 }
 
 
@@ -271,81 +322,57 @@ gth_image_preloader_get_type (void)
 
 
 GthImagePreloader *
-gth_image_preloader_new (void)
+gth_image_preloader_new (GthLoadPolicy load_policy,
+			 int           n_preloaders)
 {
-	return (GthImagePreloader *) g_object_new (GTH_TYPE_IMAGE_PRELOADER, NULL);
+	GthImagePreloader *self;
+	int                i;
+
+	g_return_val_if_fail (n_preloaders > 0, NULL);
+
+	self = g_object_new (GTH_TYPE_IMAGE_PRELOADER, NULL);
+
+	self->priv->n_preloaders = n_preloaders;
+	self->priv->load_policy = 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;
 }
 
 
 static Preloader *
-current_preloader (GthImagePreloader *image_preloader)
+current_preloader (GthImagePreloader *self)
 {
-	if (image_preloader->priv->current == -1)
+	if (self->priv->current == -1)
 		return NULL;
 	else
-		return image_preloader->priv->loader[image_preloader->priv->current];
+		return self->priv->loader[self->priv->current];
 }
 
 
 static Preloader *
-requested_preloader (GthImagePreloader *image_preloader)
+requested_preloader (GthImagePreloader *self)
 {
-	if (image_preloader->priv->requested == -1)
+	if (self->priv->requested == -1)
 		return NULL;
 	else
-		return image_preloader->priv->loader[image_preloader->priv->requested];
+		return self->priv->loader[self->priv->requested];
 }
 
 
 /* -- gth_image_preloader_load -- */
 
 
-#define N_ARGS 3
-
-
 typedef struct {
-	GthImagePreloader *image_preloader;
+	GthImagePreloader *self;
 	GthFileData       *requested;
-	GthFileData       *next1;
-	GthFileData       *prev1;
+	int                requested_size;
 } LoadData;
 
 
-static GthFileData *
-check_file (GthFileData *file_data)
-{
-	if (file_data == NULL)
-		return NULL;
-
-	if (! g_file_is_native (file_data->file))
-		return NULL;
-
-	if (! _g_mime_type_is_image (gth_file_data_get_mime_type (file_data)))
-		return NULL;
-
-	return gth_file_data_dup (file_data);
-}
-
-
-static LoadData*
-load_data_new (GthImagePreloader *image_preloader,
-	       GthFileData       *requested,
-	       GthFileData       *next1,
-	       GthFileData       *prev1)
-{
-	LoadData *load_data;
-
-	load_data = g_new0 (LoadData, 1);
-
-	load_data->image_preloader = image_preloader;
-	load_data->requested = gth_file_data_dup (requested);
-	load_data->next1 = check_file (next1);
-	load_data->prev1 = check_file (prev1);
-
-	return load_data;
-}
-
-
 static void
 load_data_free (LoadData *load_data)
 {
@@ -353,8 +380,6 @@ load_data_free (LoadData *load_data)
 		return;
 
 	_g_object_unref (load_data->requested);
-	_g_object_unref (load_data->next1);
-	_g_object_unref (load_data->prev1);
 	g_free (load_data);
 }
 
@@ -362,36 +387,40 @@ load_data_free (LoadData *load_data)
 void
 gth_image_preloader_load__step2 (LoadData *load_data)
 {
-	GthImagePreloader *image_preloader = load_data->image_preloader;
-	GthFileData       *requested = load_data->requested;
-	GthFileData       *next1 = load_data->next1;
-	GthFileData       *prev1 = load_data->prev1;
-	GthFileData       *files[N_ARGS];
-	gboolean           file_assigned[N_LOADERS];
-	gboolean           loader_assigned[N_LOADERS];
+	GthImagePreloader *self = load_data->self;
+	gboolean          *file_assigned;
+	gboolean          *loader_assigned;
+	GthFileData       *requested;
 	int                i, j;
 
-	files[0] = requested;
-	files[1] = next1;
-	files[2] = prev1;
+	if (! _g_file_equal (load_data->requested->file, self->priv->requested_file)
+	    || (load_data->requested_size != self->priv->requested_size))
+	{
+		load_data_free (load_data);
+		return;
+	}
+
+	requested = load_data->requested;
 
-	for (i = 0; i < N_LOADERS; i++) {
+	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++) {
 		loader_assigned[i] = FALSE;
 		file_assigned[i] = FALSE;
 	}
 
-	image_preloader->priv->requested = -1;
+	self->priv->requested = -1;
 
-	for (j = 0; j < N_ARGS; j++) {
-		GthFileData *file_data = files[j];
+	for (j = 0; j < self->priv->n_preloaders; j++) {
+		GthFileData *file_data = self->priv->files[j];
 
 		if (file_data == NULL)
 			continue;
 
 		/* check whether the image has already been loaded. */
 
-		for (i = 0; i < N_LOADERS; i++) {
-			Preloader *preloader = image_preloader->priv->loader[i];
+		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)
@@ -399,30 +428,50 @@ gth_image_preloader_load__step2 (LoadData *load_data)
 			    			 gth_file_data_get_modification_time (preloader->file_data)) == 0)
 			    && preloader->loaded)
 			{
-				char *uri;
-
 				loader_assigned[i] = TRUE;
 				file_assigned[j] = TRUE;
 				if ((requested != NULL) && g_file_equal (file_data->file, requested->file)) {
-					image_preloader->priv->requested = i;
-					g_signal_emit (G_OBJECT (image_preloader), gth_image_preloader_signals[REQUESTED_READY], 0, NULL);
+					self->priv->requested = i;
+					g_signal_emit (G_OBJECT (self),
+							gth_image_preloader_signals[REQUESTED_READY],
+							0,
+							preloader->file_data,
+							preloader->loader,
+							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))
+					{
+						/* Reload the image at the original size */
+						preloader->loaded = FALSE;
+						preloader->requested_size = -1;
+					}
 				}
 
-				uri = g_file_get_uri (file_data->file);
-				debug (DEBUG_INFO, "[=] [%d] <- %s", i, uri);
-				g_free (uri);
+#if DEBUG_PRELOADER
+				{
+					char *uri;
+
+					uri = g_file_get_uri (file_data->file);
+					debug (DEBUG_INFO, "[=] [%d] <- %s", i, uri);
+					g_free (uri);
+				}
+#endif
+
+				break;
 			}
 		}
 	}
 
-	/* assign remaining paths. */
+	/* assign remaining files */
 
-	for (j = 0; j < N_ARGS; j++) {
-		GthFileData *file_data = files[j];
+	for (j = 0; j < self->priv->n_preloaders; j++) {
+		GthFileData *file_data = self->priv->files[j];
 		Preloader   *preloader;
 		int          k;
-		char        *uri;
 
 		if (file_data == NULL)
 			continue;
@@ -431,60 +480,119 @@ gth_image_preloader_load__step2 (LoadData *load_data)
 			continue;
 
 		/* find the first non-assigned loader */
-		for (k = 0; (k < N_LOADERS) && loader_assigned[k]; k++)
+		for (k = 0; (k < self->priv->n_preloaders) && loader_assigned[k]; k++)
 			/* void */;
 
-		g_return_if_fail (k < N_LOADERS);
+		g_return_if_fail (k < self->priv->n_preloaders);
 
-		preloader = image_preloader->priv->loader[k];
+		preloader = self->priv->loader[k];
 		loader_assigned[k] = TRUE;
 		preloader_set_file_data (preloader, file_data);
+		preloader->requested_size = load_data->requested_size;
 
 		if ((requested != NULL) && g_file_equal (file_data->file, requested->file)) {
-			image_preloader->priv->requested = k;
+			self->priv->requested = k;
+#if DEBUG_PRELOADER
+			{
+				char *uri;
 
-			uri = g_file_get_uri (file_data->file);
-			debug (DEBUG_INFO, "[requested] %s", uri);
-			g_free (uri);
+				uri = g_file_get_uri (file_data->file);
+				debug (DEBUG_INFO, "[requested] %s", uri);
+				g_free (uri);
+			}
+#endif
 		}
 
+#if DEBUG_PRELOADER
 		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);
+}
+
+
+static GthFileData *
+check_file (GthFileData *file_data)
+{
+	if (file_data == NULL)
+		return NULL;
 
-	start_next_loader (image_preloader);
+	if (! g_file_is_native (file_data->file))
+		return NULL;
+
+	if (! _g_mime_type_is_image (gth_file_data_get_mime_type (file_data)))
+		return NULL;
+
+	return gth_file_data_dup (file_data);
 }
 
 
 void
-gth_image_preloader_load (GthImagePreloader  *image_preloader,
-			  GthFileData        *requested,
-			  GthFileData        *next1,
-			  GthFileData        *prev1)
+gth_image_preloader_load (GthImagePreloader *self,
+			  GthFileData       *requested,
+			  int                requested_size,
+			  ...)
 {
-	LoadData *load_data;
+	int          i;
+	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->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);
+
+	load_data = g_new0 (LoadData, 1);
+	load_data->self = self;
+	load_data->requested = gth_file_data_dup (requested);
+	load_data->requested_size = requested_size;
+
+	gth_image_preloader_stop (self, (DataFunc) gth_image_preloader_load__step2, load_data);
+}
+
 
-	load_data = load_data_new (image_preloader, requested, next1, prev1);
-	gth_image_preloader_stop (image_preloader, (DataFunc) gth_image_preloader_load__step2, load_data);
+void
+gth_image_prelaoder_set_load_policy (GthImagePreloader *self,
+				     GthLoadPolicy      policy)
+{
+	self->priv->load_policy = policy;
 }
 
 
 GthImageLoader *
-gth_image_preloader_get_loader (GthImagePreloader *image_preloader,
+gth_image_preloader_get_loader (GthImagePreloader *self,
 				GthFileData       *file_data)
 {
 	int i;
 
-	g_return_val_if_fail (image_preloader != NULL, NULL);
+	g_return_val_if_fail (self != NULL, NULL);
 
 	if (file_data == NULL)
 		return NULL;
 
-	for (i = 0; i < N_LOADERS; i++) {
-		Preloader *preloader = image_preloader->priv->loader[i];
+	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)
@@ -501,11 +609,11 @@ gth_image_preloader_get_loader (GthImagePreloader *image_preloader,
 
 
 GthFileData *
-gth_image_preloader_get_requested (GthImagePreloader *image_preloader)
+gth_image_preloader_get_requested (GthImagePreloader *self)
 {
 	Preloader *preloader;
 
-	preloader = requested_preloader (image_preloader);
+	preloader = requested_preloader (self);
 	if (preloader == NULL)
 		return NULL;
 	else
@@ -514,30 +622,29 @@ gth_image_preloader_get_requested (GthImagePreloader *image_preloader)
 
 
 static void
-start_next_loader (GthImagePreloader *image_preloader)
+start_next_loader (GthImagePreloader *self)
 {
-	int        i;
 	Preloader *preloader;
-	char      *uri;
+	int        i;
 
-	preloader = requested_preloader (image_preloader);
+	preloader = requested_preloader (self);
 	if ((preloader != NULL)
 	    && (preloader->file_data != NULL)
 	    && ! preloader->error
 	    && ! preloader->loaded)
 	{
-		i = image_preloader->priv->requested;
+		i = self->priv->requested;
 	}
 	else {
 		int n = 0;
 
-		if  (image_preloader->priv->current == -1)
+		if  (self->priv->current == -1)
 			i = 0;
 		else
-			i = (image_preloader->priv->current + 1) % N_LOADERS;
+			i = (self->priv->current + 1) % self->priv->n_preloaders;
 
-		for (i = 0; n < N_LOADERS; i = (i + 1) % N_LOADERS) {
-			preloader = image_preloader->priv->loader[i];
+		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)
@@ -550,40 +657,50 @@ start_next_loader (GthImagePreloader *image_preloader)
 			n++;
 		}
 
-		if (n >= N_LOADERS) {
-			image_preloader->priv->current = -1;
+		if (n >= self->priv->n_preloaders) {
+			self->priv->current = -1;
+#if DEBUG_PRELOADER
 			debug (DEBUG_INFO, "done");
+#endif
 			return;
 		}
 	}
 
-	image_preloader->priv->current = i;
-	preloader = current_preloader (image_preloader);
+	self->priv->current = i;
+	preloader = current_preloader (self);
 
-	gth_image_loader_load (preloader->loader);
+#if DEBUG_PRELOADER
+	{
+		char *uri;
 
-	uri = g_file_get_uri (preloader->file_data->file);
-	debug (DEBUG_INFO, "load %s", uri);
-	g_free (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 *image_preloader,
+gth_image_preloader_stop (GthImagePreloader *self,
 			  DataFunc           done_func,
 			  gpointer           done_func_data)
 {
 	Preloader *preloader;
 
-	if (image_preloader->priv->current == -1) {
+	preloader = current_preloader (self);
+
+	if (preloader == NULL) {
+#if DEBUG_PRELOADER
 		debug (DEBUG_INFO, "stopped");
+#endif
 		call_when_idle (done_func, done_func_data);
 		return;
 	}
 
-	preloader = current_preloader (image_preloader);
-	image_preloader->priv->current = -1;
-
+	self->priv->current = -1;
 	gth_image_loader_cancel (preloader->loader, done_func, done_func_data);
 }
 
@@ -597,7 +714,9 @@ gth_image_preloader_set (GthImagePreloader *dest,
 	if (src == NULL)
 		return;
 
-	for (i = 0; i < N_LOADERS; i++) {
+	g_return_if_fail (src->priv->n_preloaders == dest->priv->n_preloaders);
+
+	for (i = 0; i < src->priv->n_preloaders; i++) {
 		Preloader *src_loader = src->priv->loader[i];
 		Preloader *dest_loader = dest->priv->loader[i];
 
diff --git a/gthumb/gth-image-preloader.h b/gthumb/gth-image-preloader.h
index 6a9de2a..38df535 100644
--- a/gthumb/gth-image-preloader.h
+++ b/gthumb/gth-image-preloader.h
@@ -25,6 +25,10 @@
 #include "gth-image-loader.h"
 #include "gth-file-data.h"
 
+typedef enum {
+	GTH_LOAD_POLICY_ONE_STEP,
+	GTH_LOAD_POLICY_TWO_STEPS,
+} GthLoadPolicy;
 
 #define GTH_TYPE_IMAGE_PRELOADER            (gth_image_preloader_get_type ())
 #define GTH_IMAGE_PRELOADER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_IMAGE_PRELOADER, GthImagePreloader))
@@ -51,24 +55,28 @@ struct _GthImagePreloaderClass {
 	/*< signals >*/
 
 	void      (* requested_ready)  (GthImagePreloader *preloader,
+					GthFileData       *requested,
+					GthImageLoader    *image_loader,
 					GError            *error);
 };
 
 
-GType               gth_image_preloader_get_type      (void) G_GNUC_CONST;
-GthImagePreloader * gth_image_preloader_new           (void);
-/* images get loaded in the following order : requested, next1, prev1. */
-void                gth_image_preloader_load          (GthImagePreloader  *preloader,
-						       GthFileData        *requested,
-						       GthFileData        *next1,
-						       GthFileData        *prev1);
-void                gth_image_preloader_stop          (GthImagePreloader  *preloader,
-						       DataFunc            done_func,
-						       gpointer            done_func_data);
-GthImageLoader *    gth_image_preloader_get_loader    (GthImagePreloader  *preloader,
-						       GthFileData        *file_data);
-GthFileData *       gth_image_preloader_get_requested (GthImagePreloader  *preloader);
-void                gth_image_preloader_set           (GthImagePreloader  *dest,
-						       GthImagePreloader  *src);
+GType               gth_image_preloader_get_type         (void) G_GNUC_CONST;
+GthImagePreloader * gth_image_preloader_new              (GthLoadPolicy       load_policy,
+							  int                 max_preloaders);
+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);
+void                gth_image_preloader_set              (GthImagePreloader  *dest,
+						       	  GthImagePreloader  *src);
 
 #endif /* GTH_IMAGE_PRELOADER_H */
diff --git a/gthumb/gth-main.h b/gthumb/gth-main.h
index 741068a..2afbb49 100644
--- a/gthumb/gth-main.h
+++ b/gthumb/gth-main.h
@@ -51,6 +51,9 @@ typedef struct _GthMainClass    GthMainClass;
 
 typedef GdkPixbufAnimation* (*PixbufLoader) (GthFileData  *file_data,
 					     int           requested_size,
+					     int          *original_width,
+					     int          *original_height,
+					     gpointer      user_data,
 				   	     GError      **error);
 
 struct _GthMain {
diff --git a/gthumb/gth-marshal.list b/gthumb/gth-marshal.list
index 6054fa7..b83cc20 100644
--- a/gthumb/gth-marshal.list
+++ b/gthumb/gth-marshal.list
@@ -4,6 +4,7 @@ VOID:INT, INT
 VOID:OBJECT, BOOLEAN
 VOID:OBJECT, BOXED, ENUM
 VOID:OBJECT, OBJECT
+VOID:OBJECT, OBJECT, POINTER
 VOID:OBJECT, POINTER
 VOID:OBJECT, STRING
 VOID:OBJECT, UINT
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index d8eebfe..e662571 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -476,15 +476,24 @@ image_loader_ready_cb (GthImageLoader *iloader,
 }
 
 
-static GdkPixbufAnimation*
+static GdkPixbufAnimation *
 thumb_loader (GthFileData  *file_data,
-	      GError      **error,
-	      gpointer      data)
+	      int           requested_size,
+	      int          *original_width,
+	      int          *original_height,
+	      gpointer      data,
+	      GError      **error)
 {
 	GthThumbLoader     *self = data;
 	GdkPixbuf          *pixbuf = NULL;
 	GdkPixbufAnimation *animation;
 
+	if (original_width != NULL)
+		*original_width = -1;
+
+	if (original_height != NULL)
+		*original_height = -1;
+
 	animation = NULL;
 	if (! self->priv->loading_from_cache) {
 		char *uri;
@@ -498,13 +507,23 @@ thumb_loader (GthFileData  *file_data,
 
 			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, error);
+				animation = thumbnailer (file_data,
+							 self->priv->cache_max_size,
+							 original_width,
+							 original_height,
+							 NULL,
+							 error);
 		}
 
 		g_free (uri);
 	}
 	else
-		pixbuf = gth_pixbuf_new_from_file (file_data, -1, error);
+		pixbuf = gth_pixbuf_new_from_file (file_data,
+						   -1,
+						   original_width,
+						   original_height,
+						   FALSE,
+						   error);
 
 	if (pixbuf != NULL) {
 		g_clear_error (error);
@@ -548,7 +567,7 @@ gth_thumb_loader_new (int size)
 
 void
 gth_thumb_loader_set_loader (GthThumbLoader *self,
-			     LoaderFunc      loader)
+			     PixbufLoader    loader)
 {
 	if (loader != NULL)
 		gth_image_loader_set_loader (self->priv->iloader, loader, self);
diff --git a/gthumb/gth-thumb-loader.h b/gthumb/gth-thumb-loader.h
index c2c2b2a..e92feb5 100644
--- a/gthumb/gth-thumb-loader.h
+++ b/gthumb/gth-thumb-loader.h
@@ -60,7 +60,7 @@ struct _GthThumbLoaderClass
 GType            gth_thumb_loader_get_type           (void);
 GthThumbLoader * gth_thumb_loader_new                (int             size);
 void             gth_thumb_loader_set_loader         (GthThumbLoader *self,
-						      LoaderFunc      loader);
+						      PixbufLoader    loader);
 void             gth_thumb_loader_set_requested_size (GthThumbLoader *self,
 					              int             size);
 int              gth_thumb_loader_get_requested_size (GthThumbLoader *self);
diff --git a/gthumb/gth-viewer-page.c b/gthumb/gth-viewer-page.c
index fc03671..4cc9c94 100644
--- a/gthumb/gth-viewer-page.c
+++ b/gthumb/gth-viewer-page.c
@@ -20,8 +20,10 @@
  */
 
 #include <config.h>
+#include "gth-marshal.h"
 #include "gth-viewer-page.h"
 
+
 enum {
     FILE_LOADED,
     LAST_SIGNAL
@@ -44,9 +46,10 @@ gth_viewer_page_base_init (gpointer g_iface)
 	                          G_SIGNAL_RUN_LAST,
 	                          G_STRUCT_OFFSET (GthViewerPageIface, file_loaded),
 	                          NULL, NULL,
-	                          g_cclosure_marshal_VOID__BOOLEAN,
+	                          gth_marshal_VOID__OBJECT_BOOLEAN,
 	                          G_TYPE_NONE,
-	                          1,
+	                          2,
+	                          G_TYPE_OBJECT,
 	                          G_TYPE_BOOLEAN);
 
 	initialized = TRUE;
@@ -191,7 +194,8 @@ gth_viewer_page_revert (GthViewerPage *self)
 
 void
 gth_viewer_page_file_loaded (GthViewerPage *self,
+			     GthFileData   *file_data,
 			     gboolean       success)
 {
-	g_signal_emit (self, gth_viewer_page_signals[FILE_LOADED], 0, success);
+	g_signal_emit (self, gth_viewer_page_signals[FILE_LOADED], 0, file_data, success);
 }
diff --git a/gthumb/gth-viewer-page.h b/gthumb/gth-viewer-page.h
index ec3adec..70611d2 100644
--- a/gthumb/gth-viewer-page.h
+++ b/gthumb/gth-viewer-page.h
@@ -74,6 +74,7 @@ struct _GthViewerPageIface {
 	/*< signals >*/
 
 	void      (*file_loaded)         (GthViewerPage *self,
+					  GthFileData   *file_data,
 					  gboolean       success);
 };
 
@@ -103,6 +104,7 @@ void         gth_viewer_page_save_as             (GthViewerPage  *self,
 						  gpointer        data);
 void         gth_viewer_page_revert              (GthViewerPage  *self);
 void         gth_viewer_page_file_loaded         (GthViewerPage  *self,
+						  GthFileData    *file_data,
 						  gboolean        success);
 
 G_END_DECLS
diff --git a/gthumb/pixbuf-io.c b/gthumb/pixbuf-io.c
index ca66296..37d54a8 100644
--- a/gthumb/pixbuf-io.c
+++ b/gthumb/pixbuf-io.c
@@ -30,6 +30,7 @@
 #include "gth-main.h"
 #include "gth-pixbuf-saver.h"
 #include "pixbuf-io.h"
+#include "pixbuf-utils.h"
 
 
 char *
@@ -219,38 +220,59 @@ _gdk_pixbuf_save_async (GdkPixbuf        *pixbuf,
 }
 
 
-GdkPixbuf*
+GdkPixbuf *
 gth_pixbuf_new_from_file (GthFileData  *file_data,
 			  int           requested_size,
+			  int          *original_width,
+			  int          *original_height,
+			  gboolean      scale_to_original,
 			  GError      **error)
 {
 	GdkPixbuf *pixbuf = NULL;
 	char      *path;
 	gboolean   scale_pixbuf;
+	int        original_w;
+	int        original_h;
+
+	if (original_width != NULL)
+		*original_width = -1;
+
+	if (original_height != NULL)
+		*original_height = -1;
 
 	if (file_data == NULL)
 		return NULL;
 
 	path = g_file_get_path (file_data->file);
+	if (path == NULL)
+		return NULL;
 
 	scale_pixbuf = FALSE;
+	original_w = -1;
+	original_h = -1;
 	if (requested_size > 0) {
-		int w, h;
-
-		if (gdk_pixbuf_get_file_info (path, &w, &h) == NULL) {
-			w = -1;
-			h = -1;
+		if (gdk_pixbuf_get_file_info (path, &original_w, &original_h) == NULL) {
+			original_w = -1;
+			original_h = -1;
 		}
-		if ((w > requested_size) || (h > requested_size))
+		if ((original_w > requested_size) || (original_h > requested_size))
 			scale_pixbuf = TRUE;
 	}
 
-	if (scale_pixbuf)
+	if (scale_pixbuf) {
 		pixbuf = gdk_pixbuf_new_from_file_at_scale (path,
 							    requested_size,
 							    requested_size,
 							    TRUE,
 							    error);
+		if (scale_to_original) {
+			GdkPixbuf *tmp;
+
+			tmp = _gdk_pixbuf_scale_simple_safe (pixbuf, original_w, original_h, GDK_INTERP_NEAREST);
+			g_object_unref (pixbuf);
+			pixbuf = tmp;
+		}
+	}
 	else
 		pixbuf = gdk_pixbuf_new_from_file (path, error);
 
@@ -264,15 +286,24 @@ gth_pixbuf_new_from_file (GthFileData  *file_data,
 		}
 	}
 
+	if (original_width != NULL)
+		*original_width = original_w;
+
+	if (original_height != NULL)
+		*original_height = original_h;
+
 	g_free (path);
 
 	return pixbuf;
 }
 
 
-GdkPixbufAnimation*
+GdkPixbufAnimation *
 gth_pixbuf_animation_new_from_file (GthFileData  *file_data,
 				    int           requested_size,
+				    int          *original_width,
+				    int          *original_height,
+				    gpointer      user_data,
 				    GError      **error)
 {
 	GdkPixbufAnimation *animation = NULL;
@@ -297,6 +328,9 @@ gth_pixbuf_animation_new_from_file (GthFileData  *file_data,
 
 		pixbuf = gth_pixbuf_new_from_file (file_data,
 						   requested_size,
+						   original_width,
+						   original_height,
+						   FALSE,
 						   error);
 
 		if (pixbuf != NULL) {
diff --git a/gthumb/pixbuf-io.h b/gthumb/pixbuf-io.h
index 1fb7fca..f437e1c 100644
--- a/gthumb/pixbuf-io.h
+++ b/gthumb/pixbuf-io.h
@@ -58,10 +58,16 @@ void        _gdk_pixbuf_save_async             (GdkPixbuf        *pixbuf,
 						gpointer          data);
 GdkPixbuf * gth_pixbuf_new_from_file           (GthFileData      *file,
 						int               requested_size,
+						int              *original_width,
+						int              *original_height,
+						gboolean          scale_to_original,
 						GError          **error);
 GdkPixbufAnimation*
 	    gth_pixbuf_animation_new_from_file (GthFileData      *file_data,
 						int               requested_size,
+						int              *original_width,
+						int              *original_height,
+						gpointer          user_data,
 						GError          **error);
 
 G_END_DECLS



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