[gthumb: 17/20] readded ability to stop the thumbnailer if it lasts too much



commit a4f7392fb0d077d04989c9fac71e1cfcd3e6ac85
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Tue Mar 30 18:21:06 2010 +0200

    readded ability to stop the thumbnailer if it lasts too much

 gthumb/gnome-desktop-thumbnail.c |  170 ++++++++++++++++++++++++++++++++++++++
 gthumb/gnome-desktop-thumbnail.h |   12 +++-
 gthumb/gth-thumb-loader.c        |   93 ++++++++++++++++++++-
 3 files changed, 270 insertions(+), 5 deletions(-)
---
diff --git a/gthumb/gnome-desktop-thumbnail.c b/gthumb/gnome-desktop-thumbnail.c
index 4cf33da..0a333ee 100644
--- a/gthumb/gnome-desktop-thumbnail.c
+++ b/gthumb/gnome-desktop-thumbnail.c
@@ -933,6 +933,176 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
   return pixbuf;
 }
 
+
+GdkPixbuf *
+gnome_desktop_thumbnail_factory_generate_no_script (GnomeDesktopThumbnailFactory *factory,
+						    const char            *uri,
+						    const char            *mime_type)
+{
+  GdkPixbuf *pixbuf, *scaled, *tmp_pixbuf;
+  int width, height, size;
+  int original_width = 0;
+  int original_height = 0;
+  char dimension[12];
+  double scale;
+
+  g_return_val_if_fail (uri != NULL, NULL);
+  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;
+
+  /* Use a registered thumbnail generator */
+  pixbuf = gth_hook_invoke_get ("generate-thumbnail", (char *) uri, mime_type, size);
+
+  /* Fall back to gdk-pixbuf */
+  if (pixbuf == NULL)
+    pixbuf = _gdk_pixbuf_new_from_uri_at_scale (uri, size, size, TRUE);
+
+  if (pixbuf == NULL)
+    return NULL;
+
+  if (pixbuf != NULL)
+    {
+      original_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
+                                                           "gnome-original-width"));
+      original_height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf),
+                                                            "gnome-original-height"));
+    }
+
+  /* The pixbuf loader may attach an "orientation" option to the pixbuf,
+     if the tiff or exif jpeg file had an orientation tag. Rotate/flip
+     the pixbuf as specified by this tag, if present. */
+  tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
+  g_object_unref (pixbuf);
+  pixbuf = tmp_pixbuf;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  if (width > size || height > size)
+    {
+      const gchar *orig_width, *orig_height;
+      scale = (double)size / MAX (width, height);
+
+      /* if the scale factor is small, use bilinear interpolation for better quality */
+      if ((scale >= 0.5) && (scale <= 2))
+	      scaled = _gdk_pixbuf_scale_simple_safe (pixbuf,
+						      floor (width * scale + 0.5),
+						      floor (height * scale + 0.5),
+						      GDK_INTERP_BILINEAR);
+      else
+	      scaled = gnome_desktop_thumbnail_scale_down_pixbuf (pixbuf,
+							          floor (width * scale + 0.5),
+							          floor (height * scale + 0.5));
+
+      orig_width = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width");
+      orig_height = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height");
+
+      if (orig_width != NULL) {
+	      gdk_pixbuf_set_option (scaled, "tEXt::Thumb::Image::Width", orig_width);
+      }
+      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);
+    }
+  if (original_height > 0)
+    {
+      g_snprintf (dimension, sizeof (dimension), "%i", original_height);
+      gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Height", dimension);
+    }
+
+  return pixbuf;
+}
+
+
+gboolean
+gnome_desktop_thumbnail_factory_generate_from_script (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;
+	g_mutex_lock (factory->priv->lock);
+	if (factory->priv->scripts_hash != NULL) {
+		script = g_hash_table_lookup (factory->priv->scripts_hash, mime_type);
+		if (script)
+			script = g_strdup (script);
+	}
+	g_mutex_unlock (factory->priv->lock);
+
+	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);
+	g_free (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)
 {
diff --git a/gthumb/gnome-desktop-thumbnail.h b/gthumb/gnome-desktop-thumbnail.h
index 5081d00..3d7a197 100644
--- a/gthumb/gnome-desktop-thumbnail.h
+++ b/gthumb/gnome-desktop-thumbnail.h
@@ -97,6 +97,17 @@ gboolean               gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDeskt
 GdkPixbuf *            gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory,
 									   const char            *uri,
 									   const char            *mime_type);
+GdkPixbuf *            gnome_desktop_thumbnail_factory_generate_no_script (GnomeDesktopThumbnailFactory *factory,
+									   const char            *uri,
+									   const char            *mime_type);
+gboolean               gnome_desktop_thumbnail_factory_generate_from_script (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,
@@ -105,7 +116,6 @@ void                   gnome_desktop_thumbnail_factory_create_failed_thumbnail (
 										const char            *uri,
 										time_t                 mtime);
 
-
 /* Thumbnailing utils: */
 gboolean   gnome_desktop_thumbnail_has_uri           (GdkPixbuf          *pixbuf,
 						      const char         *uri);
diff --git a/gthumb/gth-thumb-loader.c b/gthumb/gth-thumb-loader.c
index 56df2fc..7058493 100644
--- a/gthumb/gth-thumb-loader.c
+++ b/gthumb/gth-thumb-loader.c
@@ -67,6 +67,10 @@ struct _GthThumbLoaderPrivateData
 			  thumb_size;
 	GnomeDesktopThumbnailFactory
 			 *thumb_factory;
+	char             *thumbnailer_tmpfile;
+	GPid              thumbnailer_pid;
+	guint             thumbnailer_watch;
+	guint             thumbnailer_timeout;
 };
 
 
@@ -91,6 +95,7 @@ gth_thumb_loader_finalize (GObject *object)
 	self = GTH_THUMB_LOADER (object);
 
 	if (self->priv != NULL) {
+		g_free (self->priv->thumbnailer_tmpfile);
 		_g_object_unref (self->priv->pixbuf);
 		_g_object_unref (self->priv->iloader);
 		_g_object_unref (self->priv->file_data);
@@ -405,7 +410,7 @@ thumb_loader (GthFileData  *file_data,
 		char *uri;
 
 		uri = g_file_get_uri (file_data->file);
-		pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (self->priv->thumb_factory,
+		pixbuf = gnome_desktop_thumbnail_factory_generate_no_script (self->priv->thumb_factory,
 									     uri,
 									     gth_file_data_get_mime_type (file_data));
 		if (pixbuf == NULL) {
@@ -589,16 +594,68 @@ gth_thumb_loader_get_pixbuf (GthThumbLoader *self)
 }
 
 
+static gboolean
+kill_thumbnailer_cb (gpointer data)
+{
+	GthThumbLoader *self = data;
+
+	g_source_remove (self->priv->thumbnailer_timeout);
+	self->priv->thumbnailer_timeout = 0;
+
+	if (self->priv->thumbnailer_pid != 0) {
+		/*g_source_remove (self->priv->thumbnailer_watch);
+		self->priv->thumbnailer_watch = 0;*/
+		kill (self->priv->thumbnailer_pid, SIGTERM);
+		/*self->priv->thumbnailer_pid = 0;*/
+	}
+
+	return FALSE;
+}
+
+
+static void
+watch_thumbnailer_cb (GPid     pid,
+		      int      status,
+		      gpointer data)
+{
+	GthThumbLoader *self = data;
+	GdkPixbuf      *pixbuf = NULL;
+
+	if (self->priv->thumbnailer_timeout != 0) {
+		g_source_remove (self->priv->thumbnailer_timeout);
+		self->priv->thumbnailer_timeout = 0;
+	}
+
+	g_spawn_close_pid (pid);
+	self->priv->thumbnailer_pid = 0;
+	self->priv->thumbnailer_watch = 0;
+
+	if (status == 0)
+		pixbuf = gnome_desktop_thumbnail_factory_load_from_tempfile (self->priv->thumb_factory,
+									     &self->priv->thumbnailer_tmpfile);
+
+	if (pixbuf != NULL) {
+		image_loader_loaded (NULL, pixbuf, data);
+		g_object_unref (pixbuf);
+	}
+	else {
+		/* the system thumbnailer couldn't generate the thumbnail,
+		 * try using the thumb_loader() function */
+		gth_image_loader_load (self->priv->iloader);
+	}
+}
+
+
 static void
 gth_thumb_loader_load__step2 (GthThumbLoader *self)
 {
 	char *cache_path = NULL;
+	char *uri;
 
 	g_return_if_fail (self != NULL);
 
 	if (self->priv->use_cache) {
-		char   *uri;
-		time_t  mtime;
+		time_t mtime;
 
 		uri = g_file_get_uri (self->priv->file_data->file);
 		mtime = gth_file_data_get_mtime (self->priv->file_data);
@@ -644,7 +701,35 @@ gth_thumb_loader_load__step2 (GthThumbLoader *self)
 		}
 	}
 
-	gth_image_loader_load (self->priv->iloader);
+	if (self->priv->loading_from_cache) {
+		gth_image_loader_load (self->priv->iloader);
+		return;
+	}
+
+	/* not loading from the cache: try with the system thumbnailer first */
+
+	g_free (self->priv->thumbnailer_tmpfile);
+	self->priv->thumbnailer_tmpfile = NULL;
+	uri = g_file_get_uri (self->priv->file_data->file);
+	if (gnome_desktop_thumbnail_factory_generate_from_script (self->priv->thumb_factory,
+								  uri,
+								  gth_file_data_get_mime_type (self->priv->file_data),
+								  &self->priv->thumbnailer_pid,
+								  &self->priv->thumbnailer_tmpfile,
+								  NULL))
+	{
+		self->priv->thumbnailer_watch = g_child_watch_add (self->priv->thumbnailer_pid,
+								   watch_thumbnailer_cb,
+								   self);
+		self->priv->thumbnailer_timeout = g_timeout_add (MAX_THUMBNAILER_LIFETIME,
+								 kill_thumbnailer_cb,
+								 self);
+	}
+	else /* if the system thumbnailer cannot generate the thumbnail,
+	      * try using the thumb_loader() function */
+		gth_image_loader_load (self->priv->iloader);
+
+	g_free (uri);
 }
 
 



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