summaryrefslogtreecommitdiff
path: root/libeog
diff options
context:
space:
mode:
authorJens Finke <jens@triq.net>2003-03-11 16:15:36 +0000
committerJens Finke <jens@src.gnome.org>2003-03-11 16:15:36 +0000
commit7e21ea9c5e33b5642dc0b1b47bacbd72ee9166a5 (patch)
tree41985d1c6a192d9aecdffb54842db60d06ec730c /libeog
parentac8360af67c2e88655a7fc1f4a148413d081732e (diff)
downloadeog-7e21ea9c5e33b5642dc0b1b47bacbd72ee9166a5.tar.gz
Switched to a thread based loading mechanism. (eog_image_dispose): Free
2003-03-11 Jens Finke <jens@triq.net> * libeog/eog-image.[ch]: Switched to a thread based loading mechanism. (eog_image_dispose): Free mutex. (check_load_status): New function. (load_area_updated), (load_size_prepared), (real_image_load), (eog_image_load): Reworked, so that they use the thread based approach. (eog_image_get_pixbuf): Add mutex around pixbuf accessing. (eog_image_cancel_load): New function. * libeog/eog-scroll-view.c (free_image_resources): Cancel loading of the previous shown image. * shell/eog-window.c (property_changed_cb): Be quite.
Diffstat (limited to 'libeog')
-rw-r--r--libeog/eog-image.c219
-rw-r--r--libeog/eog-image.h1
-rw-r--r--libeog/eog-scroll-view.c3
3 files changed, 184 insertions, 39 deletions
diff --git a/libeog/eog-image.c b/libeog/eog-image.c
index 6e4657e3..2ed25d9d 100644
--- a/libeog/eog-image.c
+++ b/libeog/eog-image.c
@@ -18,6 +18,15 @@ static GQueue *jobs_done = NULL;
static gint dispatch_callbacks_id = -1;
static GStaticMutex jobs_mutex = G_STATIC_MUTEX_INIT;
+enum {
+ EOG_IMAGE_LOAD_STATUS_NONE = 0,
+ EOG_IMAGE_LOAD_STATUS_PREPARED = 1 << 0,
+ EOG_IMAGE_LOAD_STATUS_UPDATED = 1 << 1,
+ EOG_IMAGE_LOAD_STATUS_DONE = 1 << 2,
+ EOG_IMAGE_LOAD_STATUS_FAILED = 1 << 3,
+ EOG_IMAGE_LOAD_STATUS_CANCELLED = 1 << 4
+};
+
struct _EogImagePrivate {
GnomeVFSURI *uri;
EogImageLoadMode mode;
@@ -28,13 +37,25 @@ struct _EogImagePrivate {
gint width;
gint height;
- gint load_idle_id;
gint thumbnail_id;
gboolean modified;
gchar *caption;
gchar *caption_key;
+
+ GThread *load_thread;
+ gint load_id;
+ GMutex *status_mutex;
+ gint load_status;
+ gboolean cancel_loading;
+
+ /* data which depends on the load status */
+ int update_x1;
+ int update_y1;
+ int update_x2;
+ int update_y2;
+ char *error_message;
};
enum {
@@ -61,6 +82,8 @@ static gint eog_image_signals [SIGNAL_LAST];
static int n_active_images = 0;
#endif
+#define CHECK_LOAD_TIMEOUT 5
+
/*============================================
static thumbnail loader for all image objects
@@ -288,6 +311,11 @@ eog_image_dispose (GObject *object)
g_free (priv->caption_key);
priv->caption_key = NULL;
}
+
+ if (priv->status_mutex) {
+ g_mutex_free (priv->status_mutex);
+ priv->status_mutex = NULL;
+ }
}
static void
@@ -411,6 +439,7 @@ eog_image_instance_init (EogImage *img)
priv->thumbnail = NULL;
priv->width = priv->height = -1;
priv->modified = FALSE;
+ priv->status_mutex = g_mutex_new ();
img->priv = priv;
}
@@ -427,6 +456,7 @@ eog_image_new_uri (GnomeVFSURI *uri, EogImageLoadMode mode)
priv->uri = gnome_vfs_uri_ref (uri);
priv->mode = mode;
priv->modified = FALSE;
+ priv->load_thread = NULL;
#if OBJECT_WATCH
n_active_images++;
@@ -459,12 +489,78 @@ eog_image_error_quark (void)
return q;
}
+static gboolean
+check_load_status (gpointer data)
+{
+ EogImage *img;
+ EogImagePrivate *priv;
+ int load_status;
+ int x, y, width, height;
+ gboolean call_again = TRUE;
+
+ img = EOG_IMAGE (data);
+ priv = img->priv;
+
+ g_mutex_lock (priv->status_mutex);
+
+ g_source_remove (priv->load_id);
+ priv->load_id = -1;
+
+ load_status = priv->load_status;
+ x = priv->update_x1;
+ y = priv->update_y1;
+ width = priv->update_x2 - x;
+ height = priv->update_y2 - y;
+
+ priv->load_status = 0;
+ priv->update_x1 = 10000;
+ priv->update_y1 = 10000;
+ priv->update_x2 = 0;
+ priv->update_y2 = 0;
+
+ g_mutex_unlock (priv->status_mutex);
+
+ if ((load_status & EOG_IMAGE_LOAD_STATUS_FAILED) > 0) {
+ g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_FAILED], 0, priv->error_message);
+ call_again = FALSE;
+ }
+
+ if ((load_status & EOG_IMAGE_LOAD_STATUS_CANCELLED) > 0) {
+ g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_CANCELLED], 0);
+ call_again = FALSE;
+ }
+
+ if ((load_status & EOG_IMAGE_LOAD_STATUS_PREPARED) > 0) {
+ g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_SIZE_PREPARED], 0, priv->width, priv->height);
+ }
+
+ if ((load_status & EOG_IMAGE_LOAD_STATUS_UPDATED) > 0) {
+ g_signal_emit (img, eog_image_signals [SIGNAL_LOADING_UPDATE], 0,
+ x, y, width, height);
+ }
+
+ if ((load_status & EOG_IMAGE_LOAD_STATUS_DONE) > 0) {
+ g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_FINISHED], 0);
+ call_again = FALSE;
+ }
+
+ if (call_again) {
+ priv->load_id = g_timeout_add (CHECK_LOAD_TIMEOUT, check_load_status, img);
+ }
+ else {
+ g_object_unref (img);
+ }
+
+ return FALSE;
+}
+
static void
load_area_updated (GdkPixbufLoader *loader, gint x, gint y, gint width, gint height, gpointer data)
{
EogImage *img;
EogImagePrivate *priv;
+ int x2, y2;
img = EOG_IMAGE (data);
@@ -474,17 +570,27 @@ load_area_updated (GdkPixbufLoader *loader, gint x, gint y, gint width, gint hei
priv = img->priv;
+ g_mutex_lock (priv->status_mutex);
+ priv->load_status |= EOG_IMAGE_LOAD_STATUS_UPDATED;
+
if (priv->image == NULL) {
- g_print ("get pixbuf.\n");
priv->image = gdk_pixbuf_loader_get_pixbuf (loader);
g_object_ref (priv->image);
}
+
+ x2 = x + width;
+ y2 = y + height;
+
+ priv->update_x1 = MIN (priv->update_x1, x);
+ priv->update_y1 = MIN (priv->update_y1, y);
+ priv->update_x2 = MAX (priv->update_x2, x2);
+ priv->update_y2 = MAX (priv->update_y2, y2);
+
+ g_mutex_unlock (priv->status_mutex);
#ifdef DEBUG
g_print ("area_updated: x: %i, y: %i, width: %i, height: %i\n", x, y, width, height);
#endif
-
- g_signal_emit (img, eog_image_signals [SIGNAL_LOADING_UPDATE], 0, x, y, width, height);
}
static void
@@ -496,13 +602,16 @@ load_size_prepared (GdkPixbufLoader *loader, gint width, gint height, gpointer d
img = EOG_IMAGE (data);
+ g_mutex_lock (img->priv->status_mutex);
+ img->priv->load_status |= EOG_IMAGE_LOAD_STATUS_PREPARED;
+
img->priv->width = width;
img->priv->height = height;
-
- g_signal_emit (img, eog_image_signals [SIGNAL_LOADING_SIZE_PREPARED], 0, width, height);
+ g_mutex_unlock (img->priv->status_mutex);
}
-static gboolean
+/* this function runs in it's own thread */
+static gpointer
real_image_load (gpointer data)
{
EogImage *img;
@@ -525,10 +634,12 @@ real_image_load (gpointer data)
result = gnome_vfs_open_uri (&handle, priv->uri, GNOME_VFS_OPEN_READ);
if (result != GNOME_VFS_OK) {
- g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_FAILED], 0, gnome_vfs_result_to_string (result));
- g_print ("VFS Error: %s\n", gnome_vfs_result_to_string (result));
- g_object_unref (img);
- return FALSE;
+ g_mutex_lock (priv->status_mutex);
+ priv->load_status |= EOG_IMAGE_LOAD_STATUS_FAILED;
+ priv->error_message = (char*) gnome_vfs_result_to_string (result);
+ g_mutex_unlock (priv->status_mutex);
+
+ return NULL;
}
buffer = g_new0 (guchar, 4096);
@@ -540,7 +651,7 @@ real_image_load (gpointer data)
g_signal_connect_object (G_OBJECT (loader), "size-prepared", (GCallback) load_size_prepared, img, 0);
}
- while (TRUE) {
+ while (!priv->cancel_loading) {
result = gnome_vfs_read (handle, buffer, 4096, &bytes_read);
if (result == GNOME_VFS_ERROR_EOF || bytes_read == 0) {
break;
@@ -554,24 +665,29 @@ real_image_load (gpointer data)
failed = TRUE;
break;
}
-
- if (priv->mode == EOG_IMAGE_LOAD_PROGRESSIVE) {
- while (gtk_events_pending ()) {
- gtk_main_iteration ();
- }
- }
}
g_free (buffer);
gnome_vfs_close (handle);
+ g_mutex_lock (priv->status_mutex);
+
if (failed) {
if (priv->image != NULL) {
g_object_unref (priv->image);
priv->image = NULL;
}
+ priv->load_status |= EOG_IMAGE_LOAD_STATUS_FAILED;
+ priv->error_message = NULL; /* FIXME: add descriptive error message */
+ }
+ else if (priv->cancel_loading) {
+ if (priv->image != NULL) {
+ g_object_unref (priv->image);
+ priv->image = NULL;
+ }
+ priv->cancel_loading = TRUE;
- g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_FAILED], 0);
+ priv->load_status |= EOG_IMAGE_LOAD_STATUS_CANCELLED;
}
else {
if (priv->image == NULL) {
@@ -580,19 +696,19 @@ real_image_load (gpointer data)
priv->width = gdk_pixbuf_get_width (priv->image);
priv->height = gdk_pixbuf_get_height (priv->image);
- g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_SIZE_PREPARED],
- 0, priv->width, priv->height);
+ priv->load_status |= EOG_IMAGE_LOAD_STATUS_PREPARED;
}
-
- g_signal_emit (G_OBJECT (img), eog_image_signals [SIGNAL_LOADING_FINISHED], 0);
- }
+ priv->load_status |= EOG_IMAGE_LOAD_STATUS_DONE;
+ }
+
+ priv->load_thread = NULL;
+ g_mutex_unlock (priv->status_mutex);
+
gdk_pixbuf_loader_close (loader, NULL);
- priv->load_idle_id = 0;
g_object_unref (loader);
- g_object_unref (img);
- return FALSE;
+ return NULL;
}
gboolean
@@ -604,7 +720,7 @@ eog_image_load (EogImage *img)
g_return_val_if_fail (priv->uri != NULL, FALSE);
- if (priv->image == NULL && priv->load_idle_id == 0)
+ if (priv->image == NULL && priv->load_thread == NULL)
{
if (priv->mode == EOG_IMAGE_LOAD_DEFAULT) {
if (gnome_vfs_uri_is_local (priv->uri)) {
@@ -637,9 +753,16 @@ eog_image_load (EogImage *img)
}
}
- g_object_ref (img); /* make sure the object isn't destroyed when we enter the
- idle callback */
- priv->load_idle_id = g_idle_add (real_image_load, img);
+ g_object_ref (img); /* make sure the object isn't destroyed while we try to load it */
+ priv->load_status = EOG_IMAGE_LOAD_STATUS_NONE;
+ priv->update_x1 = 10000;
+ priv->update_y1 = 10000;
+ priv->update_x2 = 0;
+ priv->update_y2 = 0;
+ priv->error_message = NULL;
+ priv->cancel_loading = FALSE;
+ priv->load_id = g_timeout_add (CHECK_LOAD_TIMEOUT, check_load_status, img);
+ priv->load_thread = g_thread_create (real_image_load, img, TRUE, NULL);
}
return (priv->image != NULL);
@@ -671,15 +794,19 @@ eog_image_is_animation (EogImage *img)
GdkPixbuf*
eog_image_get_pixbuf (EogImage *img)
{
+ GdkPixbuf *image = NULL;
+
g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
- if (img->priv->image != 0) {
- g_object_ref (img->priv->image);
- return img->priv->image;
- }
- else {
- return 0;
+ g_mutex_lock (img->priv->status_mutex);
+ image = img->priv->image;
+ g_mutex_unlock (img->priv->status_mutex);
+
+ if (image != NULL) {
+ g_object_ref (image);
}
+
+ return image;
}
GdkPixbuf*
@@ -919,3 +1046,21 @@ eog_image_get_collate_key (EogImage *img)
return priv->caption_key;
}
+
+void
+eog_image_cancel_load (EogImage *img)
+{
+ EogImagePrivate *priv;
+
+ g_return_if_fail (EOG_IS_IMAGE (img));
+
+ priv = img->priv;
+
+ if (priv->load_thread != NULL) {
+ priv->cancel_loading = TRUE;
+
+ g_thread_join (priv->load_thread);
+
+ g_assert (priv->load_thread == NULL);
+ }
+}
diff --git a/libeog/eog-image.h b/libeog/eog-image.h
index 0a205096..1fd6a478 100644
--- a/libeog/eog-image.h
+++ b/libeog/eog-image.h
@@ -64,6 +64,7 @@ EogImage* eog_image_new (const char *txt_ur
EogImage* eog_image_new_uri (GnomeVFSURI *uri, EogImageLoadMode mode);
gboolean eog_image_load (EogImage *img);
gboolean eog_image_load_thumbnail (EogImage *img);
+void eog_image_cancel_load (EogImage *img);
void eog_image_free_mem (EogImage *img);
/* saving API */
diff --git a/libeog/eog-scroll-view.c b/libeog/eog-scroll-view.c
index 57f18537..b63b03c5 100644
--- a/libeog/eog-scroll-view.c
+++ b/libeog/eog-scroll-view.c
@@ -134,6 +134,7 @@ free_image_resources (EogScrollView *view)
}
if (priv->image != NULL) {
+ eog_image_cancel_load (priv->image);
g_object_unref (priv->image);
priv->image = NULL;
}
@@ -216,8 +217,6 @@ update_scrollbar_values (EogScrollView *view)
if (!GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->hbar)) && !GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->vbar)))
return;
- g_print ("update scrollbar values\n");
-
compute_scaled_size (view, priv->zoom, &scaled_width, &scaled_height);
allocation = &GTK_WIDGET (priv->display)->allocation;