[gthumb: 17/40] Fixed other bugs related to image loading cancellation
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb: 17/40] Fixed other bugs related to image loading cancellation
- Date: Fri, 10 Sep 2010 16:57:38 +0000 (UTC)
commit 6e314a9e55faed4523c242d5a1d312b50c7e65ef
Author: Paolo Bacchilega <paobac src gnome org>
Date: Wed Sep 8 17:38:48 2010 +0200
Fixed other bugs related to image loading cancellation
extensions/file_viewer/gth-file-viewer-page.c | 33 ++-
extensions/image_print/gth-load-image-info-task.c | 2 -
extensions/list_tools/gth-script.c | 1 -
extensions/webalbums/gth-web-exporter.c | 2 -
gthumb/gth-browser.c | 8 +-
gthumb/gth-file-list.c | 275 +++++++++++++--------
gthumb/gth-hook.c | 7 +
gthumb/gth-image-loader.c | 28 +--
gthumb/gth-image-loader.h | 7 +-
gthumb/gth-image-preloader.c | 49 +++--
gthumb/gth-main.h | 9 +-
gthumb/gth-overwrite-dialog.c | 2 -
gthumb/gth-thumb-loader.c | 101 +++++---
gthumb/gth-thumb-loader.h | 1 -
gthumb/pixbuf-io.h | 7 +
15 files changed, 340 insertions(+), 192 deletions(-)
---
diff --git a/extensions/file_viewer/gth-file-viewer-page.c b/extensions/file_viewer/gth-file-viewer-page.c
index f2824d7..b90f1bf 100644
--- a/extensions/file_viewer/gth-file-viewer-page.c
+++ b/extensions/file_viewer/gth-file-viewer-page.c
@@ -191,31 +191,46 @@ gth_file_viewer_page_real_can_view (GthViewerPage *base,
}
+typedef struct {
+ GthFileViewerPage *self;
+ GthFileData *file_data;
+} ViewData;
+
+
+static void
+view_data_free (ViewData *view_data)
+{
+ g_object_unref (view_data->file_data);
+ g_object_unref (view_data->self);
+ g_free (view_data);
+}
+
+
static void
thumb_loader_ready_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
- GthFileViewerPage *self = user_data;
- GthFileData *file_data;
+ ViewData *view_data = user_data;
+ GthFileViewerPage *self = view_data->self;
GdkPixbuf *pixbuf;
if (! gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object),
result,
- &file_data,
&pixbuf,
NULL))
{
+ view_data_free (view_data);
return;
}
- if (g_file_equal (self->priv->file_data->file, file_data->file)) {
+ if (g_file_equal (self->priv->file_data->file, view_data->file_data->file)) {
gtk_image_set_from_pixbuf (GTK_IMAGE (self->priv->icon), pixbuf);
gth_viewer_page_file_loaded (GTH_VIEWER_PAGE (self), self->priv->file_data, TRUE);
}
g_object_unref (pixbuf);
- g_object_unref (file_data);
+ view_data_free (view_data);
}
@@ -225,6 +240,7 @@ gth_file_viewer_page_real_view (GthViewerPage *base,
{
GthFileViewerPage *self;
GIcon *icon;
+ ViewData *view_data;
self = (GthFileViewerPage*) base;
g_return_if_fail (file_data != NULL);
@@ -239,11 +255,14 @@ gth_file_viewer_page_real_view (GthViewerPage *base,
gth_viewer_page_focus (GTH_VIEWER_PAGE (self));
+ view_data = g_new0 (ViewData, 1);
+ view_data->self = g_object_ref (self);
+ view_data->file_data = g_object_ref (file_data);
gth_thumb_loader_load (self->priv->thumb_loader,
- self->priv->file_data,
+ view_data->file_data,
NULL,
thumb_loader_ready_cb,
- self);
+ view_data);
}
diff --git a/extensions/image_print/gth-load-image-info-task.c b/extensions/image_print/gth-load-image-info-task.c
index a6b84c3..fbf7dc5 100644
--- a/extensions/image_print/gth-load-image-info-task.c
+++ b/extensions/image_print/gth-load-image-info-task.c
@@ -114,8 +114,6 @@ image_loader_ready_cb (GObject *source_object,
gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
result,
- NULL,
- NULL,
&pixbuf,
NULL,
NULL,
diff --git a/extensions/list_tools/gth-script.c b/extensions/list_tools/gth-script.c
index ec230ac..118a72c 100644
--- a/extensions/list_tools/gth-script.c
+++ b/extensions/list_tools/gth-script.c
@@ -599,7 +599,6 @@ thumb_loader_ready_cb (GObject *source_object,
if (! gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object),
result,
- NULL,
&pixbuf,
NULL))
{
diff --git a/extensions/webalbums/gth-web-exporter.c b/extensions/webalbums/gth-web-exporter.c
index f9d6bec..d1eb060 100644
--- a/extensions/webalbums/gth-web-exporter.c
+++ b/extensions/webalbums/gth-web-exporter.c
@@ -2578,8 +2578,6 @@ image_loader_ready_cb (GObject *source_object,
if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
result,
- NULL,
- NULL,
&pixbuf,
NULL,
NULL,
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 3635ef4..b22e92a 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -2044,7 +2044,9 @@ _gth_browser_close_step4 (gpointer user_data)
{
GthBrowser *browser = user_data;
- gth_file_list_cancel (GTH_FILE_LIST (browser->priv->thumbnail_list), _gth_browser_close_final_step, browser);
+ gth_file_list_cancel (GTH_FILE_LIST (browser->priv->thumbnail_list),
+ _gth_browser_close_final_step,
+ browser);
}
@@ -2053,7 +2055,9 @@ _gth_browser_close_step3 (gpointer user_data)
{
GthBrowser *browser = user_data;
- gth_file_list_cancel (GTH_FILE_LIST (browser->priv->file_list), _gth_browser_close_step4, browser);
+ gth_file_list_cancel (GTH_FILE_LIST (browser->priv->file_list),
+ _gth_browser_close_step4,
+ browser);
}
diff --git a/gthumb/gth-file-list.c b/gthumb/gth-file-list.c
index 5f34680..b0a4a2b 100644
--- a/gthumb/gth-file-list.c
+++ b/gthumb/gth-file-list.c
@@ -34,11 +34,14 @@
#include "gth-thumb-loader.h"
#include "gtk-utils.h"
+
#define DEFAULT_THUMBNAIL_SIZE 112
#define UPDATE_THUMBNAILS_TIMEOUT 200
#define N_LOOKAHEAD 50
#define EMPTY (N_("(Empty)"))
#define THUMBNAIL_BORDER (8 * 2)
+#define CHECK_JOBS_INTERVAL 100
+
typedef enum {
GTH_FILE_LIST_OP_TYPE_SET_FILES,
@@ -107,26 +110,17 @@ struct _GthFileListPrivateData
gboolean ignore_hidden_thumbs;
GHashTable *thumb_data;
GthThumbLoader *thumb_loader;
- gboolean update_thumb_in_view;
- int thumb_pos;
- int n_thumb;
- GthFileData *thumb_fd;
gboolean loading_thumbs;
gboolean cancel;
gboolean dirty;
guint dirty_event;
guint restart_thumb_update;
GList *queue; /* list of GthFileListOp */
+ GList *jobs; /* list of ThumbnailJob */
GtkCellRenderer *thumbnail_renderer;
GtkCellRenderer *text_renderer;
GtkCellRenderer *checkbox_renderer;
-
char **caption_attributes_v;
-
- gboolean can_cancel;
- GCancellable *cancellable;
- DataFunc done_func;
- gpointer done_func_data;
};
@@ -251,7 +245,6 @@ gth_file_list_finalize (GObject *object)
file_list = GTH_FILE_LIST (object);
if (file_list->priv != NULL) {
- g_object_unref (file_list->priv->cancellable);
g_hash_table_unref (file_list->priv->thumb_data);
if (file_list->priv->icon_cache != NULL)
gth_icon_cache_free (file_list->priv->icon_cache);
@@ -354,14 +347,11 @@ static void
gth_file_list_init (GthFileList *file_list)
{
file_list->priv = g_new0 (GthFileListPrivateData, 1);
-
file_list->priv->thumb_data = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, (GDestroyNotify) thumb_data_unref);
file_list->priv->thumb_size = DEFAULT_THUMBNAIL_SIZE;
file_list->priv->ignore_hidden_thumbs = FALSE;
file_list->priv->load_thumbs = TRUE;
file_list->priv->caption_attributes_v = g_strsplit ("none", ",", -1);
- file_list->priv->cancellable = g_cancellable_new ();
- file_list->priv->can_cancel = FALSE;
}
@@ -371,8 +361,6 @@ static void _gth_file_list_update_next_thumb (GthFileList *file_list);
static void
start_update_next_thumb (GthFileList *file_list)
{
- GthFileStore *file_store;
-
if (file_list->priv->loading_thumbs)
return;
@@ -381,8 +369,6 @@ start_update_next_thumb (GthFileList *file_list)
return;
}
- file_store = (GthFileStore*) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
- file_list->priv->n_thumb = -1;
file_list->priv->loading_thumbs = TRUE;
_gth_file_list_update_next_thumb (file_list);
}
@@ -699,39 +685,116 @@ gth_file_list_set_type (GthFileList *file_list,
static void
-_gth_file_list_thumb_cleanup (GthFileList *file_list)
+_gth_file_list_done (GthFileList *file_list)
{
- _g_object_unref (file_list->priv->thumb_fd);
- file_list->priv->thumb_fd = NULL;
+ file_list->priv->loading_thumbs = FALSE;
+ file_list->priv->cancel = FALSE;
}
+
+typedef struct {
+ GthFileList *file_list;
+ GthThumbLoader *loader;
+ GCancellable *cancellable;
+ GthFileData *file_data;
+ gboolean update_in_view;
+} ThumbnailJob;
+
+
static void
-_gth_file_list_done (GthFileList *file_list)
+thumbnail_job_free (ThumbnailJob *job)
{
- _gth_file_list_thumb_cleanup (file_list);
- file_list->priv->loading_thumbs = FALSE;
- file_list->priv->cancel = FALSE;
- g_cancellable_reset (file_list->priv->cancellable);
+ job->file_list->priv->jobs = g_list_remove (job->file_list->priv->jobs, job);
+ _g_object_unref (job->file_data);
+ _g_object_unref (job->cancellable);
+ _g_object_unref (job->loader);
+ _g_object_unref (job->file_list);
+ g_free (job);
}
-void
-gth_file_list_cancel (GthFileList *file_list,
- DataFunc done_func,
- gpointer user_data)
+static void
+thumbnail_job_cancel (ThumbnailJob *job)
{
- _gth_file_list_clear_queue (file_list);
+ g_cancellable_cancel (job->cancellable);
+}
+
+
+typedef struct {
+ GthFileList *file_list;
+ DataFunc done_func;
+ gpointer user_data;
+ guint check_id;
+} CancelData;
+
+
+static void
+cancel_data_free (CancelData *cancel_data)
+{
+ if (cancel_data->check_id != 0)
+ g_source_remove (cancel_data->check_id);
+ g_object_unref (cancel_data->file_list);
+ g_free (cancel_data);
+}
- file_list->priv->done_func = done_func;
- file_list->priv->done_func_data = user_data;
- if (file_list->priv->can_cancel) {
- g_cancellable_cancel (file_list->priv->cancellable);
- file_list->priv->can_cancel = FALSE;
+static gboolean
+wait_for_jobs_to_finish (gpointer user_data)
+{
+ CancelData *cancel_data = user_data;
+
+ if (cancel_data->file_list->priv->jobs == NULL) {
+ if (cancel_data->check_id != 0) {
+ g_source_remove (cancel_data->check_id);
+ cancel_data->check_id = 0;
+ }
+ if (cancel_data->done_func != NULL)
+ cancel_data->done_func (cancel_data->user_data);
+ cancel_data_free (cancel_data);
+ return FALSE;
}
- else
- call_when_idle (done_func, user_data);
+
+ return TRUE;
+}
+
+
+static void
+_gth_file_list_cancel_jobs (GthFileList *file_list,
+ DataFunc done_func,
+ gpointer user_data)
+{
+ CancelData *cancel_data;
+ GList *scan;
+
+ cancel_data = g_new0 (CancelData, 1);
+ cancel_data->file_list = g_object_ref (file_list);
+ cancel_data->done_func = done_func;
+ cancel_data->user_data = user_data;
+
+ if (file_list->priv->jobs == NULL) {
+ cancel_data->check_id = g_idle_add (wait_for_jobs_to_finish, cancel_data);
+ return;
+ }
+
+ for (scan = file_list->priv->jobs; scan; scan = scan->next) {
+ ThumbnailJob *job = scan->data;
+ thumbnail_job_cancel (job);
+ }
+
+ cancel_data->check_id = g_timeout_add (CHECK_JOBS_INTERVAL,
+ wait_for_jobs_to_finish,
+ cancel_data);
+}
+
+
+void
+gth_file_list_cancel (GthFileList *file_list,
+ DataFunc done_func,
+ gpointer user_data)
+{
+ _gth_file_list_clear_queue (file_list);
+ _gth_file_list_cancel_jobs (file_list, done_func, user_data);
}
@@ -1346,25 +1409,32 @@ set_mime_type_icon (GthFileList *file_list,
static void
-thumb_loader_ready_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GthFileList *file_list = user_data;
- ThumbData *thumb_data;
- GthFileData *file_data;
- GdkPixbuf *pixbuf;
- GError *error = NULL;
+thumbnail_job_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ThumbnailJob *job = user_data;
+ GthFileList *file_list = job->file_list;
+ gboolean success;
+ GdkPixbuf *pixbuf = NULL;
+ GError *error = NULL;
+ ThumbData *thumb_data;
- file_list->priv->can_cancel = FALSE;
+ success = gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object),
+ result,
+ &pixbuf,
+ &error);
- if (file_list->priv->thumb_fd == NULL) {
- _gth_file_list_update_next_thumb (file_list);
+ if (! success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ thumbnail_job_free (job);
+ _gth_file_list_done (file_list);
return;
}
- thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_list->priv->thumb_fd->file);
+ thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, job->file_data->file);
if (thumb_data == NULL) {
+ _g_object_unref (pixbuf);
+ thumbnail_job_free (job);
_gth_file_list_update_next_thumb (file_list);
return;
}
@@ -1372,39 +1442,46 @@ thumb_loader_ready_cb (GObject *source_object,
_g_object_unref (thumb_data->pixbuf);
thumb_data->pixbuf = NULL;
- if (! gth_thumb_loader_load_finish (GTH_THUMB_LOADER (source_object),
- result,
- &file_data,
- &pixbuf,
- &error))
- {
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- _gth_file_list_done (file_list);
- if (file_list->priv->done_func)
- (file_list->priv->done_func) (file_list->priv->done_func_data);
- return;
- }
+ if (! success) {
+ thumb_data->thumb_created = FALSE;
+ thumb_data->thumb_loaded = FALSE;
+ if (job->update_in_view)
+ set_mime_type_icon (file_list, job->file_data);
thumb_data->error = TRUE;
- thumb_data->thumb_loaded = FALSE;
- thumb_data->thumb_created = FALSE;
- if (file_list->priv->update_thumb_in_view)
- set_mime_type_icon (file_list, file_list->priv->thumb_fd);
}
else {
- thumb_data->error = FALSE;
+ thumb_data->pixbuf = g_object_ref (pixbuf);
thumb_data->thumb_created = TRUE;
- thumb_data->pixbuf = pixbuf;
- if (file_list->priv->update_thumb_in_view) {
+ thumb_data->error = FALSE;
+ if (job->update_in_view) {
thumb_data->thumb_loaded = TRUE;
- update_thumb_in_file_view (file_list, file_list->priv->thumb_fd);
+ update_thumb_in_file_view (file_list, job->file_data);
}
}
+ _g_object_unref (pixbuf);
+ thumbnail_job_free (job);
+
_gth_file_list_update_next_thumb (file_list);
}
+static gboolean
+start_thumbnail_job (gpointer user_data)
+{
+ ThumbnailJob *job = user_data;
+
+ gth_thumb_loader_load (job->loader,
+ job->file_data,
+ job->cancellable,
+ thumbnail_job_ready_cb,
+ job);
+
+ return FALSE;
+}
+
+
static void
set_loading_icon (GthFileList *file_list,
GthFileData *file_data)
@@ -1434,16 +1511,19 @@ set_loading_icon (GthFileList *file_list,
static void
-_gth_file_list_update_current_thumb (GthFileList *file_list)
+_gth_file_list_update_thumb (GthFileList *file_list,
+ ThumbnailJob *job)
{
- set_loading_icon (file_list, file_list->priv->thumb_fd);
+ GList *scan;
+
+ for (scan = file_list->priv->jobs; scan; scan = scan->next) {
+ ThumbnailJob *job = scan->data;
+ thumbnail_job_cancel (job);
+ }
+ file_list->priv->jobs = g_list_prepend (file_list->priv->jobs, job);
- file_list->priv->can_cancel = TRUE;
- gth_thumb_loader_load (file_list->priv->thumb_loader,
- file_list->priv->thumb_fd,
- file_list->priv->cancellable,
- thumb_loader_ready_cb,
- file_list);
+ set_loading_icon (file_list, job->file_data);
+ g_idle_add (start_thumbnail_job, job);
}
@@ -1506,17 +1586,18 @@ can_create_file_thumbnail (GthFileData *file_data,
static void
_gth_file_list_update_next_thumb (GthFileList *file_list)
{
- GthFileStore *file_store;
- int pos;
- int first_pos;
- int last_pos;
- int max_pos;
- GthFileData *file_data = NULL;
- ThumbData *thumb_data;
- GList *list, *scan;
- int new_pos = -1;
- GTimeVal current_time;
- gboolean young_file_found = FALSE;
+ GthFileStore *file_store;
+ int pos;
+ int first_pos;
+ int last_pos;
+ int max_pos;
+ GthFileData *file_data = NULL;
+ ThumbData *thumb_data;
+ GList *list, *scan;
+ int new_pos = -1;
+ GTimeVal current_time;
+ gboolean young_file_found = FALSE;
+ ThumbnailJob *job;
if (file_list->priv->cancel || (file_list->priv->queue != NULL)) {
g_idle_add (update_thumbs_stopped, file_list);
@@ -1620,14 +1701,14 @@ _gth_file_list_update_next_thumb (GthFileList *file_list)
load the visible ones (and N_LOOKAHEAD before and N_LOOKAHEAD after the visible range),
to minimize memory consumption in large folders. */
- file_list->priv->update_thumb_in_view = (new_pos >= (first_pos - N_LOOKAHEAD)) &&
- (new_pos <= (last_pos + N_LOOKAHEAD));
- file_list->priv->thumb_pos = new_pos;
- _g_object_unref (file_list->priv->thumb_fd);
- file_list->priv->thumb_fd = file_data; /* already ref-ed above */
- file_list->priv->n_thumb++;
+ job = g_new0 (ThumbnailJob, 1);
+ job->file_list = g_object_ref (file_list);
+ job->loader = gth_thumb_loader_new (file_list->priv->thumb_size);
+ job->cancellable = g_cancellable_new ();
+ job->file_data = file_data; /* already ref-ed above */
+ job->update_in_view = (new_pos >= (first_pos - N_LOOKAHEAD)) && (new_pos <= (last_pos + N_LOOKAHEAD));
- _gth_file_list_update_current_thumb (file_list);
+ _gth_file_list_update_thumb (file_list, job);
}
diff --git a/gthumb/gth-hook.c b/gthumb/gth-hook.c
index f9d0e3c..e4ef647 100644
--- a/gthumb/gth-hook.c
+++ b/gthumb/gth-hook.c
@@ -50,6 +50,7 @@ typedef struct {
typedef struct {
GHookList *list;
int n_args;
+ GMutex *mutex;
} GthHook;
@@ -58,6 +59,7 @@ gth_hook_free (GthHook *hook)
{
g_hook_list_clear (hook->list);
g_free (hook->list);
+ g_mutex_free (hook->mutex);
g_free (hook);
}
@@ -95,6 +97,7 @@ gth_hook_register (const char *name,
hook->list = g_new (GHookList, 1);
g_hook_list_init (hook->list, sizeof (GthHookCallback));
hook->n_args = n_args;
+ hook->mutex = g_mutex_new ();
g_hash_table_insert (hooks, g_strdup (name), hook);
}
@@ -261,8 +264,10 @@ gth_hook_invoke (const char *name,
break;
}
+ g_mutex_lock (hook->mutex);
if (invoke_marshaller != NULL)
g_hook_list_marshal (hook->list, TRUE, invoke_marshaller, marshal_data);
+ g_mutex_unlock (hook->mutex);
g_free (marshal_data);
}
@@ -373,8 +378,10 @@ gth_hook_invoke_get (const char *name,
break;
}
+ g_mutex_lock (hook->mutex);
if (invoke_marshaller != NULL)
g_hook_list_marshal (hook->list, TRUE, invoke_marshaller, marshal_data);
+ g_mutex_unlock (hook->mutex);
value = marshal_data[hook->n_args];
diff --git a/gthumb/gth-image-loader.c b/gthumb/gth-image-loader.c
index c047ddb..8dbf562 100644
--- a/gthumb/gth-image-loader.c
+++ b/gthumb/gth-image-loader.c
@@ -152,8 +152,6 @@ load_data_unref (LoadData *load_data)
typedef struct {
- GthFileData *file_data;
- int requested_size;
GdkPixbufAnimation *animation;
int original_width;
int original_height;
@@ -163,7 +161,6 @@ typedef struct {
static void
load_result_unref (LoadResult *load_result)
{
- g_object_unref (load_result->file_data);
if (load_result->animation != NULL)
g_object_unref (load_result->animation);
g_free (load_result);
@@ -214,8 +211,6 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
}
load_result = g_new0 (LoadResult, 1);
- load_result->file_data = g_object_ref (load_data->file_data);
- load_result->requested_size = load_data->requested_size;
load_result->animation = animation;
load_result->original_width = original_width;
load_result->original_height = original_height;
@@ -254,8 +249,6 @@ gth_image_loader_load (GthImageLoader *loader,
gboolean
gth_image_loader_load_animation_finish (GthImageLoader *loader,
GAsyncResult *result,
- GthFileData **file_data,
- int *requested_size,
GdkPixbufAnimation **animation,
int *original_width,
int *original_height,
@@ -272,10 +265,6 @@ gth_image_loader_load_animation_finish (GthImageLoader *loader,
return FALSE;
load_result = g_simple_async_result_get_op_res_gpointer (simple);
- if (file_data != NULL)
- *file_data = g_object_ref (load_result->file_data);
- if (requested_size != NULL)
- *requested_size = load_result->requested_size;
if (animation != NULL)
*animation = g_object_ref (load_result->animation);
if (original_width != NULL)
@@ -290,19 +279,16 @@ gth_image_loader_load_animation_finish (GthImageLoader *loader,
gboolean
gth_image_loader_load_image_finish (GthImageLoader *loader,
GAsyncResult *res,
- GthFileData **file_data,
- int *requested_size,
GdkPixbuf **pixbuf,
int *original_width,
int *original_height,
GError **error)
{
GdkPixbufAnimation *animation;
+ GdkPixbuf *static_image;
if (! gth_image_loader_load_animation_finish (loader,
res,
- file_data,
- requested_size,
&animation,
original_width,
original_height,
@@ -311,7 +297,17 @@ gth_image_loader_load_image_finish (GthImageLoader *loader,
return FALSE;
}
- *pixbuf = gdk_pixbuf_animation_get_static_image (animation);
+ static_image = gdk_pixbuf_animation_get_static_image (animation);
+ if (static_image != NULL) {
+ *pixbuf = gdk_pixbuf_copy (static_image);
+ }
+ else {
+ *pixbuf = NULL;
+ if (error != NULL)
+ *error = g_error_new_literal (GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "No image");
+ }
+
+ g_object_unref (animation);
return TRUE;
}
diff --git a/gthumb/gth-image-loader.h b/gthumb/gth-image-loader.h
index 31d9c2b..e469177 100644
--- a/gthumb/gth-image-loader.h
+++ b/gthumb/gth-image-loader.h
@@ -24,9 +24,8 @@
#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
-#include "typedefs.h"
#include "gth-file-data.h"
-#include "gth-main.h"
+#include "pixbuf-io.h"
G_BEGIN_DECLS
@@ -64,16 +63,12 @@ void gth_image_loader_load (GthImageLoader
gpointer user_data);
gboolean gth_image_loader_load_animation_finish (GthImageLoader *loader,
GAsyncResult *res,
- GthFileData **file_data,
- int *requested_size,
GdkPixbufAnimation **animation,
int *original_width,
int *original_height,
GError **error);
gboolean gth_image_loader_load_image_finish (GthImageLoader *loader,
GAsyncResult *res,
- GthFileData **file_data,
- int *requested_size,
GdkPixbuf **pixbuf,
int *original_width,
int *original_height,
diff --git a/gthumb/gth-image-preloader.c b/gthumb/gth-image-preloader.c
index 314e255..5cfd58a 100644
--- a/gthumb/gth-image-preloader.c
+++ b/gthumb/gth-image-preloader.c
@@ -326,16 +326,30 @@ load_next (gpointer data)
}
+typedef struct {
+ Preloader *preloader;
+ GthFileData *file_data;
+ int requested_size;
+} LoadRequest;
+
+
+static void
+load_request_free (LoadRequest *load_request)
+{
+ g_object_unref (load_request->file_data);
+ g_free (load_request);
+}
+
+
static void
image_loader_ready_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
- Preloader *preloader = user_data;
+ LoadRequest *load_request = user_data;
+ Preloader *preloader = load_request->preloader;
GthImagePreloader *self = preloader->self;
- GthFileData *file_data;
- int requested_size;
- GdkPixbufAnimation *animation;
+ GdkPixbufAnimation *animation = NULL;
int original_width;
int original_height;
GError *error = NULL;
@@ -344,18 +358,16 @@ image_loader_ready_cb (GObject *source_object,
success = gth_image_loader_load_animation_finish (GTH_IMAGE_LOADER (source_object),
result,
- &file_data,
- &requested_size,
&animation,
&original_width,
&original_height,
&error);
- if (! g_file_equal (file_data->file, preloader->file_data->file)
+ if (! g_file_equal (load_request->file_data->file, preloader->file_data->file)
|| (preloader->token != self->priv->token))
{
- g_object_unref (file_data);
- g_object_unref (animation);
+ load_request_free (load_request);
+ _g_object_unref (animation);
if (error != NULL)
g_error_free (error);
return;
@@ -364,14 +376,14 @@ image_loader_ready_cb (GObject *source_object,
interval = NEXT_LOAD_SMALL_TIMEOUT;
_g_object_unref (preloader->animation);
- preloader->animation = g_object_ref (animation);
+ preloader->animation = _g_object_ref (animation);
preloader->original_width = original_width;
preloader->original_height = original_height;
preloader->loaded = success;
preloader->error = ! success;
- preloader->requested_size = requested_size;
+ preloader->requested_size = load_request->requested_size;
- if (_g_file_equal (file_data->file, self->priv->requested_file)) {
+ if (_g_file_equal (load_request->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
@@ -400,8 +412,8 @@ image_loader_ready_cb (GObject *source_object,
if (self->priv->load_id == 0)
self->priv->load_id = g_timeout_add (interval, load_next, self);
- g_object_unref (file_data);
- g_object_unref (animation);
+ load_request_free (load_request);
+ _g_object_unref (animation);
}
@@ -452,6 +464,8 @@ start_next_loader (GthImagePreloader *self)
preloader = current_preloader (self);
if (preloader != NULL) {
+ LoadRequest *load_request;
+
#if DEBUG_PRELOADER
{
char *uri;
@@ -465,13 +479,18 @@ start_next_loader (GthImagePreloader *self)
_g_object_unref (preloader->animation);
preloader->animation = NULL;
+ load_request = g_new0 (LoadRequest, 1);
+ load_request->preloader = preloader;
+ load_request->file_data = g_object_ref (preloader->file_data);
+ load_request->requested_size = preloader->requested_size;
+
g_cancellable_reset (preloader->self->priv->cancellable);
gth_image_loader_load (preloader->loader,
preloader->file_data,
preloader->requested_size,
preloader->self->priv->cancellable,
image_loader_ready_cb,
- preloader);
+ load_request);
}
#if DEBUG_PRELOADER
else
diff --git a/gthumb/gth-main.h b/gthumb/gth-main.h
index f428755..df7458c 100644
--- a/gthumb/gth-main.h
+++ b/gthumb/gth-main.h
@@ -35,6 +35,7 @@
#include "gth-pixbuf-saver.h"
#include "gth-tags-file.h"
#include "gth-test.h"
+#include "pixbuf-io.h"
G_BEGIN_DECLS
@@ -49,14 +50,6 @@ typedef struct _GthMain GthMain;
typedef struct _GthMainPrivate GthMainPrivate;
typedef struct _GthMainClass GthMainClass;
-typedef GdkPixbufAnimation* (*PixbufLoader) (GthFileData *file_data,
- int requested_size,
- int *original_width,
- int *original_height,
- gpointer user_data,
- GCancellable *cancellable,
- GError **error);
-
struct _GthMain {
GObject __parent;
GthMainPrivate *priv;
diff --git a/gthumb/gth-overwrite-dialog.c b/gthumb/gth-overwrite-dialog.c
index 9160c82..cc50d3f 100644
--- a/gthumb/gth-overwrite-dialog.c
+++ b/gthumb/gth-overwrite-dialog.c
@@ -129,8 +129,6 @@ image_loader_ready_cb (GObject *source_object,
if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
result,
- NULL,
- NULL,
&pixbuf,
NULL,
NULL,
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index 1f2efb5..790a961 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -44,6 +44,7 @@
#define THUMBNAIL_NORMAL_SIZE 128
#define THUMBNAIL_DIR_PERMISSIONS 0700
#define MAX_THUMBNAILER_LIFETIME 2000 /* kill the thumbnailer after this amount of time*/
+#define CHECK_CANCELLABLE_DELAY 200
struct _GthThumbLoaderPrivate
{
@@ -289,6 +290,7 @@ typedef struct {
GPid thumbnailer_pid;
guint thumbnailer_watch;
guint thumbnailer_timeout;
+ guint cancellable_watch;
} LoadData;
@@ -352,8 +354,6 @@ cache_image_ready_cb (GObject *source_object,
if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
res,
- NULL,
- NULL,
&pixbuf,
NULL,
NULL,
@@ -375,6 +375,8 @@ cache_image_ready_cb (GObject *source_object,
/* Thumbnail correctly loaded from the cache. Scale if the user wants
* a different size. */
+ g_return_if_fail (pixbuf != NULL);
+
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
modified = scale_keeping_ratio (&width,
@@ -494,13 +496,16 @@ original_image_loaded_correctly (GthThumbLoader *self,
LoadData *load_data,
GdkPixbuf *pixbuf)
{
+ GdkPixbuf *local_pixbuf;
int width;
int height;
gboolean modified;
LoadResult *load_result;
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
+ local_pixbuf = g_object_ref (pixbuf);
+
+ width = gdk_pixbuf_get_width (local_pixbuf);
+ height = gdk_pixbuf_get_height (local_pixbuf);
if (self->priv->save_thumbnails) {
gboolean modified;
@@ -515,12 +520,12 @@ original_image_loaded_correctly (GthThumbLoader *self,
self->priv->cache_max_size,
FALSE);
if (modified) {
- GdkPixbuf *tmp = pixbuf;
- pixbuf = _gdk_pixbuf_scale_simple_safe (tmp, width, height, GDK_INTERP_BILINEAR);
+ GdkPixbuf *tmp = local_pixbuf;
+ local_pixbuf = _gdk_pixbuf_scale_simple_safe (tmp, width, height, GDK_INTERP_BILINEAR);
g_object_unref (tmp);
}
- _gth_thumb_loader_save_to_cache (self, load_data->file_data, pixbuf);
+ _gth_thumb_loader_save_to_cache (self, load_data->file_data, local_pixbuf);
}
/* Scale if the user wants a different size. */
@@ -530,16 +535,18 @@ original_image_loaded_correctly (GthThumbLoader *self,
self->priv->requested_size,
self->priv->cache_max_size);
if (modified) {
- GdkPixbuf *tmp = pixbuf;
- pixbuf = gdk_pixbuf_scale_simple (tmp, width, height, GDK_INTERP_BILINEAR);
+ GdkPixbuf *tmp = local_pixbuf;
+ local_pixbuf = gdk_pixbuf_scale_simple (tmp, width, height, GDK_INTERP_BILINEAR);
g_object_unref (tmp);
}
load_result = g_new0 (LoadResult, 1);
load_result->file_data = g_object_ref (load_data->file_data);
- load_result->pixbuf = g_object_ref (pixbuf);
+ load_result->pixbuf = g_object_ref (local_pixbuf);
g_simple_async_result_set_op_res_gpointer (load_data->simple, load_result, (GDestroyNotify) load_result_unref);
g_simple_async_result_complete_in_idle (load_data->simple);
+
+ g_object_unref (local_pixbuf);
}
@@ -548,7 +555,7 @@ failed_to_load_original_image (GthThumbLoader *self,
LoadData *load_data)
{
char *uri;
- GError *error = NULL;
+ GError *error;
uri = g_file_get_uri (load_data->file_data->file);
gnome_desktop_thumbnail_factory_create_failed_thumbnail (self->priv->thumb_factory,
@@ -574,6 +581,11 @@ kill_thumbnailer_cb (gpointer user_data)
load_data->thumbnailer_timeout = 0;
}
+ if (load_data->cancellable_watch != 0) {
+ g_source_remove (load_data->cancellable_watch);
+ load_data->cancellable_watch = 0;
+ }
+
if (load_data->thumbnailer_pid != 0)
kill (load_data->thumbnailer_pid, SIGTERM);
@@ -581,6 +593,20 @@ kill_thumbnailer_cb (gpointer user_data)
}
+static gboolean
+check_cancellable_cb (gpointer user_data)
+{
+ LoadData *load_data = user_data;
+
+ if (g_cancellable_is_cancelled (load_data->cancellable)) {
+ kill_thumbnailer_cb (user_data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
static void
watch_thumbnailer_cb (GPid pid,
int status,
@@ -595,6 +621,11 @@ watch_thumbnailer_cb (GPid pid,
load_data->thumbnailer_timeout = 0;
}
+ if (load_data->cancellable_watch != 0) {
+ g_source_remove (load_data->cancellable_watch);
+ load_data->cancellable_watch = 0;
+ }
+
g_spawn_close_pid (pid);
load_data->thumbnailer_pid = 0;
load_data->thumbnailer_watch = 0;
@@ -620,13 +651,11 @@ original_image_ready_cb (GObject *source_object,
{
LoadData *load_data = user_data;
GthThumbLoader *self = load_data->thumb_loader;
- GdkPixbuf *pixbuf;
+ GdkPixbuf *pixbuf = NULL;
GError *error = NULL;
if (! gth_image_loader_load_image_finish (GTH_IMAGE_LOADER (source_object),
res,
- NULL,
- NULL,
&pixbuf,
NULL,
NULL,
@@ -637,6 +666,12 @@ original_image_ready_cb (GObject *source_object,
char *uri;
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_simple_async_result_set_from_error (load_data->simple, error);
+ g_simple_async_result_complete_in_idle (load_data->simple);
+ return;
+ }
+
g_clear_error (&error);
uri = g_file_get_uri (load_data->file_data->file);
@@ -653,6 +688,9 @@ original_image_ready_cb (GObject *source_object,
load_data->thumbnailer_timeout = g_timeout_add (MAX_THUMBNAILER_LIFETIME,
kill_thumbnailer_cb,
load_data);
+ load_data->cancellable_watch = g_timeout_add (CHECK_CANCELLABLE_DELAY,
+ check_cancellable_cb,
+ load_data);
}
else
failed_to_load_original_image (self, load_data);
@@ -663,7 +701,6 @@ original_image_ready_cb (GObject *source_object,
}
original_image_loaded_correctly (self, load_data, pixbuf);
-
g_object_unref (pixbuf);
}
@@ -691,12 +728,11 @@ gth_thumb_loader_load (GthThumbLoader *self,
uri = g_file_get_uri (file_data->file);
mtime = gth_file_data_get_mtime (file_data);
- cache_path = gnome_desktop_thumbnail_factory_lookup (self->priv->thumb_factory, uri, mtime);
- if ((cache_path == NULL) && gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (self->priv->thumb_factory, uri, mtime)) {
+ if (gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (self->priv->thumb_factory, uri, mtime)) {
GError *error;
- error = g_error_new_literal (GTH_ERROR, 0, "failed thumbnail");
+ error = g_error_new_literal (GTH_ERROR, 0, "found a failed thumbnail");
g_simple_async_result_set_from_error (simple, error);
g_simple_async_result_complete_in_idle (simple);
@@ -706,6 +742,8 @@ gth_thumb_loader_load (GthThumbLoader *self,
return;
}
+ cache_path = gnome_desktop_thumbnail_factory_lookup (self->priv->thumb_factory, uri, mtime);
+
g_free (uri);
}
@@ -724,7 +762,7 @@ gth_thumb_loader_load (GthThumbLoader *self,
gth_image_loader_load (self->priv->iloader,
cache_file_data,
-1,
- cancellable,
+ load_data->cancellable,
cache_image_ready_cb,
load_data);
@@ -747,7 +785,7 @@ gth_thumb_loader_load (GthThumbLoader *self,
gth_image_loader_load (self->priv->tloader,
file_data,
self->priv->requested_size,
- cancellable,
+ load_data->cancellable,
original_image_ready_cb,
load_data);
}
@@ -756,25 +794,22 @@ gth_thumb_loader_load (GthThumbLoader *self,
gboolean
gth_thumb_loader_load_finish (GthThumbLoader *self,
GAsyncResult *result,
- GthFileData **file_data,
GdkPixbuf **pixbuf,
GError **error)
{
- GSimpleAsyncResult *simple;
- LoadResult *load_result;
+ GSimpleAsyncResult *simple;
+ LoadResult *load_result;
- g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), gth_thumb_loader_load), FALSE);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), gth_thumb_loader_load), FALSE);
- simple = G_SIMPLE_ASYNC_RESULT (result);
+ simple = G_SIMPLE_ASYNC_RESULT (result);
- if (g_simple_async_result_propagate_error (simple, error))
- return FALSE;
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
- load_result = g_simple_async_result_get_op_res_gpointer (simple);
- if (file_data != NULL)
- *file_data = g_object_ref (load_result->file_data);
- if (pixbuf != NULL)
- *pixbuf = g_object_ref (load_result->pixbuf);
+ load_result = g_simple_async_result_get_op_res_gpointer (simple);
+ if (pixbuf != NULL)
+ *pixbuf = _g_object_ref (load_result->pixbuf);
- return TRUE;
+ return TRUE;
}
diff --git a/gthumb/gth-thumb-loader.h b/gthumb/gth-thumb-loader.h
index 855cac6..a441130 100644
--- a/gthumb/gth-thumb-loader.h
+++ b/gthumb/gth-thumb-loader.h
@@ -72,7 +72,6 @@ void gth_thumb_loader_load (GthThumbLoader *s
gpointer user_data);
gboolean gth_thumb_loader_load_finish (GthThumbLoader *self,
GAsyncResult *res,
- GthFileData **file_data,
GdkPixbuf **pixbuf,
GError **error);
diff --git a/gthumb/pixbuf-io.h b/gthumb/pixbuf-io.h
index 0fb29d7..8ff6af0 100644
--- a/gthumb/pixbuf-io.h
+++ b/gthumb/pixbuf-io.h
@@ -30,6 +30,13 @@
G_BEGIN_DECLS
+typedef GdkPixbufAnimation* (*PixbufLoader) (GthFileData *file_data,
+ int requested_size,
+ int *original_width,
+ int *original_height,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error);
typedef struct {
GFile *file;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]