Index: src/tracker-indexer/tracker-thumbnailer.c =================================================================== --- src/tracker-indexer/tracker-thumbnailer.c (revision 0) +++ src/tracker-indexer/tracker-thumbnailer.c (revision 0) @@ -0,0 +1,290 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006, Mr Jamie McCracken (jamiemcc gnome org) + * Copyright (C) 2008, Nokia + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "tracker-dbus.h" + +/* Undef this to disable thumbnailing (don't remove unless you understand that + * that either you need to put in place another method to disable/enable this + * and that what will be used by the packager is probably *your* default, + * or unless you want to break expected functionality on-purpose) + * + * (It's not the first time that these ifdef-else-endifs where rewrapped + * incorrectly, and that way obviously broke the feature) + */ + +#ifndef THUMBNAILING_OVER_DBUS +#define THUMBNAILING_OVER_DBUS +#endif + +#ifdef THUMBNAILING_OVER_DBUS + +static GStrv thumbnailable = NULL; +static gchar *batch[51] = { 0 }; +static gchar *hints[51] = { 0 }; +static guint count = 0; +static gboolean timeout_runs = FALSE; + +static void +thumbnail_generic_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + GError *error = NULL; + guint handle; + + /* The point of this is dbus-glib correctness. Answering this because + * this comment used to be the question: what is the point of this. + * It's correct this way because we do asynchronous DBus calls using + * glib-dbus. For asynchronous DBus calls it's recommended (if not + * required for cleaning up) to call dbus_g_proxy_end_call. */ + + dbus_g_proxy_end_call (proxy, call, &error, + G_TYPE_UINT, &handle, + G_TYPE_INVALID); + + if (error) { + g_warning ("%s", error->message); + g_error_free (error); + } +} + +static gboolean +thumbnail_this (GStrv list, const gchar *mime) +{ + guint i = 0; + gboolean retval = FALSE; + + if (!list) + return TRUE; + + while (list[i] != NULL && !retval) { + if (g_ascii_strcasecmp (list[i], mime) == 0) + retval = TRUE; + i++; + } + + return retval; + +} + +static gboolean +request_thumbnails (gpointer data) +{ + if (timeout_runs) { + guint i; + + timeout_runs = FALSE; + batch[count] = NULL; + hints[count] = NULL; + + g_debug ("Requesting thumbnails"); + + dbus_g_proxy_begin_call (tracker_dbus_get_thumbnailer (), + "Queue", + thumbnail_generic_cb, + NULL, NULL, + G_TYPE_STRV, batch, + G_TYPE_STRV, hints, + G_TYPE_UINT, 0, + G_TYPE_INVALID); + + for (i = 0; i <= count; i++) { + g_free (batch[i]); + g_free (hints[i]); + batch[i] = NULL; + hints[i] = NULL; + } + + count = 0; + } + + return FALSE; +} + + +static void +prepare_thumbnailer (void) +{ + static gboolean tried = FALSE; + + /* It's known that this relatively small GStrv is leaked: it contains + * the MIME types that the DBus thumbnailer supports. If a MIME type + * is not within this list, yet we retrieved it once, then we decide + * not to perform thumbnail actions over DBus. This is a performance + * improvement and the GStrv can be resident in memory until the end + * of the application - it's a cache - + * + * It doesn't support detecting when the DBus thumbnailer starts + * supporting more formats (which can indeed start happening). This is + * a known tradeoff and limitation of this cache. We could enhance this + * cache to listen for changes on the bus, and invalidate it once we + * know that more MIME types have become supported. It has no high + * priority now, though (therefore, is this a TODO). */ + + if (!tried) { + GStrv mimes = NULL; + GError *error = NULL; + + dbus_g_proxy_call (tracker_dbus_get_thumb_manager(), + "GetSupported", &error, G_TYPE_INVALID, + G_TYPE_STRV, &mimes, G_TYPE_INVALID); + if (error) + g_error_free (error); + else if (mimes) + thumbnailable = mimes; + tried = TRUE; + } +} + +#endif /* THUMBNAILING_OVER_DBUS */ + +void +tracker_thumbnailer_move (const gchar *from_uri, + const gchar *mime_type, + const gchar *to_uri) +{ +#ifdef THUMBNAILING_OVER_DBUS + prepare_thumbnailer (); + + if (thumbnail_this (thumbnailable, mime_type)) { + GStrv from, to; + + from = (GStrv) g_malloc0 (sizeof (gchar *) * 2); + from[0] = g_strdup (from_uri); + to = (GStrv) g_malloc0 (sizeof (gchar *) * 2); + to[0] = g_strdup (to_uri); + + dbus_g_proxy_begin_call (tracker_dbus_get_thumbnailer (), + "Move", + thumbnail_generic_cb, + NULL, NULL, + G_TYPE_STRV, from, + G_TYPE_STRV, to, + G_TYPE_INVALID); + + g_strfreev (from); + g_strfreev (to); + } + +#endif /* THUMBNAILING_OVER_DBUS */ + +} + +void +tracker_thumbnailer_remove (const gchar *uri, const gchar *mime_type) +{ +#ifdef THUMBNAILING_OVER_DBUS + prepare_thumbnailer (); + + if (thumbnail_this (thumbnailable, mime_type)) { + GStrv uriv; + + uriv = (GStrv) g_malloc0 (sizeof (gchar *) * 2); + uriv[0] = g_strdup (uri); + + dbus_g_proxy_begin_call (tracker_dbus_get_thumbnailer (), + "Delete", + thumbnail_generic_cb, + NULL, NULL, + G_TYPE_STRV, uriv, + G_TYPE_INVALID); + + g_strfreev (uriv); + } + +#endif /* THUMBNAILING_OVER_DBUS */ +} + +void +tracker_thumbnailer_get_file_thumbnail (const gchar *uri, + const gchar *mime) +{ +#ifdef THUMBNAILING_OVER_DBUS + + prepare_thumbnailer (); + + if (count < 50 && thumbnail_this (thumbnailable, mime)) { + + batch[count] = g_strdup (uri); + if (mime) + hints[count] = g_strdup (mime); + else if (g_strv_length (hints) > 0) + hints[count] = g_strdup ("unknown/unknown"); + count++; + + if (!timeout_runs) { + timeout_runs = TRUE; + g_timeout_add_seconds (30, request_thumbnails, NULL); + } + } + + if (count == 50) { + request_thumbnails (NULL); + } +#else /* THUMBNAILING_OVER_DBUS */ + +#ifdef HAVE_IMAGEMAGICK + ProcessContext *context; + + /* We should most likely remove this #else action completely: starting + * up a process per indexed resource (per file on the filesystem) is + * quite a ... action if you care about the performance of the system */ + + GString *thumbnail; + gchar *argv[5]; + + argv[0] = g_strdup (LIBEXEC_PATH G_DIR_SEPARATOR_S "tracker-thumbnailer"); + argv[1] = g_filename_from_utf8 (path, -1, NULL, NULL, NULL); + argv[2] = g_strdup (mime); + argv[3] = g_strdup ("normal"); + argv[4] = NULL; + + context = process_context_create ((const gchar **) argv, + get_file_content_read_cb); + + if (!context) { + return; + } + + thumbnail = g_string_new (NULL); + context->data = thumbnail; + + g_main_loop_run (context->data_incoming_loop); + + g_free (argv[0]); + g_free (argv[1]); + g_free (argv[2]); + g_free (argv[3]); + + if (!thumbnail->str || !*thumbnail->str) { + g_string_free (thumbnail, TRUE); + return; + } + + g_debug ("Got thumbnail '%s' for '%s'", thumbnail->str, path); + + g_string_free (thumbnail, TRUE); +#endif /* HAVE_IMAGEMAGICK */ + +#endif /* THUMBNAILING_OVER_DBUS (end else) */ +} Index: src/tracker-indexer/tracker-metadata-utils.c =================================================================== --- src/tracker-indexer/tracker-metadata-utils.c (revision 2541) +++ src/tracker-indexer/tracker-metadata-utils.c (working copy) @@ -31,7 +31,7 @@ #include #include "tracker-metadata-utils.h" -#include "tracker-dbus.h" +#include "tracker-thumbnailer.h" #define METADATA_FILE_NAME_DELIMITED "File:NameDelimited" #define METADATA_FILE_EXT "File:Ext" @@ -47,10 +47,6 @@ #define TEXT_MAX_SIZE 1048576 /* bytes */ #define TEXT_CHECK_SIZE 65535 /* bytes */ -static gchar *batch[51] = { 0 }; -static gchar *hints[51] = { 0 }; -static guint count = 0; -static gboolean timeout_runs = FALSE; typedef struct { GPid pid; @@ -61,8 +57,6 @@ gpointer data; } ProcessContext; -static void get_file_thumbnail (const gchar *path, - const gchar *mime); static ProcessContext *metadata_context = NULL; @@ -645,174 +639,7 @@ return s ? g_string_free (s, FALSE) : NULL; } -#ifdef HAVE_HILDON_THUMBNAIL -static void -get_file_thumbnail_queue_cb (DBusGProxy *proxy, - DBusGProxyCall *call, - gpointer user_data) -{ - GError *error = NULL; - guint handle; - - /* FIXME: What is the point of this? */ - dbus_g_proxy_end_call (proxy, call, &error, - G_TYPE_UINT, &handle, - G_TYPE_INVALID); - - if (error) { - g_warning ("%s", error->message); - g_error_free (error); - } -} - -static gboolean -thumbnail_this (GStrv list, const gchar *mime) -{ - guint i = 0; - gboolean retval = FALSE; - - if (!list) - return TRUE; - - while (list[i] != NULL && !retval) { - if (g_ascii_strcasecmp (list[i], mime) == 0) - retval = TRUE; - i++; - } - - return retval; - -} - -static gboolean -request_thumbnails (gpointer data) -{ - if (timeout_runs) { - guint i; - - timeout_runs = FALSE; - batch[count] = NULL; - hints[count] = NULL; - - g_debug ("Requesting thumbnails"); - - dbus_g_proxy_begin_call (tracker_dbus_get_thumbnailer (), - "Queue", - get_file_thumbnail_queue_cb, - NULL, NULL, - G_TYPE_STRV, batch, - G_TYPE_STRV, hints, - G_TYPE_UINT, 0, - G_TYPE_INVALID); - - for (i = 0; i <= count; i++) { - g_free (batch[i]); - g_free (hints[i]); - batch[i] = NULL; - hints[i] = NULL; - } - - count = 0; - } - - return FALSE; -} - -#endif /* HAVE_HILDON_THUMBNAIL */ - -static void -get_file_thumbnail (const gchar *path, - const gchar *mime) -{ -#ifdef HAVE_HILDON_THUMBNAIL - - static gboolean tried = FALSE; - - - /* It's known that this relatively small GStrv is leaked */ - static GStrv thumbnailable = NULL; - - if (!tried) { - GStrv mimes = NULL; - GError *error = NULL; - - dbus_g_proxy_call (tracker_dbus_get_thumb_manager(), - "GetSupported", &error, G_TYPE_INVALID, - G_TYPE_STRV, &mimes, G_TYPE_INVALID); - if (error) - g_error_free (error); - else if (mimes) - thumbnailable = mimes; - tried = TRUE; - } - - if (count < 50 && thumbnail_this (thumbnailable, mime)) { - gchar *utf_path; - - utf_path = g_filename_to_utf8 (path, -1, NULL, NULL, NULL); - - if (utf_path) { - batch[count] = g_strdup_printf ("file://%s", utf_path); - if (mime) - hints[count] = g_strdup (mime); - else - hints[count] = g_strdup ("unknown/unknown"); - g_free (utf_path); - count++; - } - - if (!timeout_runs) { - timeout_runs = TRUE; - g_timeout_add_seconds (30, request_thumbnails, NULL); - } - } - - if (count == 50) { - request_thumbnails (NULL); - } -#endif /* HAVE_HILDON_THUMBNAIL */ - -#ifdef HAVE_IMAGEMAGICK - ProcessContext *context; - - GString *thumbnail; - gchar *argv[5]; - - argv[0] = g_strdup (LIBEXEC_PATH G_DIR_SEPARATOR_S "tracker-thumbnailer"); - argv[1] = g_filename_from_utf8 (path, -1, NULL, NULL, NULL); - argv[2] = g_strdup (mime); - argv[3] = g_strdup ("normal"); - argv[4] = NULL; - - context = process_context_create ((const gchar **) argv, - get_file_content_read_cb); - - if (!context) { - return; - } - - thumbnail = g_string_new (NULL); - context->data = thumbnail; - - g_main_loop_run (context->data_incoming_loop); - - g_free (argv[0]); - g_free (argv[1]); - g_free (argv[2]); - g_free (argv[3]); - - if (!thumbnail->str || !*thumbnail->str) { - g_string_free (thumbnail, TRUE); - return; - } - - g_debug ("Got thumbnail '%s' for '%s'", thumbnail->str, path); - - g_string_free (thumbnail, TRUE); -#endif /* HAVE_IMAGEMAGICK */ -} - static gchar * get_file_content_by_filter (const gchar *path, const gchar *mime) @@ -947,11 +774,9 @@ mime_type); if (mime_type) { - /* FIXME: - * We should determine here for which items we do and for which - * items we don't want to pre-create the thumbnail. */ - - get_file_thumbnail (path, mime_type); + gchar *uri = g_file_get_uri (file); + tracker_thumbnailer_get_file_thumbnail (uri, mime_type); + g_free (uri); } if (S_ISLNK (st.st_mode)) { Index: src/tracker-indexer/tracker-thumbnailer.h =================================================================== --- src/tracker-indexer/tracker-thumbnailer.h (revision 0) +++ src/tracker-indexer/tracker-thumbnailer.h (revision 0) @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006, Mr Jamie McCracken (jamiemcc gnome org) + * Copyright (C) 2008, Nokia + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __TRACKER_METADATA_UTILS_H__ +#define __TRACKER_METADATA_UTILS_H__ + +#include +#include + +G_BEGIN_DECLS + +void tracker_thumbnailer_get_file_thumbnail (const gchar *path, + const gchar *mime); +void tracker_thumbnailer_move (const gchar *from_uri, + const gchar *mime_type, + const gchar *to_uri); +void tracker_thumbnailer_remove (const gchar *uri, + const gchar *mime_type); + +G_END_DECLS + +#endif /* __TRACKER_METADATA_UTILS_H__ */ Index: src/tracker-indexer/modules/evolution-imap.c =================================================================== --- src/tracker-indexer/modules/evolution-imap.c (revision 2541) +++ src/tracker-indexer/modules/evolution-imap.c (working copy) @@ -25,7 +25,7 @@ #include -#include o +#include #include #include Index: src/tracker-indexer/tracker-indexer.c =================================================================== --- src/tracker-indexer/tracker-indexer.c (revision 2541) +++ src/tracker-indexer/tracker-indexer.c (working copy) @@ -74,6 +74,7 @@ #include "tracker-indexer.h" #include "tracker-indexer-module.h" #include "tracker-marshal.h" +#include "tracker-thumbnailer.h" #define TRACKER_INDEXER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_INDEXER, TrackerIndexerPrivate)) @@ -1453,6 +1454,7 @@ gchar *new_path, *new_name, *ext; GFile *file, *other_file; gchar *path, *other_path; + gchar *uri, *other_uri, *mime_type; guint32 id; service = get_service_for_file (info->other_module_file, info->module); @@ -1464,8 +1466,22 @@ path = g_file_get_path (info->file); other_path = g_file_get_path (info->other_file); + g_debug ("Moving item from '%s' to '%s'", path, other_path); + /* TODO URI branch: these are URI conversions */ + + uri = g_file_get_uri (info->file); + other_uri = g_file_get_uri (info->other_file); + + mime_type = tracker_file_get_mime_type (path); + tracker_thumbnailer_move (uri, mime_type, other_uri); + + g_free (mime_type); + g_free (uri); + g_free (other_uri); + + /* Get 'source' ID */ if (!tracker_data_query_service_exists (service, dirname, @@ -1528,6 +1544,7 @@ gchar *service_path; const gchar *service_type; guint service_id, service_type_id; + gchar *uri, *mime_type; service_type = tracker_module_config_get_index_service (info->module->name); @@ -1535,6 +1552,24 @@ dirname, basename); + /* TODO URI branch: this is a URI conversion */ + + uri = g_strdup_printf ("file://%s/%s", dirname, basename); + service_path = g_build_path (G_DIR_SEPARATOR_S, + dirname, + basename, + NULL); + mime_type = tracker_file_get_mime_type (service_path); + g_free (service_path); /* this is done this way to minimize merging + * work for URI branch (I know the exact same + * thing is being done later in the code. + * there are no caveats, you can just replace + * this while merging, indeed) */ + tracker_thumbnailer_remove (uri, mime_type); + + g_free (mime_type); + g_free (uri); + if (!service_type || !service_type[0]) { const gchar *name; Index: src/tracker-indexer/Makefile.am =================================================================== --- src/tracker-indexer/Makefile.am (revision 2541) +++ src/tracker-indexer/Makefile.am (working copy) @@ -39,7 +39,9 @@ tracker-indexer-module.c \ tracker-indexer-module.h \ tracker-main.c \ - tracker-marshal-main.c + tracker-marshal-main.c \ + tracker-thumbnailer.c \ + tracker-thumbnailer.h tracker_indexer_LDADD = \ libtracker-indexer.la \ Index: src/libtracker-common/tracker-file-utils.h =================================================================== --- src/libtracker-common/tracker-file-utils.h (revision 2541) +++ src/libtracker-common/tracker-file-utils.h (working copy) @@ -28,26 +28,26 @@ #include -gint tracker_file_open (const gchar *uri, +gint tracker_file_open (const gchar *path, gboolean readahead); void tracker_file_close (gint fd, gboolean no_longer_needed); -gboolean tracker_file_unlink (const gchar *uri); -gboolean tracker_file_is_valid (const gchar *uri); -gboolean tracker_file_is_directory (const gchar *uri); -gboolean tracker_file_is_indexable (const gchar *uri); -guint32 tracker_file_get_size (const gchar *uri); -gint32 tracker_file_get_mtime (const gchar *uri); -gchar * tracker_file_get_mime_type (const gchar *uri); -void tracker_file_get_path_and_name (const gchar *uri, - gchar **path, - gchar **name); -void tracker_path_remove (const gchar *uri); +gboolean tracker_file_unlink (const gchar *path); +gboolean tracker_file_is_valid (const gchar *path); +gboolean tracker_file_is_directory (const gchar *path); +gboolean tracker_file_is_indexable (const gchar *path); +guint32 tracker_file_get_size (const gchar *path); +gint32 tracker_file_get_mtime (const gchar *path); +gchar * tracker_file_get_mime_type (const gchar *path); +void tracker_file_get_path_and_name (const gchar *path, + gchar **path_in, + gchar **name_in); +void tracker_path_remove (const gchar *path); gboolean tracker_path_is_in_path (const gchar *path, const gchar *in_path); void tracker_path_hash_table_filter_duplicates (GHashTable *roots); GSList * tracker_path_list_filter_duplicates (GSList *roots); -gchar * tracker_path_evaluate_name (const gchar *uri); +gchar * tracker_path_evaluate_name (const gchar *path); gboolean tracker_env_check_xdg_dirs (void); #endif /* __LIBTRACKER_COMMON_FILE_UTILS_H__ */ Index: tests/tracker-indexer/Makefile.am =================================================================== --- tests/tracker-indexer/Makefile.am (revision 2541) +++ tests/tracker-indexer/Makefile.am (working copy) @@ -34,7 +34,9 @@ tracker-module-file.c \ tracker-module-file.h \ tracker-module-iteratable.c \ - tracker-module-iteratable.h + tracker-module-iteratable.h \ + tracker-thumbnailer.c \ + tracker-thumbnailer.h tracker_metadata_utils_LDADD = \ $(top_builddir)/src/libtracker-data/libtracker-data.la \ Index: configure.ac =================================================================== --- configure.ac (revision 2541) +++ configure.ac (working copy) @@ -1176,6 +1176,8 @@ tests/tracker-indexer/tracker-module-file.h:src/tracker-indexer/tracker-module-file.h tests/tracker-indexer/tracker-module-iteratable.c:src/tracker-indexer/tracker-module-iteratable.c tests/tracker-indexer/tracker-module-iteratable.h:src/tracker-indexer/tracker-module-iteratable.h + tests/tracker-indexer/tracker-thumbnailer.h:src/tracker-indexer/tracker-thumbnailer.h + tests/tracker-indexer/tracker-thumbnailer.c:src/tracker-indexer/tracker-thumbnailer.c ) ##################################################################