[gthumb] image preloader: implemented a smarter cache



commit 95c31a31f5f2e96f046715c15e5535f305a1c2ce
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Oct 2 23:15:56 2013 +0200

    image preloader: implemented a smarter cache

 extensions/cairo_io/cairo-image-surface-jpeg.c     |    3 +
 extensions/cairo_io/cairo-image-surface-jpeg.h     |    1 +
 extensions/cairo_io/cairo-image-surface-png.c      |    1 +
 extensions/cairo_io/cairo-image-surface-png.h      |    1 +
 extensions/cairo_io/cairo-image-surface-svg.c      |    1 +
 extensions/cairo_io/cairo-image-surface-svg.h      |    1 +
 extensions/cairo_io/cairo-image-surface-webp.c     |    1 +
 extensions/cairo_io/cairo-image-surface-webp.h     |    1 +
 extensions/cairo_io/cairo-image-surface-xcf.c      |    1 +
 extensions/cairo_io/cairo-image-surface-xcf.h      |    1 +
 .../contact_sheet/gth-contact-sheet-creator.c      |    1 +
 extensions/facebook/dlg-import-from-facebook.c     |    1 +
 extensions/flicker_utils/dlg-import-from-flickr.c  |    1 +
 extensions/image_print/gth-load-image-info-task.c  |    1 +
 extensions/image_viewer/gth-image-viewer-page.c    |   15 +-
 extensions/picasaweb/dlg-import-from-picasaweb.c   |    1 +
 extensions/raw_files/main.c                        |    6 +
 extensions/webalbums/gth-web-exporter.c            |    1 +
 gthumb/cairo-scale.c                               |  132 ++++++++-
 gthumb/cairo-scale.h                               |   39 ++-
 gthumb/glib-utils.c                                |    2 +-
 gthumb/gth-image-loader.c                          |   20 +-
 gthumb/gth-image-loader.h                          |    1 +
 gthumb/gth-image-preloader.c                       |  315 +++++++++++++++++---
 gthumb/gth-image-preloader.h                       |   39 ++--
 gthumb/gth-image-utils.c                           |    1 +
 gthumb/gth-image.h                                 |    1 +
 gthumb/gth-overwrite-dialog.c                      |    1 +
 gthumb/gth-task.c                                  |   57 ++--
 gthumb/gth-task.h                                  |    2 +
 gthumb/gth-thumb-loader.c                          |    5 +
 gthumb/pixbuf-io.c                                 |    1 +
 gthumb/pixbuf-io.h                                 |    1 +
 33 files changed, 544 insertions(+), 112 deletions(-)
---
diff --git a/extensions/cairo_io/cairo-image-surface-jpeg.c b/extensions/cairo_io/cairo-image-surface-jpeg.c
index 0fe2a4d..4e6f7c8 100644
--- a/extensions/cairo_io/cairo-image-surface-jpeg.c
+++ b/extensions/cairo_io/cairo-image-surface-jpeg.c
@@ -149,6 +149,7 @@ _cairo_image_surface_create_from_jpeg (GInputStream  *istream,
                                       int            requested_size,
                                       int           *original_width_p,
                                       int           *original_height_p,
+                                      gboolean      *loaded_original_p,
                                       gpointer       user_data,
                                       GCancellable  *cancellable,
                                       GError       **error)
@@ -536,6 +537,8 @@ _cairo_image_surface_create_from_jpeg (GInputStream  *istream,
                        *original_width_p = original_width;
                if (original_height_p != NULL)
                        *original_height_p = original_height;
+               if (loaded_original_p != NULL)
+                       *loaded_original_p = ! load_scaled;
 
                jpeg_finish_decompress (&srcinfo);
                jpeg_destroy_decompress (&srcinfo);
diff --git a/extensions/cairo_io/cairo-image-surface-jpeg.h b/extensions/cairo_io/cairo-image-surface-jpeg.h
index 23244a7..aaa6716 100644
--- a/extensions/cairo_io/cairo-image-surface-jpeg.h
+++ b/extensions/cairo_io/cairo-image-surface-jpeg.h
@@ -32,6 +32,7 @@ GthImage *  _cairo_image_surface_create_from_jpeg (GInputStream  *istream,
                                                   int            requested_size,
                                                   int           *original_width,
                                                   int           *original_height,
+                                                  gboolean      *loaded_original,
                                                   gpointer       user_data,
                                                   GCancellable  *cancellable,
                                                   GError       **error);
diff --git a/extensions/cairo_io/cairo-image-surface-png.c b/extensions/cairo_io/cairo-image-surface-png.c
index 4e4c126..2df3efd 100644
--- a/extensions/cairo_io/cairo-image-surface-png.c
+++ b/extensions/cairo_io/cairo-image-surface-png.c
@@ -136,6 +136,7 @@ _cairo_image_surface_create_from_png (GInputStream  *istream,
                                      int            requested_size,
                                      int           *original_width,
                                      int           *original_height,
+                                     gboolean      *loaded_original,
                                      gpointer       user_data,
                                      GCancellable  *cancellable,
                                      GError       **error)
diff --git a/extensions/cairo_io/cairo-image-surface-png.h b/extensions/cairo_io/cairo-image-surface-png.h
index 2ae9993..c11d6a4 100644
--- a/extensions/cairo_io/cairo-image-surface-png.h
+++ b/extensions/cairo_io/cairo-image-surface-png.h
@@ -32,6 +32,7 @@ GthImage *  _cairo_image_surface_create_from_png (GInputStream  *istream,
                                                  int            requested_size,
                                                  int           *original_width,
                                                  int           *original_height,
+                                                 gboolean      *loaded_original,
                                                  gpointer       user_data,
                                                  GCancellable  *cancellable,
                                                  GError       **error);
diff --git a/extensions/cairo_io/cairo-image-surface-svg.c b/extensions/cairo_io/cairo-image-surface-svg.c
index 13f9af8..7cf0a7b 100644
--- a/extensions/cairo_io/cairo-image-surface-svg.c
+++ b/extensions/cairo_io/cairo-image-surface-svg.c
@@ -168,6 +168,7 @@ _cairo_image_surface_create_from_svg (GInputStream  *istream,
                                      int            requested_size,
                                      int           *original_width,
                                      int           *original_height,
+                                     gboolean      *loaded_original,
                                      gpointer       user_data,
                                      GCancellable  *cancellable,
                                      GError       **error)
diff --git a/extensions/cairo_io/cairo-image-surface-svg.h b/extensions/cairo_io/cairo-image-surface-svg.h
index dc67431..18f32f7 100644
--- a/extensions/cairo_io/cairo-image-surface-svg.h
+++ b/extensions/cairo_io/cairo-image-surface-svg.h
@@ -32,6 +32,7 @@ GthImage *  _cairo_image_surface_create_from_svg (GInputStream  *istream,
                                                  int            requested_size,
                                                  int           *original_width,
                                                  int           *original_height,
+                                                 gboolean      *loaded_original,
                                                  gpointer       user_data,
                                                  GCancellable  *cancellable,
                                                  GError       **error);
diff --git a/extensions/cairo_io/cairo-image-surface-webp.c b/extensions/cairo_io/cairo-image-surface-webp.c
index c1ebe9d..cfa6e80 100644
--- a/extensions/cairo_io/cairo-image-surface-webp.c
+++ b/extensions/cairo_io/cairo-image-surface-webp.c
@@ -35,6 +35,7 @@ _cairo_image_surface_create_from_webp (GInputStream  *istream,
                                       int            requested_size,
                                       int           *original_width,
                                       int           *original_height,
+                                      gboolean      *loaded_original,
                                       gpointer       user_data,
                                       GCancellable  *cancellable,
                                       GError       **error)
diff --git a/extensions/cairo_io/cairo-image-surface-webp.h b/extensions/cairo_io/cairo-image-surface-webp.h
index d9c952b..4cb1725 100644
--- a/extensions/cairo_io/cairo-image-surface-webp.h
+++ b/extensions/cairo_io/cairo-image-surface-webp.h
@@ -32,6 +32,7 @@ GthImage *  _cairo_image_surface_create_from_webp (GInputStream  *istream,
                                                   int            requested_size,
                                                   int           *original_width,
                                                   int           *original_height,
+                                                  gboolean      *loaded_original,
                                                   gpointer       user_data,
                                                   GCancellable  *cancellable,
                                                   GError       **error);
diff --git a/extensions/cairo_io/cairo-image-surface-xcf.c b/extensions/cairo_io/cairo-image-surface-xcf.c
index 5846976..24392c8 100644
--- a/extensions/cairo_io/cairo-image-surface-xcf.c
+++ b/extensions/cairo_io/cairo-image-surface-xcf.c
@@ -954,6 +954,7 @@ _cairo_image_surface_create_from_xcf (GInputStream  *istream,
                                      int            requested_size,
                                      int           *original_width,
                                      int           *original_height,
+                                     gboolean      *loaded_original,
                                      gpointer       user_data,
                                      GCancellable  *cancellable,
                                      GError       **error)
diff --git a/extensions/cairo_io/cairo-image-surface-xcf.h b/extensions/cairo_io/cairo-image-surface-xcf.h
index 3d7717e..7f72e78 100644
--- a/extensions/cairo_io/cairo-image-surface-xcf.h
+++ b/extensions/cairo_io/cairo-image-surface-xcf.h
@@ -32,6 +32,7 @@ GthImage *  _cairo_image_surface_create_from_xcf (GInputStream  *istream,
                                                  int            requested_size,
                                                  int           *original_width,
                                                  int           *original_height,
+                                                 gboolean      *loaded_original,
                                                  gpointer       user_data,
                                                  GCancellable  *cancellable,
                                                  GError       **error);
diff --git a/extensions/contact_sheet/gth-contact-sheet-creator.c 
b/extensions/contact_sheet/gth-contact-sheet-creator.c
index 9ff69b5..e5d7412 100644
--- a/extensions/contact_sheet/gth-contact-sheet-creator.c
+++ b/extensions/contact_sheet/gth-contact-sheet-creator.c
@@ -933,6 +933,7 @@ image_loader_ready_cb (GObject      *source_object,
                                            &image,
                                            &original_width,
                                            &original_height,
+                                           NULL,
                                            &error))
        {
                gth_task_completed (GTH_TASK (self), error);
diff --git a/extensions/facebook/dlg-import-from-facebook.c b/extensions/facebook/dlg-import-from-facebook.c
index 7197bfd..a5cb3fd 100644
--- a/extensions/facebook/dlg-import-from-facebook.c
+++ b/extensions/facebook/dlg-import-from-facebook.c
@@ -404,6 +404,7 @@ facebook_thumbnail_loader (GInputStream  *istream,
                           int            requested_size,
                           int           *original_width,
                           int           *original_height,
+                          gboolean      *loaded_original,
                           gpointer       user_data,
                           GCancellable  *cancellable,
                           GError       **error)
diff --git a/extensions/flicker_utils/dlg-import-from-flickr.c 
b/extensions/flicker_utils/dlg-import-from-flickr.c
index c80a13e..e685cd7 100644
--- a/extensions/flicker_utils/dlg-import-from-flickr.c
+++ b/extensions/flicker_utils/dlg-import-from-flickr.c
@@ -411,6 +411,7 @@ flickr_thumbnail_loader (GInputStream  *istream,
                         int            requested_size,
                         int           *original_width,
                         int           *original_height,
+                        gboolean      *loaded_original,
                         gpointer       user_data,
                         GCancellable  *cancellable,
                         GError       **error)
diff --git a/extensions/image_print/gth-load-image-info-task.c 
b/extensions/image_print/gth-load-image-info-task.c
index 5cdcbda..df353fa 100644
--- a/extensions/image_print/gth-load-image-info-task.c
+++ b/extensions/image_print/gth-load-image-info-task.c
@@ -119,6 +119,7 @@ image_loader_ready_cb (GObject      *source_object,
                                      &image,
                                      NULL,
                                      NULL,
+                                     NULL,
                                      &error);
 
        if (error == NULL)
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index d43092d..9b5d44e 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -267,7 +267,7 @@ different_quality_ready_cb (GObject         *source_object,
                return;
        }
 
-       if (! _g_file_equal (requested->file, self->priv->file_data->file))
+       if (! (self->priv->image_changed && requested == NULL) && ! _g_file_equal (requested->file, 
self->priv->file_data->file))
                goto clear_data;
 
        if (image == NULL)
@@ -295,11 +295,14 @@ clear_data:
 static void
 update_image_quality_if_required (GthImageViewerPage *self)
 {
-       double zoom;
+       GthFileData *file_data;
+       double       zoom;
 
-       if (self->priv->image_changed || self->priv->loading_image)
+       if (self->priv->loading_image)
                return;
 
+       file_data = self->priv->image_changed ? GTH_MODIFIED_IMAGE : self->priv->file_data;
+
        zoom = gth_image_viewer_get_zoom (GTH_IMAGE_VIEWER (self->priv->viewer));
        if (zoom >= 1.0) {
                int requested_size;
@@ -312,7 +315,7 @@ update_image_quality_if_required (GthImageViewerPage *self)
                                                    &original_height);
                if ((requested_size > 0) && (MAX (original_width, original_height) > requested_size)) {
                        gth_image_preloader_load (self->priv->preloader,
-                                                 self->priv->file_data,
+                                                 file_data,
                                                  GTH_ORIGINAL_SIZE,
                                                  NULL,
                                                  different_quality_ready_cb,
@@ -329,7 +332,7 @@ update_image_quality_if_required (GthImageViewerPage *self)
                new_requested_size = _gth_image_preloader_get_requested_size (self);
                if (old_requested_size != new_requested_size) {
                        gth_image_preloader_load (self->priv->preloader,
-                                                 self->priv->file_data,
+                                                 file_data,
                                                  new_requested_size,
                                                  NULL,
                                                  different_quality_ready_cb,
@@ -1395,6 +1398,8 @@ _gth_image_viewer_page_set_image (GthImageViewerPage *self,
        if (image == NULL)
                return;
 
+       if (requested_size == -1)
+               gth_image_preloader_set_modified_image (self->priv->preloader, image);
        gth_image_viewer_set_surface (GTH_IMAGE_VIEWER (self->priv->viewer), image, -1, -1);
        gth_image_viewer_set_requested_size (GTH_IMAGE_VIEWER (self->priv->viewer), requested_size);
 
diff --git a/extensions/picasaweb/dlg-import-from-picasaweb.c 
b/extensions/picasaweb/dlg-import-from-picasaweb.c
index 0901bd0..6114fa8 100644
--- a/extensions/picasaweb/dlg-import-from-picasaweb.c
+++ b/extensions/picasaweb/dlg-import-from-picasaweb.c
@@ -337,6 +337,7 @@ picasa_web_thumbnail_loader (GInputStream  *istream,
                             int            requested_size,
                             int           *original_width,
                             int           *original_height,
+                            gboolean      *loaded_original,
                             gpointer       user_data,
                             GCancellable  *cancellable,
                             GError       **error)
diff --git a/extensions/raw_files/main.c b/extensions/raw_files/main.c
index 46cec15..652b28f 100644
--- a/extensions/raw_files/main.c
+++ b/extensions/raw_files/main.c
@@ -97,6 +97,7 @@ _libraw_read_jpeg_data (void           *buffer,
                             NULL,
                             NULL,
                             NULL,
+                            NULL,
                             cancellable,
                             error);
 
@@ -226,6 +227,7 @@ _cairo_image_surface_create_from_raw (GInputStream  *istream,
                                      int            requested_size,
                                      int           *original_width,
                                      int           *original_height,
+                                     gboolean      *loaded_original,
                                      gpointer       user_data,
                                      GCancellable  *cancellable,
                                      GError       **error)
@@ -268,6 +270,9 @@ _cairo_image_surface_create_from_raw (GInputStream  *istream,
 
        if (requested_size > 0) {
 
+               if (loaded_original != NULL)
+                       *loaded_original = FALSE;
+
                /* read the thumbnail */
 
                result = libraw_unpack_thumb (raw_data);
@@ -464,6 +469,7 @@ dcraw_pixbuf_animation_new_from_file (GInputStream  *istream,
                                        int            requested_size,
                                        int           *original_width,
                                        int           *original_height,
+                                       gboolean      *loaded_original,
                                        gpointer       user_data,
                                        GCancellable  *cancellable,
                                        GError       **error)
diff --git a/extensions/webalbums/gth-web-exporter.c b/extensions/webalbums/gth-web-exporter.c
index 6ec409b..bc9c81b 100644
--- a/extensions/webalbums/gth-web-exporter.c
+++ b/extensions/webalbums/gth-web-exporter.c
@@ -2569,6 +2569,7 @@ image_loader_ready_cb (GObject      *source_object,
                                            &image,
                                            NULL,
                                            NULL,
+                                           NULL,
                                            NULL))
        {
                load_next_file (self);
diff --git a/gthumb/cairo-scale.c b/gthumb/cairo-scale.c
index 65b499b..14dbd38 100644
--- a/gthumb/cairo-scale.c
+++ b/gthumb/cairo-scale.c
@@ -26,6 +26,7 @@
 #include "cairo-utils.h"
 #include "cairo-scale.h"
 #include "gfixed.h"
+#include "glib-utils.h"
 
 
 #define CLAMP_PIXEL(v) (((v) <= 0) ? 0  : ((v) >= 255) ? 255 : (v));
@@ -503,13 +504,14 @@ _cairo_image_surface_scale (cairo_surface_t  *image,
                            scale_filter_t    filter,
                            GthAsyncTask     *task)
 {
-       int              src_width;
-       int              src_height;
-       cairo_surface_t *scaled;
-       resize_filter_t *resize_filter;
-       ScaleReal        x_factor;
-       ScaleReal        y_factor;
-       cairo_surface_t *tmp;
+       int                       src_width;
+       int                       src_height;
+       cairo_surface_t          *scaled;
+       cairo_surface_metadata_t *metadata;
+       resize_filter_t          *resize_filter;
+       ScaleReal                 x_factor;
+       ScaleReal                 y_factor;
+       cairo_surface_t          *tmp;
 
        src_width = cairo_image_surface_get_width (image);
        src_height = cairo_image_surface_get_height (image);
@@ -520,6 +522,10 @@ _cairo_image_surface_scale (cairo_surface_t  *image,
        scaled = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                              scaled_width,
                                              scaled_height);
+       metadata = _cairo_image_surface_get_metadata (scaled);
+       metadata->original_width = src_width;
+       metadata->original_height = src_height;
+
        if (scaled == NULL)
                return NULL;
 
@@ -905,3 +911,115 @@ _cairo_image_surface_scale_bilinear (cairo_surface_t *image,
 
        return tmp2;
 }
+
+
+/* -- _cairo_image_surface_scale_async -- */
+
+
+typedef struct {
+       cairo_surface_t *original;
+       int              new_width;
+       int              new_height;
+       scale_filter_t   quality;
+       cairo_surface_t *scaled;
+       GthTask         *task;
+} ScaleData;
+
+
+static ScaleData *
+scale_data_new (cairo_surface_t         *image,
+               int               new_width,
+               int               new_height,
+               scale_filter_t    quality,
+               GCancellable     *cancellable)
+{
+       ScaleData *scale_data;
+
+       scale_data = g_new0 (ScaleData, 1);
+       scale_data->original = cairo_surface_reference (image);
+       scale_data->new_width = new_width;
+       scale_data->new_height = new_height;
+       scale_data->quality = quality;
+       scale_data->scaled = NULL;
+       scale_data->task = gth_async_task_new (NULL, NULL, NULL, NULL, NULL);
+       gth_task_set_cancellable (scale_data->task, cancellable);
+
+       return scale_data;
+}
+
+
+static void
+scale_data_free (ScaleData *scale_data)
+{
+       _g_object_unref (scale_data->task);
+       cairo_surface_destroy (scale_data->scaled);
+       cairo_surface_destroy (scale_data->original);
+       g_free (scale_data);
+}
+
+
+static void
+scale_image_thread (GSimpleAsyncResult *result,
+                   GObject            *object,
+                   GCancellable       *cancellable)
+{
+       ScaleData *scale_data;
+
+       scale_data = g_simple_async_result_get_op_res_gpointer (result);
+       scale_data->scaled = _cairo_image_surface_scale (scale_data->original,
+                                                        scale_data->new_width,
+                                                        scale_data->new_height,
+                                                        scale_data->quality,
+                                                        GTH_ASYNC_TASK (scale_data->task));
+}
+
+
+void
+_cairo_image_surface_scale_async (cairo_surface_t       *image,
+                                 int                     new_width,
+                                 int                     new_height,
+                                 scale_filter_t          quality,
+                                 GCancellable           *cancellable,
+                                 GAsyncReadyCallback     ready_callback,
+                                 gpointer                user_data)
+{
+       GSimpleAsyncResult *result;
+
+       result = g_simple_async_result_new (NULL,
+                                           ready_callback,
+                                           user_data,
+                                           _cairo_image_surface_scale_async);
+       g_simple_async_result_set_op_res_gpointer (result,
+                                                  scale_data_new (image,
+                                                                  new_width,
+                                                                  new_height,
+                                                                  quality,
+                                                                  cancellable),
+                                                  (GDestroyNotify) scale_data_free);
+       g_simple_async_result_run_in_thread (result,
+                                            scale_image_thread,
+                                            G_PRIORITY_DEFAULT,
+                                            cancellable);
+
+       g_object_unref (result);
+}
+
+
+cairo_surface_t *
+_cairo_image_surface_scale_finish (GAsyncResult         *result,
+                                  GError       **error)
+{
+         GSimpleAsyncResult *simple;
+         ScaleData          *scale_data;
+
+         g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, 
_cairo_image_surface_scale_async), NULL);
+
+         simple = G_SIMPLE_ASYNC_RESULT (result);
+
+         if (g_simple_async_result_propagate_error (simple, error))
+                 return NULL;
+
+         scale_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+         return cairo_surface_reference (scale_data->scaled);
+}
diff --git a/gthumb/cairo-scale.h b/gthumb/cairo-scale.h
index dd85c0a..a0f58ff 100644
--- a/gthumb/cairo-scale.h
+++ b/gthumb/cairo-scale.h
@@ -47,21 +47,30 @@ typedef enum /*< skip >*/ {
 } scale_filter_t;
 
 
-cairo_surface_t *  _cairo_image_surface_scale_nearest   (cairo_surface_t *image,
-                                                        int              new_width,
-                                                        int              new_height);
-cairo_surface_t *  _cairo_image_surface_scale          (cairo_surface_t *image,
-                                                        int              width,
-                                                        int              height,
-                                                        scale_filter_t   quality,
-                                                        GthAsyncTask    *task);
-cairo_surface_t *  _cairo_image_surface_scale_squared   (cairo_surface_t *image,
-                                                        int              size,
-                                                        scale_filter_t   quality,
-                                                        GthAsyncTask    *task);
-cairo_surface_t *  _cairo_image_surface_scale_bilinear  (cairo_surface_t *image,
-                                                        int              new_width,
-                                                        int              new_height);
+cairo_surface_t *  _cairo_image_surface_scale_nearest   (cairo_surface_t        *image,
+                                                        int                      new_width,
+                                                        int                      new_height);
+cairo_surface_t *  _cairo_image_surface_scale          (cairo_surface_t         *image,
+                                                        int                      width,
+                                                        int                      height,
+                                                        scale_filter_t           quality,
+                                                        GthAsyncTask            *task);
+cairo_surface_t *  _cairo_image_surface_scale_squared   (cairo_surface_t        *image,
+                                                        int                      size,
+                                                        scale_filter_t           quality,
+                                                        GthAsyncTask            *task);
+cairo_surface_t *  _cairo_image_surface_scale_bilinear  (cairo_surface_t        *image,
+                                                        int                      new_width,
+                                                        int                      new_height);
+void               _cairo_image_surface_scale_async     (cairo_surface_t        *image,
+                                                        int                      new_width,
+                                                        int                      new_height,
+                                                        scale_filter_t           quality,
+                                                        GCancellable            *cancellable,
+                                                        GAsyncReadyCallback      ready_callback,
+                                                        gpointer                 user_data);
+cairo_surface_t *  _cairo_image_surface_scale_finish   (GAsyncResult            *result,
+                                                        GError                 **error);
 
 G_END_DECLS
 
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index 1191302..45defba 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -85,7 +85,7 @@ _g_object_list_ref (GList *list)
 void
 _g_object_list_unref (GList *list)
 {
-       g_list_foreach (list, (GFunc) g_object_unref, NULL);
+       g_list_foreach (list, (GFunc) _g_object_unref, NULL);
        g_list_free (list);
 }
 
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index 7a41894..8593d07 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -113,6 +113,7 @@ typedef struct {
        GthImage     *image;
        int           original_width;
        int           original_height;
+       gboolean      loaded_original;
 } LoadData;
 
 
@@ -127,6 +128,7 @@ load_data_new (GthFileData  *file_data,
        load_data->file_data = _g_object_ref (file_data);
        load_data->requested_size = requested_size;
        load_data->cancellable = _g_object_ref (cancellable);
+       load_data->loaded_original = TRUE;
 
        return load_data;
 }
@@ -143,14 +145,15 @@ load_data_unref (LoadData *load_data)
 
 
 static void
-load_pixbuf_thread (GSimpleAsyncResult *result,
-                   GObject            *object,
-                   GCancellable       *cancellable)
+load_image_thread (GSimpleAsyncResult *result,
+                  GObject            *object,
+                  GCancellable       *cancellable)
 {
        GthImageLoader *self = GTH_IMAGE_LOADER (object);
        LoadData       *load_data;
        int             original_width;
        int             original_height;
+       gboolean        loaded_original;
        GInputStream   *istream;
        GthImage       *image = NULL;
        GError         *error = NULL;
@@ -166,12 +169,15 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
                return;
        }
 
+       loaded_original = TRUE;
+
        if (self->priv->loader_func != NULL) {
                image = (*self->priv->loader_func) (istream,
                                                    load_data->file_data,
                                                    load_data->requested_size,
                                                    &original_width,
                                                    &original_height,
+                                                   &loaded_original,
                                                    self->priv->loader_data,
                                                    cancellable,
                                                    &error);
@@ -190,6 +196,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
                                             load_data->requested_size,
                                             &original_width,
                                             &original_height,
+                                            &loaded_original,
                                             NULL,
                                             cancellable,
                                             &error);
@@ -214,6 +221,7 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
        load_data->image = image;
        load_data->original_width = original_width;
        load_data->original_height = original_height;
+       load_data->loaded_original = loaded_original;
 }
 
 
@@ -238,7 +246,7 @@ gth_image_loader_load (GthImageLoader      *loader,
                                                                  cancellable),
                                                   (GDestroyNotify) load_data_unref);
        g_simple_async_result_run_in_thread (result,
-                                            load_pixbuf_thread,
+                                            load_image_thread,
                                             io_priority,
                                             cancellable);
 
@@ -252,6 +260,7 @@ gth_image_loader_load_finish (GthImageLoader   *loader,
                              GthImage        **image,
                              int              *original_width,
                              int              *original_height,
+                             gboolean         *loaded_original,
                              GError         **error)
 {
          GSimpleAsyncResult *simple;
@@ -271,6 +280,8 @@ gth_image_loader_load_finish (GthImageLoader   *loader,
                  *original_width = load_data->original_width;
          if (original_height != NULL)
                  *original_height = load_data->original_height;
+         if (loaded_original != NULL)
+                 *loaded_original = load_data->loaded_original;
 
          return TRUE;
 }
@@ -301,6 +312,7 @@ gth_image_new_from_stream (GInputStream  *istream,
                                             &original_width,
                                             &original_height,
                                             NULL,
+                                            NULL,
                                             cancellable,
                                             &error);
        }
diff --git a/gthumb/gth-image-loader.h b/gthumb/gth-image-loader.h
index e1847d7..2db3343 100644
--- a/gthumb/gth-image-loader.h
+++ b/gthumb/gth-image-loader.h
@@ -69,6 +69,7 @@ gboolean          gth_image_loader_load_finish            (GthImageLoader
                                                           GthImage            **image,
                                                           int                  *original_width,
                                                           int                  *original_height,
+                                                          gboolean             *loaded_original,
                                                           GError              **error);
 GthImage *        gth_image_new_from_stream               (GInputStream         *istream,
                                                           int                   requested_size,
diff --git a/gthumb/gth-image-preloader.c b/gthumb/gth-image-preloader.c
index 4532c35..07cbf86 100644
--- a/gthumb/gth-image-preloader.c
+++ b/gthumb/gth-image-preloader.c
@@ -23,8 +23,11 @@
 #include <config.h>
 #include <string.h>
 #include <glib.h>
+#include "cairo-scale.h"
+#include "cairo-utils.h"
 #include "glib-utils.h"
 #include "gth-image-preloader.h"
+#include "gth-image-utils.h"
 #include "gth-marshal.h"
 
 
@@ -121,15 +124,51 @@ cache_data_unref (CacheData *cache_data)
 }
 
 
+static inline gboolean
+cache_data_file_matches (CacheData   *cache_data,
+                        GthFileData *file_data)
+{
+       if ((file_data == GTH_MODIFIED_IMAGE) && (cache_data->file_data == GTH_MODIFIED_IMAGE))
+               return TRUE;
+
+       if ((file_data == GTH_MODIFIED_IMAGE) || (cache_data->file_data == GTH_MODIFIED_IMAGE))
+               return FALSE;
+
+       if (g_file_equal (cache_data->file_data->file, file_data->file)
+            && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
+                                gth_file_data_get_modification_time (cache_data->file_data)) == 0))
+       {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+
 static gboolean
 cache_data_is_valid_for_request (CacheData   *cache_data,
                                 GthFileData *file_data,
                                 int          requested_size)
 {
-       return ((cache_data->requested_size == requested_size)
-               && g_file_equal (cache_data->file_data->file, file_data->file)
-               && (_g_time_val_cmp (gth_file_data_get_modification_time (file_data),
-                                    gth_file_data_get_modification_time (cache_data->file_data)) == 0));
+       if (! cache_data_file_matches (cache_data, file_data))
+               return FALSE;
+
+       return cache_data->requested_size == requested_size;
+}
+
+
+static gboolean
+cache_data_has_better_quality_for_request (CacheData   *cache_data,
+                                          GthFileData *file_data,
+                                          int          requested_size)
+{
+       if (! cache_data_file_matches (cache_data, file_data))
+               return FALSE;
+
+       if (requested_size == GTH_ORIGINAL_SIZE)
+               return FALSE;
+
+       return (cache_data->requested_size > requested_size) || (cache_data->requested_size == 
GTH_ORIGINAL_SIZE);
 }
 
 
@@ -147,7 +186,7 @@ load_request_new (GthImagePreloader *preloader)
        request->preloader = preloader;
        request->files = NULL;
        request->current_file = NULL;
-       request->requested_size = -1;
+       request->requested_size = GTH_ORIGINAL_SIZE;
        request->result = NULL;
        request->cancellable = NULL;
 
@@ -248,9 +287,9 @@ gth_image_preloader_new (void)
 
 
 static CacheData *
-_gth_image_preloader_lookup_request (GthImagePreloader *self,
-                                    GthFileData        *requested_file,
-                                    int                 requested_size)
+_gth_image_preloader_lookup_same_size (GthImagePreloader       *self,
+                                      GthFileData              *requested_file,
+                                      int                       requested_size)
 {
        GList *scan;
 
@@ -264,6 +303,23 @@ _gth_image_preloader_lookup_request (GthImagePreloader     *self,
 }
 
 
+static CacheData *
+_gth_image_preloader_lookup_bigger_size (GthImagePreloader     *self,
+                                        GthFileData            *requested_file,
+                                        int                     requested_size)
+{
+       GList *scan;
+
+       for (scan = self->priv->cache->head; scan; scan = scan->next) {
+               CacheData *cache_data = scan->data;
+               if (cache_data_has_better_quality_for_request (cache_data, requested_file, requested_size))
+                       return cache_data;
+       }
+
+       return NULL;
+}
+
+
 static void
 _gth_image_preloader_request_finished (GthImagePreloader *self,
                                       LoadRequest       *load_request)
@@ -300,13 +356,32 @@ load_current_file (gpointer user_data)
 
 
 static void
-queue_load_next_file (GthImagePreloader *self,
-                     LoadRequest       *request)
+_gth_image_preloader_request_completed (GthImagePreloader *self,
+                                       LoadRequest       *request,
+                                       CacheData         *cache_data)
 {
-       CacheData *cache_data;
+       if (request->current_file == request->requested_file) {
+               if (cache_data != NULL) {
+                       g_simple_async_result_set_op_res_gpointer (request->result,
+                                                                  cache_data_ref (cache_data),
+                                                                  (GDestroyNotify) cache_data_unref);
+                       g_simple_async_result_complete_in_idle (request->result);
+               }
+               else {
+                       GError *error;
+
+                       error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, NULL);
+                       g_simple_async_result_set_from_error (request->result, error);
+
+                       g_error_free (error);
+               }
+       }
+
+       /* queue the next file */
 
        g_return_if_fail (request->current_file != NULL);
 
+       cache_data = NULL;
        do {
                GthFileData *requested_file;
 
@@ -317,9 +392,9 @@ queue_load_next_file (GthImagePreloader *self,
                }
 
                requested_file = (GthFileData *) request->current_file->data;
-               cache_data = _gth_image_preloader_lookup_request (self,
-                                                                 requested_file,
-                                                                 request->requested_size);
+               cache_data = _gth_image_preloader_lookup_same_size (self,
+                                                                   requested_file,
+                                                                   request->requested_size);
        }
        while (cache_data != NULL);
 
@@ -348,22 +423,137 @@ _gth_image_preloader_add_to_cache (GthImagePreloader *self,
 }
 
 
+typedef struct {
+       LoadRequest *request;
+       gboolean     resize_to_requested_size;
+} LoadData;
+
+
+static LoadData *
+load_data_new (LoadRequest *request,
+              gboolean     resize_image)
+{
+       LoadData *load_data;
+
+       load_data = g_new0 (LoadData, 1);
+       load_data->request = load_request_ref (request);
+       load_data->resize_to_requested_size = resize_image;
+
+       return load_data;
+}
+
+
+static void
+load_data_free (LoadData *load_data)
+{
+       load_request_unref (load_data->request);
+       g_free (load_data);
+}
+
+
+static void
+image_scale_ready_cb (GObject      *source_object,
+                     GAsyncResult *result,
+                     gpointer      user_data)
+{
+       LoadData          *load_data = user_data;
+       LoadRequest       *request = load_data->request;
+       GthImagePreloader *self = request->preloader;
+       cairo_surface_t   *surface;
+       GError            *error = NULL;
+       int                original_width;
+       int                original_height;
+       CacheData         *cache_data;
+
+       if (request->finalized) {
+               load_data_free (load_data);
+               return;
+       }
+
+       surface = _cairo_image_surface_scale_finish (result, &error);
+
+       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
+           || (self->priv->last_request != request))
+       {
+               load_data_free (load_data);
+               if (error != NULL)
+                       g_error_free (error);
+               cairo_surface_destroy (surface);
+               _gth_image_preloader_request_finished (self, request);
+
+               if (self->priv->last_request != NULL)
+                       _gth_image_preloader_start_request (self, self->priv->last_request);
+
+               return;
+       }
+
+       if (! _cairo_image_surface_get_original_size (surface, &original_width, &original_height)) {
+               original_width = cairo_image_surface_get_width (surface);
+               original_height = cairo_image_surface_get_height (surface);
+       }
+       cache_data = cache_data_new ();
+       cache_data->file_data = _g_object_ref (request->current_file->data);
+       cache_data->image = (surface != NULL) ? gth_image_new_for_surface (surface) : NULL;
+       cache_data->original_width = (surface != NULL) ? original_width : -1;
+       cache_data->original_height = (surface != NULL) ? original_height : -1;
+       cache_data->requested_size = request->requested_size;
+       cache_data->error = error;
+       _gth_image_preloader_add_to_cache (self, cache_data);
+       _gth_image_preloader_request_completed (self, request, cache_data);
+
+       cairo_surface_destroy (surface);
+       load_data_free (load_data);
+}
+
+
+static void
+_gth_image_preloader_resize_at_requested_size (GthImagePreloader *self,
+                                              LoadRequest       *request,
+                                              GthImage          *image)
+{
+       cairo_surface_t *surface;
+       int              new_width;
+       int              new_height;
+
+       surface = gth_image_get_cairo_surface (image);
+       new_width = cairo_image_surface_get_width (surface);
+       new_height = cairo_image_surface_get_height (surface);
+       scale_keeping_ratio (&new_width,
+                            &new_height,
+                            request->requested_size,
+                            request->requested_size,
+                            FALSE);
+
+       _cairo_image_surface_scale_async (surface,
+                                         new_width,
+                                         new_height,
+                                         SCALE_FILTER_GOOD,
+                                         request->cancellable,
+                                         image_scale_ready_cb,
+                                         load_data_new (request, FALSE));
+
+       cairo_surface_destroy (surface);
+}
+
+
 static void
 image_loader_ready_cb (GObject      *source_object,
                       GAsyncResult *result,
                       gpointer      user_data)
 {
-       LoadRequest       *request = user_data;
+       LoadData          *load_data = user_data;
+       LoadRequest       *request = load_data->request;
        GthImagePreloader *self = request->preloader;
        GthImage          *image = NULL;
        int                original_width;
        int                original_height;
+       gboolean           loaded_original;
        GError            *error = NULL;
        gboolean           success;
        CacheData         *cache_data;
 
        if (request->finalized) {
-               load_request_unref (request);
+               load_data_free (load_data);
                return;
        }
 
@@ -372,12 +562,13 @@ image_loader_ready_cb (GObject      *source_object,
                                                 &image,
                                                 &original_width,
                                                 &original_height,
+                                                &loaded_original,
                                                 &error);
 
        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
            || (self->priv->last_request != request))
        {
-               load_request_unref (request);
+               load_data_free (load_data);
                if (error != NULL)
                        g_error_free (error);
                _g_object_unref (image);
@@ -398,17 +589,16 @@ image_loader_ready_cb (GObject      *source_object,
        cache_data->error = error;
        _gth_image_preloader_add_to_cache (self, cache_data);
 
-       if (request->current_file == request->requested_file) {
-               g_simple_async_result_set_op_res_gpointer (request->result,
-                                                          cache_data_ref (cache_data),
-                                                          (GDestroyNotify) cache_data_unref);
-               g_simple_async_result_complete_in_idle (request->result);
-       }
+       if ((request->requested_size > 0) && loaded_original)
+               load_data->resize_to_requested_size = TRUE;
 
-       queue_load_next_file (self, request);
+       if (load_data->resize_to_requested_size)
+               _gth_image_preloader_resize_at_requested_size (self, request, cache_data->image);
+       else
+               _gth_image_preloader_request_completed (self, request, cache_data);
 
        _g_object_unref (image);
-       load_request_unref (request);
+       load_data_free (load_data);
 }
 
 
@@ -418,33 +608,46 @@ _gth_image_preloader_load_current_file (GthImagePreloader *self,
 {
        GthFileData *requested_file;
        CacheData   *cache_data;
+       gboolean     ignore_requested_size;
 
        g_return_if_fail (request->current_file != NULL);
-
        requested_file = (GthFileData *) request->current_file->data;
-       cache_data = _gth_image_preloader_lookup_request (self,
-                                                         requested_file,
-                                                         request->requested_size);
+
+       /* search the file at the requested size */
+
+       cache_data = _gth_image_preloader_lookup_same_size (self,
+                                                           requested_file,
+                                                           request->requested_size);
        if (cache_data != NULL) {
-               if (request->current_file == request->requested_file) {
-                       g_simple_async_result_set_op_res_gpointer (request->result,
-                                                                  cache_data_ref (cache_data),
-                                                                  (GDestroyNotify) cache_data_unref);
-                       g_simple_async_result_complete_in_idle (request->result);
-               }
-               queue_load_next_file (self, request);
+               _gth_image_preloader_request_completed (self, request, cache_data);
+               return;
+       }
+
+       /* search the file at a bigger size */
 
+       cache_data = _gth_image_preloader_lookup_bigger_size (self,
+                                                             requested_file,
+                                                             request->requested_size);
+       if (cache_data != NULL) {
+               _gth_image_preloader_resize_at_requested_size (self, request, cache_data->image);
                return;
        }
 
-       load_request_ref (request);
+       /* load the file at the requested size */
+
+       if (requested_file == GTH_MODIFIED_IMAGE) {
+               _gth_image_preloader_request_completed (self, request, NULL);
+               return;
+       }
+
+       ignore_requested_size = (request->requested_size > 0) && ! g_file_is_native (requested_file->file);
        gth_image_loader_load (self->priv->loader,
                               requested_file,
-                              request->requested_size,
+                              ignore_requested_size ? -1 : request->requested_size,
                               (request->current_file == request->files) ? G_PRIORITY_HIGH : 
G_PRIORITY_DEFAULT,
                               request->cancellable,
                               image_loader_ready_cb,
-                              request);
+                              load_data_new (request, ignore_requested_size));
 }
 
 
@@ -573,3 +776,37 @@ gth_image_preloader_load_finish (GthImagePreloader  *self,
 
        return TRUE;
 }
+
+
+void
+gth_image_preloader_set_modified_image (GthImagePreloader *self,
+                                       cairo_surface_t   *image)
+{
+       GList     *scan;
+       CacheData *cache_data;
+
+       /* delete the modified image from the cache */
+
+       for (scan = self->priv->cache->head; scan; /* void */) {
+               GList *next = scan->next;
+
+               cache_data = scan->data;
+               if (cache_data->file_data == GTH_MODIFIED_IMAGE)
+                       g_queue_delete_link (self->priv->cache, scan);
+               scan = next;
+       }
+
+       if (image == NULL)
+               return;
+
+       /* add the modified image to the cache */
+
+       cache_data = cache_data_new ();
+       cache_data->file_data = GTH_MODIFIED_IMAGE;
+       cache_data->image = gth_image_new_for_surface (image);
+       cache_data->original_width = -1;
+       cache_data->original_height = -1;
+       cache_data->requested_size = -1;
+       cache_data->error = NULL;
+       _gth_image_preloader_add_to_cache (self, cache_data);
+}
diff --git a/gthumb/gth-image-preloader.h b/gthumb/gth-image-preloader.h
index 0077213..dec9506 100644
--- a/gthumb/gth-image-preloader.h
+++ b/gthumb/gth-image-preloader.h
@@ -27,6 +27,7 @@
 
 #define GTH_ORIGINAL_SIZE -1
 #define GTH_NO_PRELOADERS 0
+#define GTH_MODIFIED_IMAGE NULL
 
 #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))
@@ -48,23 +49,25 @@ struct _GthImagePreloaderClass {
        GObjectClass __parent_class;
 };
 
-GType               gth_image_preloader_get_type         (void) G_GNUC_CONST;
-GthImagePreloader * gth_image_preloader_new              (void);
-void                gth_image_preloader_load             (GthImagePreloader             *self,
-                                                         GthFileData                    *requested,
-                                                         int                             requested_size,
-                                                         GCancellable                   *cancellable,
-                                                         GAsyncReadyCallback             callback,
-                                                         gpointer                        user_data,
-                                                         int                             n_files,
-                                                         ...);
-gboolean            gth_image_preloader_load_finish      (GthImagePreloader             *self,
-                                                         GAsyncResult                   *result,
-                                                         GthFileData                   **requested,
-                                                         GthImage                      **image,
-                                                         int                            *requested_size,
-                                                         int                            *original_width,
-                                                         int                            *original_height,
-                                                         GError                        **error);
+GType               gth_image_preloader_get_type                (void) G_GNUC_CONST;
+GthImagePreloader * gth_image_preloader_new                     (void);
+void                gth_image_preloader_load                    (GthImagePreloader              *self,
+                                                                 GthFileData                    *requested,
+                                                                 int                             
requested_size,
+                                                                 GCancellable                   *cancellable,
+                                                                 GAsyncReadyCallback             callback,
+                                                                 gpointer                        user_data,
+                                                                 int                             n_files,
+                                                                 ...);
+gboolean            gth_image_preloader_load_finish                     (GthImagePreloader              
*self,
+                                                                 GAsyncResult                   *result,
+                                                                 GthFileData                   **requested,
+                                                                 GthImage                      **image,
+                                                                 int                            
*requested_size,
+                                                                 int                            
*original_width,
+                                                                 int                            
*original_height,
+                                                                 GError                        **error);
+void                gth_image_preloader_set_modified_image      (GthImagePreloader              *self,
+                                                                 cairo_surface_t                *image);
 
 #endif /* GTH_IMAGE_PRELOADER_H */
diff --git a/gthumb/gth-image-utils.c b/gthumb/gth-image-utils.c
index ef14751..045030d 100644
--- a/gthumb/gth-image-utils.c
+++ b/gthumb/gth-image-utils.c
@@ -145,6 +145,7 @@ _g_buffer_resize_image (void          *buffer,
                             &width,
                             &height,
                             NULL,
+                            NULL,
                             cancellable,
                             error);
        if (image == NULL) {
diff --git a/gthumb/gth-image.h b/gthumb/gth-image.h
index a4bf01c..49e38d9 100644
--- a/gthumb/gth-image.h
+++ b/gthumb/gth-image.h
@@ -71,6 +71,7 @@ typedef GthImage * (*GthImageLoaderFunc) (GInputStream  *istream,
                                          int            requested_size,
                                          int           *original_width,
                                          int           *original_height,
+                                         gboolean      *loaded_original,
                                          gpointer       user_data,
                                          GCancellable  *cancellable,
                                          GError       **error);
diff --git a/gthumb/gth-overwrite-dialog.c b/gthumb/gth-overwrite-dialog.c
index 33809a8..4191e90 100644
--- a/gthumb/gth-overwrite-dialog.c
+++ b/gthumb/gth-overwrite-dialog.c
@@ -103,6 +103,7 @@ image_loader_ready_cb (GObject      *source_object,
                                            &image,
                                            NULL,
                                            NULL,
+                                           NULL,
                                            &error))
        {
                return;
diff --git a/gthumb/gth-task.c b/gthumb/gth-task.c
index 6136c19..5fe2e66 100644
--- a/gthumb/gth-task.c
+++ b/gthumb/gth-task.c
@@ -214,16 +214,6 @@ gth_task_init (GthTask *self)
 }
 
 
-static void
-cancellable_cancelled_cb (GCancellable *cancellable,
-                         gpointer      user_data)
-{
-       GthTask *task = user_data;
-
-       GTH_TASK_GET_CLASS (task)->cancelled (task);
-}
-
-
 void
 gth_task_exec (GthTask      *task,
               GCancellable *cancellable)
@@ -231,19 +221,7 @@ gth_task_exec (GthTask      *task,
        if (task->priv->running)
                return;
 
-       if (task->priv->cancellable != NULL) {
-               g_cancellable_disconnect (task->priv->cancellable, task->priv->cancellable_cancelled);
-               g_object_unref (task->priv->cancellable);
-       }
-
-       if (cancellable != NULL)
-               task->priv->cancellable = _g_object_ref (cancellable);
-       else
-               task->priv->cancellable = g_cancellable_new ();
-       task->priv->cancellable_cancelled = g_cancellable_connect (task->priv->cancellable,
-                                                                  G_CALLBACK (cancellable_cancelled_cb),
-                                                                  task,
-                                                                  NULL);
+       gth_task_set_cancellable (task, cancellable);
 
        if (task->priv->description != NULL)
                gth_task_progress (task, task->priv->description, NULL, TRUE, 0.0);
@@ -260,6 +238,16 @@ gth_task_is_running (GthTask *task)
 }
 
 
+static void
+cancellable_cancelled_cb (GCancellable *cancellable,
+                         gpointer      user_data)
+{
+       GthTask *task = user_data;
+
+       GTH_TASK_GET_CLASS (task)->cancelled (task);
+}
+
+
 void
 gth_task_cancel (GthTask *task)
 {
@@ -270,6 +258,29 @@ gth_task_cancel (GthTask *task)
 }
 
 
+void
+gth_task_set_cancellable (GthTask      *task,
+                         GCancellable *cancellable)
+{
+       if (task->priv->running)
+               return;
+
+       if (task->priv->cancellable != NULL) {
+               g_cancellable_disconnect (task->priv->cancellable, task->priv->cancellable_cancelled);
+               g_object_unref (task->priv->cancellable);
+       }
+
+       if (cancellable != NULL)
+               task->priv->cancellable = _g_object_ref (cancellable);
+       else
+               task->priv->cancellable = g_cancellable_new ();
+       task->priv->cancellable_cancelled = g_cancellable_connect (task->priv->cancellable,
+                                                                  G_CALLBACK (cancellable_cancelled_cb),
+                                                                  task,
+                                                                  NULL);
+}
+
+
 GCancellable *
 gth_task_get_cancellable (GthTask *task)
 {
diff --git a/gthumb/gth-task.h b/gthumb/gth-task.h
index a8973e0..d21bdb3 100644
--- a/gthumb/gth-task.h
+++ b/gthumb/gth-task.h
@@ -81,6 +81,8 @@ void            gth_task_exec            (GthTask      *task,
                                          GCancellable *cancellable);
 gboolean        gth_task_is_running      (GthTask      *task);
 void            gth_task_cancel          (GthTask      *task);
+void           gth_task_set_cancellable (GthTask      *task,
+                                         GCancellable *cancellable);
 GCancellable *  gth_task_get_cancellable (GthTask      *task);
 void            gth_task_completed       (GthTask      *task,
                                          GError       *error);
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index a1c688c..36f5aa9 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -119,6 +119,7 @@ generate_thumbnail (GInputStream  *istream,
                    int            requested_size,
                    int           *original_width,
                    int           *original_height,
+                   gboolean      *loaded_original,
                    gpointer       user_data,
                    GCancellable  *cancellable,
                    GError       **error)
@@ -187,6 +188,7 @@ generate_thumbnail (GInputStream  *istream,
                                             original_width,
                                             original_height,
                                             NULL,
+                                            NULL,
                                             cancellable,
                                             error);
        }
@@ -206,6 +208,7 @@ load_cached_thumbnail (GInputStream  *istream,
                       int            requested_size,
                       int           *original_width,
                       int           *original_height,
+                      gboolean      *loaded_original,
                       gpointer       user_data,
                       GCancellable  *cancellable,
                       GError       **error)
@@ -443,6 +446,7 @@ cache_image_ready_cb (GObject      *source_object,
                                            &image,
                                            NULL,
                                            NULL,
+                                           NULL,
                                            NULL))
        {
                /* error loading the thumbnail from the cache, try to generate
@@ -757,6 +761,7 @@ original_image_ready_cb (GObject      *source_object,
                                            &image,
                                            &original_width,
                                            &original_height,
+                                           NULL,
                                            &error))
        {
                /* error loading the original image, try with the system
diff --git a/gthumb/pixbuf-io.c b/gthumb/pixbuf-io.c
index 8715364..b826748 100644
--- a/gthumb/pixbuf-io.c
+++ b/gthumb/pixbuf-io.c
@@ -205,6 +205,7 @@ gth_pixbuf_animation_new_from_file (GInputStream  *istream,
                                    int            requested_size,
                                    int           *original_width,
                                    int           *original_height,
+                                   gboolean      *loaded_original,
                                    gpointer       user_data,
                                    GCancellable  *cancellable,
                                    GError       **error)
diff --git a/gthumb/pixbuf-io.h b/gthumb/pixbuf-io.h
index b0ca8f3..f38468a 100644
--- a/gthumb/pixbuf-io.h
+++ b/gthumb/pixbuf-io.h
@@ -43,6 +43,7 @@ GthImage *  gth_pixbuf_animation_new_from_file (GInputStream     *istream,
                                                int               requested_size,
                                                int              *original_width,
                                                int              *original_height,
+                                               gboolean         *loaded_original,
                                                gpointer          user_data,
                                                GCancellable     *cancellable,
                                                GError          **error);



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