use metadata_read_* functions where possible
[geeqie.git] / src / image.c
index 4f279b2..ec601c8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Geeqie
  * (C) 2006 John Ellis
- * Copyright (C) 2008 The Geeqie Team
+ * Copyright (C) 2008 - 2009 The Geeqie Team
  *
  * Author: John Ellis
  *
@@ -18,6 +18,7 @@
 #include "collect.h"
 #include "color-man.h"
 #include "exif.h"
+#include "metadata.h"
 #include "histogram.h"
 #include "image-load.h"
 #include "image-overlay.h"
 
 #include <math.h>
 
-
-/* size of the image loader buffer (512 bytes x defined number) */
-#define IMAGE_LOAD_BUFFER_COUNT 8
-
-/* define this so that more bytes are read per idle loop on larger images (> 1MB) */
-#define IMAGE_THROTTLE_LARGER_IMAGES 1
-
-/* throttle factor to increase read bytes by (2 is double, 3 is triple, etc.) */
-#define IMAGE_THROTTLE_FACTOR 32
-
-/* the file size at which throttling take place */
-#define IMAGE_THROTTLE_THRESHOLD 1048576
-
 static GList *image_list = NULL;
 
-
 static void image_update_title(ImageWindow *imd);
 static void image_read_ahead_start(ImageWindow *imd);
 static void image_cache_set(ImageWindow *imd, FileData *fd);
@@ -169,10 +156,9 @@ static void image_update_title(ImageWindow *imd)
 
        if (imd->collection && collection_to_number(imd->collection) >= 0)
                {
-               const gchar *name;
-               name = imd->collection->name;
+               const gchar *name = imd->collection->name;
                if (!name) name = _("Untitled");
-               collection = g_strdup_printf(" (Collection %s)", name);
+               collection = g_strdup_printf(_(" (Collection %s)"), name);
                }
 
        if (imd->title_show_zoom)
@@ -210,7 +196,7 @@ static gint image_post_process_color(ImageWindow *imd, gint start_row, ExifData
        ColorManProfileType screen_type;
        const gchar *input_file;
        const gchar *screen_file;
-       unsigned char *profile = NULL;
+       guchar *profile = NULL;
        guint profile_len;
 
        if (imd->cm) return FALSE;
@@ -340,7 +326,7 @@ void image_alter(ImageWindow *imd, AlterType type)
        static const gint flip[]         = {1,   4, 3, 2, 1, 8, 7, 6, 5};
 
 
-       if (!imd || !imd->pr) return;
+       if (!imd || !imd->pr || !imd->image_fd) return;
 
        if (imd->orientation < 1 || imd->orientation > 8) imd->orientation = 1;
 
@@ -423,10 +409,6 @@ static void image_read_ahead_done_cb(ImageLoader *il, gpointer data)
                        g_object_ref(imd->read_ahead_fd->pixbuf);
                        image_cache_set(imd, imd->read_ahead_fd);
                        }
-               else
-                       {
-                       imd->read_ahead_fd->pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
-                       }
                }
        image_loader_free(imd->read_ahead_il);
        imd->read_ahead_il = NULL;
@@ -451,9 +433,13 @@ static void image_read_ahead_start(ImageWindow *imd)
        DEBUG_1("%s read ahead started for :%s", get_exec_time(), imd->read_ahead_fd->path);
 
        imd->read_ahead_il = image_loader_new(imd->read_ahead_fd);
+       
+       image_loader_delay_area_ready(imd->read_ahead_il, TRUE); /* we will need the area_ready signals later */
 
-       image_loader_set_error_func(imd->read_ahead_il, image_read_ahead_error_cb, imd);
-       if (!image_loader_start(imd->read_ahead_il, image_read_ahead_done_cb, imd))
+       g_signal_connect (G_OBJECT(imd->read_ahead_il), "error", (GCallback)image_read_ahead_error_cb, imd);
+       g_signal_connect (G_OBJECT(imd->read_ahead_il), "done", (GCallback)image_read_ahead_done_cb, imd);
+
+       if (!image_loader_start(imd->read_ahead_il))
                {
                image_read_ahead_cancel(imd);
                image_complete_util(imd, TRUE);
@@ -485,7 +471,7 @@ static void image_cache_release_cb(FileData *fd)
        fd->pixbuf = NULL;
 }
 
-static FileCacheData *image_get_cache()
+static FileCacheData *image_get_cache(void)
 {
        static FileCacheData *cache = NULL;
        if (!cache) cache = file_cache_new(image_cache_release_cb, 1);
@@ -508,7 +494,7 @@ static gint image_cache_get(ImageWindow *imd)
        if (success)
                {
                g_assert(imd->image_fd->pixbuf);
-               image_change_pixbuf(imd, imd->image_fd->pixbuf, image_zoom_get(imd));
+               image_change_pixbuf(imd, imd->image_fd->pixbuf, image_zoom_get(imd), FALSE);
                }
        
        file_cache_dump(image_get_cache());
@@ -525,7 +511,7 @@ static void image_load_pixbuf_ready(ImageWindow *imd)
 {
        if (image_get_pixbuf(imd) || !imd->il) return;
 
-       image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
+       image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), FALSE);
 }
 
 static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint h, gpointer data)
@@ -541,7 +527,7 @@ static void image_load_area_cb(ImageLoader *il, guint x, guint y, guint w, guint
                return;
                }
 
-       if (!pr->pixbuf) image_load_pixbuf_ready(imd);
+       if (!pr->pixbuf) image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), TRUE);
 
        pixbuf_renderer_area_changed(pr, x, y, w, h);
 }
@@ -557,15 +543,25 @@ static void image_load_done_cb(ImageLoader *il, gpointer data)
 
        if (options->image.enable_read_ahead && imd->image_fd && !imd->image_fd->pixbuf && image_loader_get_pixbuf(imd->il))
                {
-               imd->image_fd->pixbuf = gdk_pixbuf_ref(image_loader_get_pixbuf(imd->il));
+               imd->image_fd->pixbuf = g_object_ref(image_loader_get_pixbuf(imd->il));
                image_cache_set(imd, imd->image_fd);
                }
 
-       if (imd->delay_flip &&
+       if (!image_loader_get_pixbuf(imd->il))
+               {
+               GdkPixbuf *pixbuf;
+
+               pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
+               image_change_pixbuf(imd, pixbuf, image_zoom_get(imd), FALSE);
+               g_object_unref(pixbuf);
+
+               imd->unknown = TRUE;
+               }
+       else if (imd->delay_flip &&
            image_get_pixbuf(imd) != image_loader_get_pixbuf(imd->il))
                {
                g_object_set(G_OBJECT(imd->pr), "complete", FALSE, NULL);
-               image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
+               image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), FALSE);
                }
 
        image_loader_free(imd->il);
@@ -586,20 +582,6 @@ static void image_load_error_cb(ImageLoader *il, gpointer data)
        image_load_done_cb(il, data);
 }
 
-#ifdef IMAGE_THROTTLE_LARGER_IMAGES
-static void image_load_buffer_throttle(ImageLoader *il)
-{
-       if (!il || il->bytes_total < IMAGE_THROTTLE_THRESHOLD) return;
-
-       /* Larger image files usually have larger chunks of data per pixel...
-        * So increase the buffer read size so that the rendering chunks called
-        * are also larger.
-        */
-
-       image_loader_set_buffer_size(il, IMAGE_LOAD_BUFFER_COUNT * IMAGE_THROTTLE_FACTOR);
-}
-#endif
-
 /* this read ahead is located here merely for the callbacks, above */
 
 static gint image_read_ahead_check(ImageWindow *imd)
@@ -619,30 +601,28 @@ static gint image_read_ahead_check(ImageWindow *imd)
                imd->read_ahead_il = NULL;
 
                /* override the old signals */
-               image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
-               image_loader_set_error_func(imd->il, image_load_error_cb, imd);
-               image_loader_set_done_func(imd->il, image_load_done_cb, imd);
-               image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
-
-#ifdef IMAGE_THROTTLE_LARGER_IMAGES
-               image_load_buffer_throttle(imd->il);
-#endif
+               g_signal_handlers_disconnect_matched(G_OBJECT(imd->il), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, imd);
+               g_signal_connect (G_OBJECT(imd->il), "area_ready", (GCallback)image_load_area_cb, imd);
+               g_signal_connect (G_OBJECT(imd->il), "error", (GCallback)image_load_error_cb, imd);
+               g_signal_connect (G_OBJECT(imd->il), "done", (GCallback)image_load_done_cb, imd);
 
                g_object_set(G_OBJECT(imd->pr), "loading", TRUE, NULL);
                image_state_set(imd, IMAGE_STATE_LOADING);
 
                if (!imd->delay_flip)
                        {
-                       image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd));
+                       image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), TRUE);
                        }
 
+               image_loader_delay_area_ready(imd->il, FALSE); /* send the delayed area_ready signals */
+
                file_data_unref(imd->read_ahead_fd);
                imd->read_ahead_fd = NULL;
                return TRUE;
                }
        else if (imd->read_ahead_fd->pixbuf)
                {
-               image_change_pixbuf(imd, imd->read_ahead_fd->pixbuf, image_zoom_get(imd));
+               image_change_pixbuf(imd, imd->read_ahead_fd->pixbuf, image_zoom_get(imd), FALSE);
 
                file_data_unref(imd->read_ahead_fd);
                imd->read_ahead_fd = NULL;
@@ -689,11 +669,11 @@ static gint image_load_begin(ImageWindow *imd, FileData *fd)
 
        imd->il = image_loader_new(fd);
 
-       image_loader_set_area_ready_func(imd->il, image_load_area_cb, imd);
-       image_loader_set_error_func(imd->il, image_load_error_cb, imd);
-       image_loader_set_buffer_size(imd->il, IMAGE_LOAD_BUFFER_COUNT);
+       g_signal_connect (G_OBJECT(imd->il), "area_ready", (GCallback)image_load_area_cb, imd);
+       g_signal_connect (G_OBJECT(imd->il), "error", (GCallback)image_load_error_cb, imd);
+       g_signal_connect (G_OBJECT(imd->il), "done", (GCallback)image_load_done_cb, imd);
 
-       if (!image_loader_start(imd->il, image_load_done_cb, imd))
+       if (!image_loader_start(imd->il))
                {
                DEBUG_1("image start error");
 
@@ -709,12 +689,12 @@ static gint image_load_begin(ImageWindow *imd, FileData *fd)
 
        image_state_set(imd, IMAGE_STATE_LOADING);
 
-#ifdef IMAGE_THROTTLE_LARGER_IMAGES
-       image_load_buffer_throttle(imd->il);
-#endif
-
-       if (!imd->delay_flip && !image_get_pixbuf(imd)) image_load_pixbuf_ready(imd);
-
+/*
+       if (!imd->delay_flip && !image_get_pixbuf(imd) && image_loader_get_pixbuf(imd->il))
+               {
+               image_change_pixbuf(imd, image_loader_get_pixbuf(imd->il), image_zoom_get(imd), TRUE);
+               }
+*/     
        return TRUE;
 }
 
@@ -763,7 +743,7 @@ static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
                        GdkPixbuf *pixbuf;
 
                        pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
-                       image_change_pixbuf(imd, pixbuf, zoom);
+                       image_change_pixbuf(imd, pixbuf, zoom, FALSE);
                        g_object_unref(pixbuf);
 
                        imd->unknown = TRUE;
@@ -776,12 +756,12 @@ static void image_change_complete(ImageWindow *imd, gdouble zoom, gint new)
                        GdkPixbuf *pixbuf;
 
                        pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN);
-                       image_change_pixbuf(imd, pixbuf, zoom);
+                       image_change_pixbuf(imd, pixbuf, zoom, FALSE);
                        g_object_unref(pixbuf);
                        }
                else
                        {
-                       image_change_pixbuf(imd, NULL, zoom);
+                       image_change_pixbuf(imd, NULL, zoom, FALSE);
                        }
                imd->unknown = TRUE;
                }
@@ -1017,30 +997,23 @@ GdkPixbuf *image_get_pixbuf(ImageWindow *imd)
        return pixbuf_renderer_get_pixbuf((PixbufRenderer *)imd->pr);
 }
 
-void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
+void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom, gint lazy)
 {
 
-       ExifData *exif = NULL;
-       gint read_exif_for_color_profile = (imd->color_profile_enable && imd->color_profile_use_image);
-       gint read_exif_for_orientation = FALSE;
 
-       if (imd->image_fd && imd->image_fd->user_orientation)
-               imd->orientation = imd->image_fd->user_orientation;
-       else if (options->image.exif_rotate_enable)
-               read_exif_for_orientation = TRUE;
-
-       if (read_exif_for_color_profile || read_exif_for_orientation)
+       /* read_exif and similar functions can actually notice that the file has changed and triger a notification
+       that removes the pixbuf from cache and unref it. Therefore we must ref it here before it is taken over by the renderer. */
+       if (pixbuf) g_object_ref(pixbuf); 
+       
+       if (imd->image_fd)
                {
-               gint orientation;
-
-               exif = exif_read_fd(imd->image_fd);
-
-               if (exif && read_exif_for_orientation)
+               if (imd->image_fd->user_orientation)
                        {
-                       if (exif_get_integer(exif, "Exif.Image.Orientation", &orientation))
-                               imd->orientation = orientation;
-                       else
-                               imd->orientation = 1;
+                       imd->orientation = imd->image_fd->user_orientation;
+                       }
+               else if (options->image.exif_rotate_enable)
+                       {
+                       imd->orientation = metadata_read_int(imd->image_fd, "Exif.Image.Orientation", EXIF_ORIENTATION_TOP_LEFT);
                        imd->image_fd->exif_orientation = imd->orientation;
                        }
                }
@@ -1052,19 +1025,32 @@ void image_change_pixbuf(ImageWindow *imd, GdkPixbuf *pixbuf, gdouble zoom)
                imd->cm = NULL;
                }
 
-       pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
-       pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
+       if (lazy)
+               {
+               pixbuf_renderer_set_pixbuf_lazy((PixbufRenderer *)imd->pr, pixbuf, zoom, imd->orientation);
+               }
+       else
+               {
+               pixbuf_renderer_set_pixbuf((PixbufRenderer *)imd->pr, pixbuf, zoom);
+               pixbuf_renderer_set_orientation((PixbufRenderer *)imd->pr, imd->orientation);
+               }
+
+       if (pixbuf) g_object_unref(pixbuf);
 
        if (imd->color_profile_enable)
                {
+               ExifData *exif = NULL;
+
+               if (imd->color_profile_use_image) exif = exif_read_fd(imd->image_fd);
+
                if (!image_post_process_color(imd, 0, exif, FALSE))
                        {
                        /* fixme: note error to user */
 //                     image_state_set(imd, IMAGE_STATE_COLOR_ADJ);
                        }
-               }
+               if (exif) exif_free_fd(imd->image_fd, exif);
 
-       exif_free_fd(imd->image_fd, exif);
+               }
 
        if (imd->cm || imd->desaturate)
                pixbuf_renderer_set_post_process_func((PixbufRenderer *)imd->pr, image_post_process_tile_color_cb, (gpointer) imd, (imd->cm != NULL) );
@@ -1098,14 +1084,25 @@ CollectionData *image_get_collection(ImageWindow *imd, CollectInfo **info)
        return NULL;
 }
 
-static void image_loader_sync_data(ImageLoader *il, gpointer data)
+static void image_loader_sync_read_ahead_data(ImageLoader *il, gpointer old_data, gpointer data)
 {
-       /* change data for the callbacks directly */
+       if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_read_ahead_error_cb, old_data))
+               g_signal_connect (G_OBJECT(il), "error", (GCallback)image_read_ahead_error_cb, data);
+
+       if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_read_ahead_done_cb, old_data))
+               g_signal_connect (G_OBJECT(il), "done", (GCallback)image_read_ahead_done_cb, data);
+}
+
+static void image_loader_sync_data(ImageLoader *il, gpointer old_data, gpointer data)
+{              
+       if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_load_area_cb, old_data))
+               g_signal_connect (G_OBJECT(il), "area_ready", (GCallback)image_load_area_cb, data);
 
-       il->data_area_ready = data;
-       il->data_error = data;
-       il->data_done = data;
-       il->data_percent = data;
+       if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_load_error_cb, old_data))
+               g_signal_connect (G_OBJECT(il), "error", (GCallback)image_load_error_cb, data);
+
+       if (g_signal_handlers_disconnect_by_func(G_OBJECT(il), (GCallback)image_load_done_cb, old_data))
+               g_signal_connect (G_OBJECT(il), "done", (GCallback)image_load_done_cb, data);
 }
 
 /* this is more like a move function
@@ -1131,7 +1128,7 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source)
                imd->il = source->il;
                source->il = NULL;
 
-               image_loader_sync_data(imd->il, imd);
+               image_loader_sync_data(imd->il, source, imd);
 
                imd->delay_alter_type = source->delay_alter_type;
                source->delay_alter_type = ALTER_NONE;
@@ -1158,7 +1155,7 @@ void image_change_from_image(ImageWindow *imd, ImageWindow *source)
        image_loader_free(imd->read_ahead_il);
        imd->read_ahead_il = source->read_ahead_il;
        source->read_ahead_il = NULL;
-       if (imd->read_ahead_il) image_loader_sync_data(imd->read_ahead_il, imd);
+       if (imd->read_ahead_il) image_loader_sync_read_ahead_data(imd->read_ahead_il, source, imd);
 
        file_data_unref(imd->read_ahead_fd);
        imd->read_ahead_fd = source->read_ahead_fd;
@@ -1235,7 +1232,7 @@ void image_zoom_set(ImageWindow *imd, gdouble zoom)
        pixbuf_renderer_zoom_set((PixbufRenderer *)imd->pr, zoom);
 }
 
-void image_zoom_set_fill_geometry(ImageWindow *imd, gint vertical)
+void image_zoom_set_fill_geometry(ImageWindow *imd, gboolean vertical)
 {
        PixbufRenderer *pr;
        gdouble zoom;
@@ -1356,7 +1353,7 @@ static void image_notify_cb(FileData *fd, NotifyType type, gpointer data)
        ImageWindow *imd = data;
 
        if (!imd || !image_get_pixbuf(imd) ||
-           /* imd->il || */ /* loading in progress - do not check - it should start from the beginning anyway */ 
+           /* imd->il || */ /* loading in progress - do not check - it should start from the beginning anyway */
            !imd->image_fd || /* nothing to reload */
            imd->state == IMAGE_STATE_NONE /* loading not started, no need to reload */
            ) return;
@@ -1636,10 +1633,19 @@ void image_set_frame(ImageWindow *imd, gboolean frame)
        if (frame)
                {
                imd->frame = gtk_frame_new(NULL);
-               gtk_widget_ref(imd->pr);
+#if GTK_CHECK_VERSION(2,12,0)
+        g_object_ref(imd->pr);
+#else
+        gtk_widget_ref(imd->pr);
+#endif
                if (imd->has_frame != -1) gtk_container_remove(GTK_CONTAINER(imd->widget), imd->pr);
                gtk_container_add(GTK_CONTAINER(imd->frame), imd->pr);
-               gtk_widget_unref(imd->pr);
+
+#if GTK_CHECK_VERSION(2,12,0)
+        g_object_unref(imd->pr);
+#else
+        gtk_widget_unref(imd->pr);
+#endif
                g_signal_connect(G_OBJECT(imd->frame), "expose_event",
                                 G_CALLBACK(selectable_frame_expose_cb), NULL);
 
@@ -1652,21 +1658,37 @@ void image_set_frame(ImageWindow *imd, gboolean frame)
                g_signal_connect_after(G_OBJECT(imd->frame), "expose_event",
                                       G_CALLBACK(image_focus_expose), imd);
 
-
-               gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
-               gtk_widget_show(imd->frame);
+#if GTK_CHECK_VERSION(2,14,0)
+        gtk_box_pack_start(GTK_BOX(imd->widget), imd->frame, TRUE, TRUE, 0);
+#else
+        gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->frame);
+#endif
+        gtk_widget_show(imd->frame);
                }
        else
                {
+#if GTK_CHECK_VERSION(2,12,0)
+               g_object_ref(imd->pr);
+#else
                gtk_widget_ref(imd->pr);
+#endif
                if (imd->frame)
                        {
                        gtk_container_remove(GTK_CONTAINER(imd->frame), imd->pr);
                        gtk_widget_destroy(imd->frame);
                        imd->frame = NULL;
                        }
+#if GTK_CHECK_VERSION(2,14,0)
+        gtk_box_pack_start(GTK_BOX(imd->widget), imd->pr, TRUE, TRUE, 0);
+#else
                gtk_box_pack_start_defaults(GTK_BOX(imd->widget), imd->pr);
-               gtk_widget_unref(imd->pr);
+#endif
+
+#if GTK_CHECK_VERSION(2,12,0)
+       g_object_unref(imd->pr);
+#else
+       gtk_widget_unref(imd->pr);
+#endif
                }
 
        gtk_widget_show(imd->pr);
@@ -1753,3 +1775,4 @@ ImageWindow *image_new(gint frame)
 
        return imd;
 }
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */