Commit 95f78732 authored by Paolo Bacchilega's avatar Paolo Bacchilega
Browse files

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.
parent 3ca4b637
......@@ -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;
}
......@@ -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,
......
......@@ -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