[gthumb/ext: 29/79] Fixed many issues related to the thumbnailer



commit 95f7873201cae50c1510e4ed3d2b7cbed2c32342
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Mon Jun 29 00:39:45 2009 +0200

    Fixed many issues related to the thumbnailer
    
    Force the thumbnailer to stop when closing the window or
    changing directory;  Kill the thumbnailer if it lasts more then
    3 seconds;  Update the thumbnail icons every 250 msec instead of
    every 20 thumbnails.

 gthumb/gnome-desktop-thumbnail.c |  204 +++++++++++++++++++++++++-------------
 gthumb/gnome-desktop-thumbnail.h |   10 ++-
 gthumb/gth-file-list.c           |   96 +++++++++++++++++-
 gthumb/gth-file-store.c          |    7 +-
 gthumb/gth-main-default-types.c  |   26 +++++-
 gthumb/gth-main.c                |   12 +--
 gthumb/gth-thumb-loader.c        |  171 +++++++++++++++++++++++++-------
 7 files changed, 407 insertions(+), 119 deletions(-)
---
diff --git a/gthumb/gnome-desktop-thumbnail.c b/gthumb/gnome-desktop-thumbnail.c
index 0927f91..ca81ad5 100644
--- a/gthumb/gnome-desktop-thumbnail.c
+++ b/gthumb/gnome-desktop-thumbnail.c
@@ -77,21 +77,21 @@ typedef struct {
 #define LOAD_BUFFER_SIZE 4096
 
 static void
-size_prepared_cb (GdkPixbufLoader *loader, 
+size_prepared_cb (GdkPixbufLoader *loader,
 		  int              width,
 		  int              height,
 		  gpointer         data)
 {
   SizePrepareContext *info = data;
-  
+
   g_return_if_fail (width > 0 && height > 0);
-  
+
   info->input_width = width;
   info->input_height = height;
-  
+
   if (width < info->width && height < info->height) return;
-  
-  if (info->preserve_aspect_ratio && 
+
+  if (info->preserve_aspect_ratio &&
       (info->width > 0 || info->height > 0)) {
     if (info->width < 0)
       {
@@ -117,7 +117,7 @@ size_prepared_cb (GdkPixbufLoader *loader,
     if (info->height > 0)
       height = info->height;
   }
-  
+
   gdk_pixbuf_loader_set_size (loader, width, height);
 }
 
@@ -131,7 +131,7 @@ _gdk_pixbuf_new_from_uri_at_scale (const char *uri,
     char buffer[LOAD_BUFFER_SIZE];
     gsize bytes_read;
     GdkPixbufLoader *loader;
-    GdkPixbuf *pixbuf;	
+    GdkPixbuf *pixbuf;
     GdkPixbufAnimation *animation;
     GdkPixbufAnimationIter *iter;
     gboolean has_frame;
@@ -154,7 +154,7 @@ _gdk_pixbuf_new_from_uri_at_scale (const char *uri,
         info.width = width;
         info.height = height;
 	info.input_width = info.input_height = 0;
-        info.preserve_aspect_ratio = preserve_aspect_ratio;        
+        info.preserve_aspect_ratio = preserve_aspect_ratio;
         g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
     }
 
@@ -227,11 +227,11 @@ gnome_desktop_thumbnail_factory_finalize (GObject *object)
   GnomeDesktopThumbnailFactory *factory;
   GnomeDesktopThumbnailFactoryPrivate *priv;
   GConfClient *client;
-  
+
   factory = GNOME_DESKTOP_THUMBNAIL_FACTORY (object);
 
   priv = factory->priv;
-  
+
   g_free (priv->application);
   priv->application = NULL;
 
@@ -246,7 +246,7 @@ gnome_desktop_thumbnail_factory_finalize (GObject *object)
     priv->thumbnailers_notify = 0;
     g_object_unref (client);
   }
-  
+
   if (priv->scripts_hash)
     {
       g_hash_table_destroy (priv->scripts_hash);
@@ -258,10 +258,10 @@ gnome_desktop_thumbnail_factory_finalize (GObject *object)
       g_mutex_free (priv->lock);
       priv->lock = NULL;
     }
-  
+
   g_free (priv);
   factory->priv = NULL;
-  
+
   if (G_OBJECT_CLASS (parent_class)->finalize)
     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
 }
@@ -284,12 +284,12 @@ read_scripts (void)
       g_object_unref (G_OBJECT (client));
       return NULL;
     }
-  
+
   scripts_hash = g_hash_table_new_full (g_str_hash,
 					g_str_equal,
 					g_free, g_free);
 
-  
+
   subdirs = gconf_client_all_dirs (client, "/desktop/gnome/thumbnailers", NULL);
 
   for (l = subdirs; l != NULL; l = l->next)
@@ -310,7 +310,7 @@ read_scripts (void)
 	    if (mimetype != NULL)
 	      {
 		mimetype++; /* skip past slash */
-		
+
 		/* Convert '@' to slash in mimetype */
 		escape = strchr (mimetype, '@');
 		if (escape != NULL)
@@ -330,14 +330,14 @@ read_scripts (void)
 	  }
 	}
       g_free (enable);
-      
+
       g_free (subdir);
     }
-  
+
   g_slist_free(subdirs);
 
   g_object_unref (G_OBJECT (client));
-  
+
   return scripts_hash;
 }
 
@@ -355,9 +355,9 @@ gnome_desktop_thumbnail_factory_reread_scripts (GnomeDesktopThumbnailFactory *fa
 
   if (priv->scripts_hash != NULL)
     g_hash_table_destroy (priv->scripts_hash);
-  
+
   priv->scripts_hash = scripts_hash;
-  
+
   g_mutex_unlock (priv->lock);
 }
 
@@ -372,7 +372,7 @@ reread_idle_callback (gpointer user_data)
   g_mutex_lock (priv->lock);
   priv->reread_scheduled = 0;
   g_mutex_unlock (priv->lock);
-   
+
   return FALSE;
 }
 
@@ -392,7 +392,7 @@ schedule_reread (GConfClient* client,
       priv->reread_scheduled = g_idle_add (reread_idle_callback,
 					   factory);
     }
-  
+
   g_mutex_unlock (priv->lock);
 }
 
@@ -402,16 +402,16 @@ gnome_desktop_thumbnail_factory_init (GnomeDesktopThumbnailFactory *factory)
 {
   GConfClient *client;
   GnomeDesktopThumbnailFactoryPrivate *priv;
-  
+
   factory->priv = g_new0 (GnomeDesktopThumbnailFactoryPrivate, 1);
 
   priv = factory->priv;
 
   priv->size = GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL;
   priv->application = g_strdup ("gnome-thumbnail-factory");
-  
+
   priv->scripts_hash = NULL;
-  
+
   priv->lock = g_mutex_new ();
 
   gnome_desktop_thumbnail_factory_reread_scripts (factory);
@@ -434,7 +434,7 @@ gnome_desktop_thumbnail_factory_class_init (GnomeDesktopThumbnailFactoryClass *c
   GObjectClass *gobject_class;
 
   gobject_class = G_OBJECT_CLASS (class);
-	
+
   gobject_class->finalize = gnome_desktop_thumbnail_factory_finalize;
 }
 
@@ -445,7 +445,7 @@ gnome_desktop_thumbnail_factory_class_init (GnomeDesktopThumbnailFactoryClass *c
  * Creates a new #GnomeDesktopThumbnailFactory.
  *
  * This function must be called on the main thread.
- * 
+ *
  * Return value: a new #GnomeDesktopThumbnailFactory
  *
  * Since: 2.2
@@ -454,11 +454,11 @@ GnomeDesktopThumbnailFactory *
 gnome_desktop_thumbnail_factory_new (GnomeDesktopThumbnailSize size)
 {
   GnomeDesktopThumbnailFactory *factory;
-  
+
   factory = g_object_new (GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, NULL);
-  
+
   factory->priv->size = size;
-  
+
   return factory;
 }
 
@@ -500,7 +500,7 @@ gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory,
   g_assert (digest_len == 16);
 
   file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
-  
+
   path = g_build_filename (g_get_home_dir (),
 			   ".thumbnails",
 			   (priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
@@ -591,23 +591,23 @@ mimetype_supported_by_gdk_pixbuf (const char *mime_type)
 
 	if (!formats_hash) {
 		GSList *formats, *list;
-		
+
 		formats_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
 		formats = gdk_pixbuf_get_formats ();
 		list = formats;
-		
+
 		while (list) {
 			GdkPixbufFormat *format = list->data;
 			gchar **mime_types;
-			
+
 			mime_types = gdk_pixbuf_format_get_mime_types (format);
 
 			for (i = 0; mime_types[i] != NULL; i++)
 				g_hash_table_insert (formats_hash,
 						     (gpointer) g_strdup (mime_types[i]),
-						     GUINT_TO_POINTER (1));	
-				
+						     GUINT_TO_POINTER (1));
+
 			g_strfreev (mime_types);
 			list = list->next;
 		}
@@ -647,7 +647,7 @@ gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *fac
       strncmp (uri, "file:/", 6) == 0 &&
       strstr (uri, "/.thumbnails/") != NULL)
     return FALSE;
-  
+
   if (mime_type != NULL &&
       (mimetype_supported_by_gdk_pixbuf (mime_type) ||
        (factory->priv->scripts_hash != NULL &&
@@ -657,13 +657,13 @@ gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *fac
 								  uri,
 								  mtime);
     }
-  
+
   return FALSE;
 }
 
 static char *
 expand_thumbnailing_script (const char *script,
-			    const int   size, 
+			    const int   size,
 			    const char *inuri,
 			    const char *outfile)
 {
@@ -673,7 +673,7 @@ expand_thumbnailing_script (const char *script,
   gboolean got_in;
 
   str = g_string_new (NULL);
-  
+
   got_in = FALSE;
   last = script;
   while ((p = strchr (last, '%')) != NULL)
@@ -764,7 +764,7 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
   g_return_val_if_fail (mime_type != NULL, NULL);
 
   /* Doesn't access any volatile fields in factory, so it's threadsafe */
-  
+
   size = 128;
   if (factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE)
     size = 256;
@@ -774,7 +774,7 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
   script = NULL;
   if (factory->priv->scripts_hash != NULL)
     script = g_hash_table_lookup (factory->priv->scripts_hash, mime_type);
-  
+
   if (script)
     {
       int fd;
@@ -814,7 +814,7 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
                                                                 "gnome-original-height"));
         }
     }
-      
+
   if (pixbuf == NULL)
     return NULL;
 
@@ -827,7 +827,7 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
 
   width = gdk_pixbuf_get_width (pixbuf);
   height = gdk_pixbuf_get_height (pixbuf);
-  
+
   if (width > size || height > size)
     {
       const gchar *orig_width, *orig_height;
@@ -846,11 +846,11 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
       if (orig_height != NULL) {
 	      gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Height", orig_height);
       }
-      
+
       g_object_unref (pixbuf);
       pixbuf = scaled;
     }
-  
+
   if (original_width > 0) {
 	  g_snprintf (dimension, sizeof (dimension), "%i", original_width);
 	  gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Width", dimension);
@@ -863,6 +863,76 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
   return pixbuf;
 }
 
+
+gboolean
+gnome_desktop_thumbnail_factory_generate_thumbnail_async (GnomeDesktopThumbnailFactory *factory,
+							  const char            *uri,
+							  const char            *mime_type,
+							  GPid                  *pid,
+							  char                 **tmpname,
+							  GError               **error)
+{
+	gboolean   retval = FALSE;
+	int        size;
+	char      *script;
+	int        fd;
+	char      *expanded_script;
+	int        argc;
+	char     **argv;
+
+	g_return_val_if_fail (uri != NULL, FALSE);
+	g_return_val_if_fail (mime_type != NULL, FALSE);
+
+	size = 128;
+	if (factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE)
+		size = 256;
+
+	script = NULL;
+	if (factory->priv->scripts_hash != NULL)
+		script = g_hash_table_lookup (factory->priv->scripts_hash, mime_type);
+
+	if (script == NULL)
+		return FALSE;
+
+	fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", tmpname, error);
+	if (fd == -1)
+		return FALSE;
+	close (fd);
+
+	expanded_script = expand_thumbnailing_script (script, size, uri, *tmpname);
+	if (g_shell_parse_argv (expanded_script, &argc, &argv, error))
+		if (g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, pid, error))
+			retval = TRUE;
+
+	g_free (expanded_script);
+
+	return retval;
+}
+
+
+GdkPixbuf *
+gnome_desktop_thumbnail_factory_load_from_tempfile (GnomeDesktopThumbnailFactory  *factory,
+						    char                         **tmpname)
+{
+	GdkPixbuf *pixbuf;
+	GdkPixbuf *tmp_pixbuf;
+
+	pixbuf = gdk_pixbuf_new_from_file (*tmpname, NULL);
+	g_unlink (*tmpname);
+	g_free (*tmpname);
+	*tmpname = NULL;
+
+	if (pixbuf == NULL)
+		return NULL;
+
+	tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
+	g_object_unref (pixbuf);
+	pixbuf = tmp_pixbuf;
+
+	return pixbuf;
+}
+
+
 static gboolean
 make_thumbnail_dirs (GnomeDesktopThumbnailFactory *factory)
 {
@@ -892,7 +962,7 @@ make_thumbnail_dirs (GnomeDesktopThumbnailFactory *factory)
 
   g_free (thumbnail_dir);
   g_free (image_dir);
-  
+
   return res;
 }
 
@@ -936,7 +1006,7 @@ make_thumbnail_fail_dirs (GnomeDesktopThumbnailFactory *factory)
   g_free (thumbnail_dir);
   g_free (fail_dir);
   g_free (app_dir);
-  
+
   return res;
 }
 
@@ -944,9 +1014,9 @@ make_thumbnail_fail_dirs (GnomeDesktopThumbnailFactory *factory)
 /**
  * gnome_desktop_thumbnail_factory_save_thumbnail:
  * @factory: a #GnomeDesktopThumbnailFactory
- * @thumbnail: the thumbnail as a pixbuf 
+ * @thumbnail: the thumbnail as a pixbuf
  * @uri: the uri of a file
- * @original_mtime: the modification time of the original file 
+ * @original_mtime: the modification time of the original file
  *
  * Saves @thumbnail at the right place. If the save fails a
  * failed thumbnail is written.
@@ -979,12 +1049,12 @@ gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *fa
   g_assert (digest_len == 16);
 
   file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
-  
+
   dir = g_build_filename (g_get_home_dir (),
 			  ".thumbnails",
 			  (priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
 			  NULL);
-  
+
   path = g_build_filename (dir,
 			   file,
 			   NULL);
@@ -1012,12 +1082,12 @@ gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *fa
       return;
     }
   close (tmp_fd);
-  
+
   g_snprintf (mtime_str, 21, "%ld",  original_mtime);
   width = gdk_pixbuf_get_option (thumbnail, "tEXt::Thumb::Image::Width");
   height = gdk_pixbuf_get_option (thumbnail, "tEXt::Thumb::Image::Height");
 
-  if (width != NULL && height != NULL) 
+  if (width != NULL && height != NULL)
     saved_ok  = gdk_pixbuf_save (thumbnail,
 				 tmp_path,
 				 "png", NULL,
@@ -1035,7 +1105,7 @@ gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *fa
 				 "tEXt::Thumb::MTime", mtime_str,
 				 "tEXt::Software", "GNOME::ThumbnailFactory",
 				 NULL);
-    
+
 
   if (saved_ok)
     {
@@ -1087,12 +1157,12 @@ gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFa
   g_assert (digest_len == 16);
 
   file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
-  
+
   dir = g_build_filename (g_get_home_dir (),
 			  ".thumbnails/fail",
 			  factory->priv->application,
 			  NULL);
-  
+
   path = g_build_filename (dir,
 			   file,
 			   NULL);
@@ -1119,12 +1189,12 @@ gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFa
       return;
     }
   close (tmp_fd);
-  
+
   g_snprintf (mtime_str, 21, "%ld",  mtime);
   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
   saved_ok  = gdk_pixbuf_save (pixbuf,
 			       tmp_path,
-			       "png", NULL, 
+			       "png", NULL,
 			       "tEXt::Thumb::URI", uri,
 			       "tEXt::Thumb::MTime", mtime_str,
 			       "tEXt::Software", "GNOME::ThumbnailFactory",
@@ -1184,13 +1254,13 @@ gnome_desktop_thumbnail_path_for_uri (const char         *uri,
   md5 = gnome_desktop_thumbnail_md5 (uri);
   file = g_strconcat (md5, ".png", NULL);
   g_free (md5);
-  
+
   path = g_build_filename (g_get_home_dir (),
 			   ".thumbnails",
 			   (size == GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL)?"normal":"large",
 			   file,
 			   NULL);
-    
+
   g_free (file);
 
   return path;
@@ -1213,7 +1283,7 @@ gnome_desktop_thumbnail_has_uri (GdkPixbuf          *pixbuf,
 				 const char         *uri)
 {
   const char *thumb_uri;
-  
+
   thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI");
   if (!thumb_uri)
     return FALSE;
@@ -1241,19 +1311,19 @@ gnome_desktop_thumbnail_is_valid (GdkPixbuf          *pixbuf,
 {
   const char *thumb_uri, *thumb_mtime_str;
   time_t thumb_mtime;
-  
+
   thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI");
   if (!thumb_uri)
     return FALSE;
   if (strcmp (uri, thumb_uri) != 0)
     return FALSE;
-  
+
   thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime");
   if (!thumb_mtime_str)
     return FALSE;
   thumb_mtime = atol (thumb_mtime_str);
   if (mtime != thumb_mtime)
     return FALSE;
-  
+
   return TRUE;
 }
diff --git a/gthumb/gnome-desktop-thumbnail.h b/gthumb/gnome-desktop-thumbnail.h
index c7537de..dfdc1af 100644
--- a/gthumb/gnome-desktop-thumbnail.h
+++ b/gthumb/gnome-desktop-thumbnail.h
@@ -50,7 +50,7 @@ typedef struct _GnomeDesktopThumbnailFactoryPrivate GnomeDesktopThumbnailFactory
 
 struct _GnomeDesktopThumbnailFactory {
 	GObject parent;
-	
+
 	GnomeDesktopThumbnailFactoryPrivate *priv;
 };
 
@@ -75,6 +75,14 @@ gboolean               gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDeskt
 GdkPixbuf *            gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory,
 									   const char            *uri,
 									   const char            *mime_type);
+gboolean               gnome_desktop_thumbnail_factory_generate_thumbnail_async (GnomeDesktopThumbnailFactory *factory,
+										 const char            *uri,
+										 const char            *mime_type,
+										 GPid                  *pid,
+										 char                 **tmpname,
+										 GError               **error);
+GdkPixbuf *            gnome_desktop_thumbnail_factory_load_from_tempfile (GnomeDesktopThumbnailFactory *factory,
+									   char **tmpname);
 void                   gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *factory,
 								       GdkPixbuf             *thumbnail,
 								       const char            *uri,
diff --git a/gthumb/gth-file-list.c b/gthumb/gth-file-list.c
index 319122e..a150d2c 100644
--- a/gthumb/gth-file-list.c
+++ b/gthumb/gth-file-list.c
@@ -37,6 +37,7 @@
 
 #define DEFAULT_THUMBNAIL_SIZE 112
 #define N_THUMBS_PER_NOTIFICATION 15
+#define UPDATE_THUMBNAILS_TIMEOUT 250
 #define N_LOOKAHEAD 50
 #define EMPTY (N_("(Empty)"))
 
@@ -96,6 +97,8 @@ struct _GthFileListPrivateData
 	GthFileData     *thumb_fd;
 	gboolean         loading_thumbs;
 	gboolean         cancel;
+	gboolean         dirty;
+	guint            dirty_event;
 	GList           *queue; /* list of GthFileListOp */
 	GtkCellRenderer *thumbnail_renderer;
 	GtkCellRenderer *text_renderer;
@@ -154,6 +157,11 @@ gth_file_list_op_free (GthFileListOp *op)
 static void
 _gth_file_list_clear_queue (GthFileList *file_list)
 {
+	if (file_list->priv->dirty_event != 0) {
+		g_source_remove (file_list->priv->dirty_event);
+		file_list->priv->dirty = FALSE;
+	}
+
 	g_list_foreach (file_list->priv->queue, (GFunc) gth_file_list_op_free, NULL);
 	g_list_free (file_list->priv->queue);
 	file_list->priv->queue = NULL;
@@ -249,6 +257,23 @@ gth_file_list_init (GthFileList *file_list)
 static void _gth_file_list_update_next_thumb (GthFileList *file_list);
 
 
+static gboolean
+flash_queue_cb (gpointer data)
+{
+	GthFileList *file_list = data;
+	GthFileStore *file_store;
+
+	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
+	gth_file_store_exec_set (file_store);
+
+	g_source_remove (file_list->priv->dirty_event);
+	file_list->priv->dirty_event = 0;
+	file_list->priv->dirty = FALSE;
+
+	return FALSE;
+}
+
+
 static void
 update_thumb_in_file_view (GthFileList *file_list)
 {
@@ -258,16 +283,46 @@ update_thumb_in_file_view (GthFileList *file_list)
 	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
 
 	pixbuf = gth_thumb_loader_get_pixbuf (file_list->priv->thumb_loader);
-	if (pixbuf != NULL)
+	if (pixbuf != NULL) {
 		gth_file_store_queue_set (file_store,
 					  gth_file_store_get_abs_pos (file_store, file_list->priv->thumb_pos),
 					  NULL,
 					  pixbuf,
 					  FALSE,
 					  NULL);
+		file_list->priv->dirty = TRUE;
+		if (file_list->priv->dirty_event == 0)
+			file_list->priv->dirty_event = g_timeout_add (UPDATE_THUMBNAILS_TIMEOUT, flash_queue_cb, file_list);
+	}
+}
 
-	if (file_list->priv->n_thumb % N_THUMBS_PER_NOTIFICATION == N_THUMBS_PER_NOTIFICATION - 1)
-		gth_file_store_exec_set (file_store);
+
+static void
+set_mime_type_icon (GthFileList *file_list,
+		    GthFileData *file_data)
+{
+	GthFileStore *file_store;
+	int           pos;
+	GIcon        *icon;
+	GdkPixbuf    *pixbuf;
+
+	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
+
+	pos = gth_file_store_find (file_store, file_data->file);
+	if (pos < 0)
+		return;
+
+	icon = g_file_info_get_icon (file_data->info);
+	pixbuf = gth_icon_cache_get_pixbuf (file_list->priv->icon_cache, icon);
+	gth_file_store_queue_set (file_store,
+				  pos,
+				  NULL,
+				  pixbuf,
+				  TRUE,
+				  NULL);
+
+	if (pixbuf != NULL)
+		g_object_unref (pixbuf);
 }
 
 
@@ -291,8 +346,11 @@ thumb_loader_ready_cb (GthThumbLoader *tloader,
 			file_list->priv->thumb_fd->error = TRUE;
 			file_list->priv->thumb_fd->thumb_loaded = FALSE;
 			file_list->priv->thumb_fd->thumb_created = FALSE;
+			if (file_list->priv->update_thumb_in_view)
+				set_mime_type_icon (file_list, file_list->priv->thumb_fd);
 		}
 	}
+
 	_gth_file_list_update_next_thumb (file_list);
 }
 
@@ -715,7 +773,7 @@ gfl_update_files (GthFileList *file_list,
 						  abs_pos,
 						  fd,
 						  NULL,
-						  FALSE,
+						  -1,
 						  NULL);
 	}
 	gth_file_store_exec_set (file_store);
@@ -949,8 +1007,38 @@ _gth_file_list_thumbs_completed (GthFileList *file_list)
 
 
 static void
+set_loading_icon (GthFileList *file_list,
+		  GthFileData *file_data)
+{
+	GthFileStore *file_store;
+	int           pos;
+	GIcon        *icon;
+	GdkPixbuf    *pixbuf;
+
+	file_store = (GthFileStore *) gth_file_view_get_model (GTH_FILE_VIEW (file_list->priv->view));
+
+	pos = gth_file_store_find (file_store, file_data->file);
+	if (pos < 0)
+		return;
+
+	icon = g_themed_icon_new ("image-loading");
+	pixbuf = gth_icon_cache_get_pixbuf (file_list->priv->icon_cache, icon);
+	gth_file_store_queue_set (file_store,
+				  pos,
+				  NULL,
+				  pixbuf,
+				  TRUE,
+				  NULL);
+
+	_g_object_unref (pixbuf);
+	g_object_unref (icon);
+}
+
+
+static void
 _gth_file_list_update_current_thumb (GthFileList *file_list)
 {
+	set_loading_icon (file_list, file_list->priv->thumb_fd);
 	gth_thumb_loader_set_file (file_list->priv->thumb_loader, file_list->priv->thumb_fd);
 	gth_thumb_loader_load (file_list->priv->thumb_loader);
 }
diff --git a/gthumb/gth-file-store.c b/gthumb/gth-file-store.c
index ee12c01..00ee185 100644
--- a/gthumb/gth-file-store.c
+++ b/gthumb/gth-file-store.c
@@ -1162,7 +1162,7 @@ gth_file_store_find (GthFileStore *file_store,
 			continue;
 
 		if (g_file_equal (row->file->file, file))
-			return i;
+			return row->abs_pos;
 	}
 
 	return -1;
@@ -1182,7 +1182,7 @@ gth_file_store_find_visible (GthFileStore *file_store,
 			continue;
 
 		if (g_file_equal (row->file->file, file))
-			return i;
+			return row->pos;
 	}
 
 	return -1;
@@ -1272,7 +1272,8 @@ gth_file_store_queue_set (GthFileStore *file_store,
 	_gth_file_row_set_file (row, file);
 	_gth_file_row_set_thumbnail (row, thumbnail);
 	_gth_file_row_set_metadata (row, metadata);
-	row->is_icon = is_icon;
+	if (is_icon != -1)
+		row->is_icon = is_icon;
 	row->changed = TRUE;
 
 	if (file != NULL)
diff --git a/gthumb/gth-main-default-types.c b/gthumb/gth-main-default-types.c
index 64b33ff..9cc7609 100644
--- a/gthumb/gth-main-default-types.c
+++ b/gthumb/gth-main-default-types.c
@@ -25,10 +25,34 @@
 #include <glib/gi18n.h>
 #include "gth-file-properties.h"
 #include "gth-main.h"
+#include "pixbuf-io.h"
 
 
-void 
+static void
+gth_main_register_default_file_loader (void)
+{
+	GSList *formats;
+	GSList *scan;
+
+	formats = gdk_pixbuf_get_formats ();
+	for (scan = formats; scan; scan = scan->next) {
+		GdkPixbufFormat  *format = scan->data;
+		char            **mime_types;
+		int               i;
+
+		if (gdk_pixbuf_format_is_disabled (format))
+			continue;
+
+		mime_types = gdk_pixbuf_format_get_mime_types (format);
+		for (i = 0; mime_types[i] != NULL; i++)
+			gth_main_register_file_loader (gth_pixbuf_animation_new_from_file, mime_types[i], NULL);
+	}
+}
+
+
+void
 gth_main_register_default_types (void)
 {
 	gth_main_register_type ("file-properties", GTH_TYPE_FILE_PROPERTIES);
+	gth_main_register_default_file_loader ();
 }
diff --git a/gthumb/gth-main.c b/gthumb/gth-main.c
index 4993022..c5385ea 100644
--- a/gthumb/gth-main.c
+++ b/gthumb/gth-main.c
@@ -718,9 +718,9 @@ gth_main_register_file_loader (FileLoader  loader,
 	va_start (var_args, first_mime_type);
 	mime_type = first_mime_type;
   	while (mime_type != NULL) {
-		mime_type = va_arg (var_args, const char *);
 		g_hash_table_insert (Main->priv->loaders, (gpointer) get_static_string (mime_type), loader);
-	}
+		mime_type = va_arg (var_args, const char *);
+  	}
 	va_end (var_args);
 }
 
@@ -728,13 +728,7 @@ gth_main_register_file_loader (FileLoader  loader,
 FileLoader
 gth_main_get_file_loader (const char *mime_type)
 {
-	FileLoader loader;
-
-	loader = g_hash_table_lookup (Main->priv->loaders, mime_type);
-	if (loader == NULL)
-		loader = gth_pixbuf_animation_new_from_file;
-
-	return loader;
+	return (FileLoader) g_hash_table_lookup (Main->priv->loaders, mime_type);
 }
 
 
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index 164c3f5..0baa2c7 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -24,6 +24,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
 #define GDK_PIXBUF_ENABLE_BACKEND
 #include <gtk/gtk.h>
 #include <gdk-pixbuf/gdk-pixbuf-animation.h>
@@ -39,10 +41,11 @@
 #include "pixbuf-utils.h"
 #include "typedefs.h"
 
-#define DEFAULT_MAX_FILE_SIZE (4*1024*1024)
-#define THUMBNAIL_LARGE_SIZE	256
-#define THUMBNAIL_NORMAL_SIZE	128
+#define DEFAULT_MAX_FILE_SIZE     (4*1024*1024)
+#define THUMBNAIL_LARGE_SIZE	  256
+#define THUMBNAIL_NORMAL_SIZE	  128
 #define THUMBNAIL_DIR_PERMISSIONS 0700
+#define KILL_THUMBNAILER_DELAY    3000
 
 struct _GthThumbLoaderPrivateData
 {
@@ -65,6 +68,10 @@ struct _GthThumbLoaderPrivateData
 
 	GnomeDesktopThumbnailSize     thumb_size;
 	GnomeDesktopThumbnailFactory *thumb_factory;
+	char                         *thumbnailer_tmpfile;
+	GPid                          thumbnailer_pid;
+	guint                         thumbnailer_watch;
+	guint                         thumbnailer_timeout;
 };
 
 
@@ -89,8 +96,8 @@ gth_thumb_loader_finalize (GObject *object)
 	tloader = GTH_THUMB_LOADER (object);
 
 	if (tloader->priv != NULL) {
-		if (tloader->priv->pixbuf != NULL)
-			g_object_unref (tloader->priv->pixbuf);
+		g_free (tloader->priv->thumbnailer_tmpfile);
+		_g_object_unref (tloader->priv->pixbuf);
 		g_object_unref (tloader->priv->iloader);
 		g_object_unref (tloader->priv->file);
 		g_free (tloader->priv);
@@ -260,10 +267,10 @@ _gth_thumb_loader_save_to_cache (GthThumbLoader *tloader)
 
 static void
 image_loader_loaded (GthImageLoader *iloader,
+		     GdkPixbuf      *pixbuf,
 		     gpointer        data)
 {
 	GthThumbLoader *tloader = data;
-	GdkPixbuf      *pixbuf;
 	int             width, height;
 	gboolean        modified;
 
@@ -272,7 +279,6 @@ image_loader_loaded (GthImageLoader *iloader,
 		tloader->priv->pixbuf = NULL;
 	}
 
-	pixbuf = gth_image_loader_get_pixbuf (tloader->priv->iloader);
 	if (pixbuf == NULL) {
 		char *uri;
 
@@ -372,15 +378,107 @@ image_loader_error (GthImageLoader *iloader,
 }
 
 
+static gboolean
+kill_thumbnailer_cb (gpointer data)
+{
+	GthThumbLoader *tloader = data;
+
+	g_source_remove (tloader->priv->thumbnailer_timeout);
+	tloader->priv->thumbnailer_timeout = 0;
+
+	if (tloader->priv->thumbnailer_pid != 0) {
+		/*g_source_remove (tloader->priv->thumbnailer_watch);
+		tloader->priv->thumbnailer_watch = 0;*/
+		kill (tloader->priv->thumbnailer_pid, SIGTERM);
+		/*tloader->priv->thumbnailer_pid = 0;*/
+	}
+
+	return FALSE;
+}
+
+
+static void
+watch_thumbnailer_cb (GPid     pid,
+                      int      status,
+                      gpointer data)
+{
+	GthThumbLoader *tloader = data;
+	GdkPixbuf      *pixbuf;
+	GError         *error;
+
+	if (tloader->priv->thumbnailer_timeout != 0) {
+		g_source_remove (tloader->priv->thumbnailer_timeout);
+		tloader->priv->thumbnailer_timeout = 0;
+	}
+
+	g_spawn_close_pid (pid);
+	tloader->priv->thumbnailer_pid = 0;
+	tloader->priv->thumbnailer_watch = 0;
+
+	if (status != 0) {
+		error = g_error_new_literal (GTHUMB_ERROR, 0, "cannot generate the thumbnail");
+		image_loader_error (NULL, error, data);
+		return;
+	}
+
+	pixbuf = gnome_desktop_thumbnail_factory_load_from_tempfile (tloader->priv->thumb_factory,
+								     &tloader->priv->thumbnailer_tmpfile);
+	if (pixbuf != NULL) {
+		image_loader_loaded (NULL, pixbuf, data);
+		g_object_unref (pixbuf);
+	}
+	else {
+		error = g_error_new_literal (GTHUMB_ERROR, 0, "cannot generate the thumbnail");
+		image_loader_error (NULL, error, data);
+	}
+}
+
+
 static void
 image_loader_ready_cb (GthImageLoader *iloader,
 		       GError         *error,
 		       gpointer        data)
 {
-	if (error == NULL)
-		image_loader_loaded (iloader, data);
-	else
+	GthThumbLoader *tloader = data;
+	char           *uri;
+
+	if (error == NULL) {
+		image_loader_loaded (iloader, gth_image_loader_get_pixbuf (tloader->priv->iloader), data);
+		return;
+	}
+
+	if (tloader->priv->from_cache) {
 		image_loader_error (iloader, error, data);
+		return;
+	}
+
+	/* try with the system thumbnailer as fallback */
+
+	g_clear_error (&error);
+	g_free (tloader->priv->thumbnailer_tmpfile);
+	tloader->priv->thumbnailer_tmpfile = NULL;
+	uri = g_file_get_uri (tloader->priv->file->file);
+	if (gnome_desktop_thumbnail_factory_generate_thumbnail_async (tloader->priv->thumb_factory,
+								      uri,
+								      gth_file_data_get_mime_type (tloader->priv->file),
+								      &tloader->priv->thumbnailer_pid,
+								      &tloader->priv->thumbnailer_tmpfile,
+								      &error))
+	{
+		tloader->priv->thumbnailer_watch = g_child_watch_add (tloader->priv->thumbnailer_pid,
+								      watch_thumbnailer_cb,
+								      tloader);
+		tloader->priv->thumbnailer_timeout = g_timeout_add (KILL_THUMBNAILER_DELAY,
+								    kill_thumbnailer_cb,
+								    tloader);
+	}
+	else {
+		if (error == NULL)
+			error = g_error_new_literal (GTHUMB_ERROR, 0, "cannot generate the thumbnail");
+		image_loader_error (iloader, error, data);
+	}
+
+	g_free (uri);
 }
 
 
@@ -390,41 +488,34 @@ thumb_loader (GthFileData  *file,
 	      gpointer      data)
 {
 	GthThumbLoader     *tloader = data;
-	GdkPixbuf          *pixbuf;
 	GdkPixbufAnimation *animation = NULL;
+	GdkPixbuf          *pixbuf = NULL;
 
-	/* try with a custom thumbnailer first */
-
-	if (! tloader->priv->from_cache) {
-		FileLoader thumbnailer;
-
-		thumbnailer = gth_main_get_file_loader (gth_file_data_get_mime_type (file));
-		if (thumbnailer != NULL)
-			animation = thumbnailer (file, error, tloader->priv->cache_max_w, tloader->priv->cache_max_h);
-
-		if (animation != NULL)
-			return animation;
+	if (tloader->priv->from_cache) {
+		pixbuf = gth_pixbuf_new_from_file (file, error, -1, -1);
 	}
+	else {
+		/* try with a custom thumbnailer first */
 
-	/* use the default thumbnailer as fallback */
-
-	if (! tloader->priv->from_cache) {
-		char *uri;
+		if (! tloader->priv->from_cache) {
+			FileLoader thumbnailer;
 
-		uri = g_file_get_uri (file->file);
-		pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (tloader->priv->thumb_factory, uri, gth_file_data_get_mime_type (file));
-		g_free (uri);
+			thumbnailer = gth_main_get_file_loader (gth_file_data_get_mime_type (file));
+			if (thumbnailer != NULL)
+				animation = thumbnailer (file, error, tloader->priv->cache_max_w, tloader->priv->cache_max_h);
 
-		if (pixbuf == NULL)
-			*error = g_error_new_literal (GTHUMB_ERROR, 0, "cannot generate the thumbnail");
+			if (animation != NULL)
+				return animation;
+		}
 	}
-	else
-		pixbuf = gth_pixbuf_new_from_file (file, error, -1, -1);
 
 	if (pixbuf != NULL) {
+		g_clear_error (error);
 		animation = gdk_pixbuf_non_anim_new (pixbuf);
 		g_object_unref (pixbuf);
 	}
+	else
+		*error = g_error_new_literal (GTHUMB_ERROR, 0, "cannot generate the thumbnail");
 
 	return animation;
 }
@@ -461,7 +552,7 @@ gth_thumb_loader_new (int width,
 
 void
 gth_thumb_loader_set_thumb_size (GthThumbLoader *tloader,
-				  int             width,
+				 int             width,
 				 int             height)
 {
 	if (tloader->priv->thumb_factory != NULL) {
@@ -667,5 +758,17 @@ gth_thumb_loader_cancel (GthThumbLoader *tloader,
 {
 	g_return_if_fail (tloader->priv->iloader != NULL);
 
+	if (tloader->priv->thumbnailer_timeout != 0) {
+		g_source_remove (tloader->priv->thumbnailer_timeout);
+		tloader->priv->thumbnailer_timeout = 0;
+	}
+
+	if (tloader->priv->thumbnailer_pid != 0) {
+		g_source_remove (tloader->priv->thumbnailer_watch);
+		tloader->priv->thumbnailer_watch = 0;
+		kill (tloader->priv->thumbnailer_pid, SIGTERM);
+		tloader->priv->thumbnailer_pid = 0;
+	}
+
 	gth_image_loader_cancel (tloader->priv->iloader, done_func, done_func_data);
 }



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