[Xfce4-commits] <tumbler:jannis/specialized> Squashme: Major refactoring, good progress with specialized thumbnailers
Jannis Pohlmann
noreply at xfce.org
Fri Nov 6 02:22:01 CET 2009
Updating branch refs/heads/jannis/specialized
to 7643d8ba2b97791d9db77e0f971b35777bc2f4fe (commit)
from c1d47c7f047f518a9681010a6092934e39b1454b (commit)
commit 7643d8ba2b97791d9db77e0f971b35777bc2f4fe
Author: Jannis Pohlmann <jannis at xfce.org>
Date: Fri Nov 6 02:10:44 2009 +0100
Squashme: Major refactoring, good progress with specialized thumbnailers
To make things faster and work properly, we store all overrides and
thumbnailer .service file information in two hash tables with lists
again. Whenever a file changes we make sure to synchronize the manager
and registry state with the disk content.
The nice thing about this is that we can merge overrides files from all
XDG_DATA_DIRS (giving priority to XDG_DATA_HOME etc.) and can also
handle .service files with the same basenames now (files earlier in
XDG_DATA_HOME/XDG_DATA_DIRS shadow others coming later). All in all,
this makes it possible to run the service ALL THE TIME, knowing that it
will always catch up changes made to the file system. Nice when
installing new overrides files and specialized thumbnailer services into
the system at runtime.
Things still to do:
- handle directory deletions (when thumbnailer directories are
deleted, we don't receive delete events for the individual files
unless we monitor them explicitely)
- handle dynamic registration of specialized thumbnailers (D-Bus
services that register themselves via the manager interface at
runtime without installing a static .service file)
- clean up and document the code
- remove all the debug statements
tumblerd/tumbler-manager.c | 997 +++++++++++++++++++---------
tumblerd/tumbler-registry.c | 115 +++-
tumblerd/tumbler-registry.h | 2 +
tumblerd/tumbler-specialized-thumbnailer.c | 4 +-
4 files changed, 782 insertions(+), 336 deletions(-)
diff --git a/tumblerd/tumbler-manager.c b/tumblerd/tumbler-manager.c
index 615938a..9b592c6 100644
--- a/tumblerd/tumbler-manager.c
+++ b/tumblerd/tumbler-manager.c
@@ -71,7 +71,8 @@ static void tumbler_manager_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
-static void tumbler_manager_load_thumbnailers (TumblerManager *manager);
+static void tumbler_manager_load_thumbnailers (TumblerManager *manager,
+ GFile *directory);
static void tumbler_manager_directory_changed (TumblerManager *manager,
GFile *file,
GFile *other_file,
@@ -111,13 +112,133 @@ struct _OverrideInfo
struct _ThumbnailerInfo
{
- gchar *base_name;
TumblerThumbnailer *thumbnailer;
+ GFile *file;
gint dir_index;
};
+static OverrideInfo *
+override_info_new (void)
+{
+ return g_slice_new0 (OverrideInfo);
+}
+
+
+
+static void
+override_info_free (gpointer pointer)
+{
+ OverrideInfo *info = pointer;
+
+ if (info == NULL)
+ return;
+
+ g_free (info->name);
+ g_free (info->uri_scheme);
+ g_free (info->mime_type);
+
+ g_slice_free (OverrideInfo, info);
+}
+
+
+
+static void
+override_info_list_free (gpointer pointer)
+{
+ GList **infos = pointer;
+ GList *iter;
+
+ for (iter = *infos; iter != NULL; iter = iter->next)
+ override_info_free (iter->data);
+
+ g_list_free (*infos);
+}
+
+
+
+static ThumbnailerInfo *
+thumbnailer_info_new (void)
+{
+ return g_slice_new0 (ThumbnailerInfo);
+}
+
+
+
+static void
+thumbnailer_info_free (ThumbnailerInfo *info)
+{
+ if (info == NULL)
+ return;
+
+ g_object_unref (info->file);
+ g_object_unref (info->thumbnailer);
+ g_slice_free (ThumbnailerInfo, info);
+}
+
+
+
+static void
+thumbnailer_info_list_free (gpointer pointer)
+{
+ GList **infos = pointer;
+ GList *iter;
+
+ for (iter = *infos; iter != NULL; iter = iter->next)
+ thumbnailer_info_free (iter->data);
+
+ g_list_free (*infos);
+}
+
+
+
+static void
+dump_overrides (TumblerManager *manager)
+{
+ GHashTableIter table_iter;
+ const gchar *hash_key;
+ GList **list;
+ GList *iter;
+
+ g_print ("\nOverrides:\n");
+
+ g_hash_table_iter_init (&table_iter, manager->overrides);
+ while (g_hash_table_iter_next (&table_iter, (gpointer) &hash_key, (gpointer) &list))
+ {
+ g_print (" %s:\n", hash_key);
+ for (iter = *list; iter != NULL; iter = iter->next)
+ g_print (" %s\n", ((OverrideInfo *)iter->data)->name);
+ }
+
+ g_print ("\n");
+}
+
+
+
+static void
+dump_thumbnailers (TumblerManager *manager)
+{
+ GHashTableIter table_iter;
+ const gchar *base_name;
+ GList **list;
+ GList *iter;
+
+ g_print ("\nThumbnailers:\n");
+
+ g_hash_table_iter_init (&table_iter, manager->thumbnailers);
+ while (g_hash_table_iter_next (&table_iter, (gpointer) &base_name, (gpointer) &list))
+ {
+ g_print (" %s:\n", base_name);
+ for (iter = *list; iter != NULL; iter = iter->next)
+ g_print (" %s\n", g_file_get_path (((ThumbnailerInfo *)iter->data)->file));
+ }
+
+ g_print ("\n");
+}
+
+
+
G_DEFINE_TYPE (TumblerManager, tumbler_manager, G_TYPE_OBJECT);
@@ -156,15 +277,24 @@ tumbler_manager_init (TumblerManager *manager)
manager->directories = NULL;
manager->monitors = NULL;
manager->mutex = g_mutex_new ();
+ manager->overrides = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, override_info_list_free);
+ manager->thumbnailers = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, thumbnailer_info_list_free);
}
static void
-monitor_unref (GFileMonitor *monitor)
+monitor_unref (GFileMonitor *monitor,
+ TumblerManager *manager)
{
if (monitor != NULL)
- g_object_unref (monitor);
+ {
+ g_signal_handlers_disconnect_matched (monitor, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, manager);
+ g_object_unref (monitor);
+ }
}
@@ -179,21 +309,17 @@ tumbler_manager_finalize (GObject *object)
g_list_foreach (manager->directories, (GFunc) g_object_unref, NULL);
g_list_free (manager->directories);
- g_list_foreach (manager->monitors, (GFunc) monitor_unref, NULL);
+ g_list_foreach (manager->monitors, (GFunc) monitor_unref, manager);
g_list_free (manager->monitors);
- if (manager->thumbnailers != NULL)
- g_hash_table_unref (manager->thumbnailers);
-
- if (manager->overrides != NULL)
- g_hash_table_unref (manager->overrides);
+ g_hash_table_unref (manager->thumbnailers);
+ g_hash_table_unref (manager->overrides);
g_object_unref (manager->registry);
dbus_g_connection_unref (manager->connection);
g_mutex_unlock (manager->mutex);
-
g_mutex_free (manager->mutex);
(*G_OBJECT_CLASS (tumbler_manager_parent_class)->finalize) (object);
@@ -249,82 +375,108 @@ tumbler_manager_set_property (GObject *object,
-static OverrideInfo *
-override_info_new (void)
+static gint
+tumbler_manager_get_dir_index (TumblerManager *manager,
+ GFile *directory)
{
- return g_slice_new0 (OverrideInfo);
+ GList *iter;
+ gint dir_index = -1;
+ gint n;
+
+ for (iter = manager->directories, n = 0;
+ dir_index < 0 && iter != NULL;
+ iter = iter->next, ++n)
+ {
+ if (g_file_equal (iter->data, directory))
+ dir_index = n;
+ }
+
+ return n;
}
static void
-override_info_free (gpointer pointer)
+tumbler_manager_update_preferred (TumblerManager *manager,
+ const gchar *hash_key)
{
- OverrideInfo *info = pointer;
+ TumblerThumbnailer *thumbnailer = NULL;
+ ThumbnailerInfo *info;
+ GHashTableIter iter;
+ const gchar *current_name;
+ const gchar *name;
+ GList **overrides;
+ GList **thumbnailers;
- if (info == NULL)
- return;
+ g_return_if_fail (TUMBLER_IS_MANAGER (manager));
+ g_return_if_fail (hash_key != NULL && *hash_key != '\0');
- g_free (info->name);
- g_free (info->uri_scheme);
- g_free (info->mime_type);
+ g_debug ("update_preferred: %s", hash_key);
- g_slice_free (OverrideInfo, info);
-}
+ overrides = g_hash_table_lookup (manager->overrides, hash_key);
+ if (overrides != NULL)
+ {
+ g_assert (*overrides != NULL);
+ name = ((OverrideInfo *)(*overrides)->data)->name;
+
+ g_hash_table_iter_init (&iter, manager->thumbnailers);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &thumbnailers))
+ {
+ g_assert (thumbnailers != NULL);
+ g_assert (*thumbnailers != NULL);
-static gint
-override_info_compare (gconstpointer a,
- gconstpointer b)
-{
- const OverrideInfo *info_a = a;
- const OverrideInfo *info_b = b;
+ info = (ThumbnailerInfo *)(*thumbnailers)->data;
- return CLAMP (info_b->dir_index - info_a->dir_index, -1, 1);
-}
+ g_assert (info != NULL);
+ g_assert (TUMBLER_IS_SPECIALIZED_THUMBNAILER (info->thumbnailer));
+ current_name = tumbler_specialized_thumbnailer_get_name (
+ TUMBLER_SPECIALIZED_THUMBNAILER (info->thumbnailer));
+ if (g_strcmp0 (name, current_name) == 0)
+ thumbnailer = info->thumbnailer;
+ }
+ }
-static void
-override_info_array_free (gpointer pointer)
-{
- GPtrArray *infos = pointer;
+ if (thumbnailer != NULL)
+ {
+ g_debug ("preferring %s for %s",
+ tumbler_specialized_thumbnailer_get_name (TUMBLER_SPECIALIZED_THUMBNAILER (thumbnailer)),
+ hash_key);
+ }
- g_ptr_array_foreach (infos, (GFunc) override_info_free, NULL);
- g_ptr_array_free (infos, TRUE);
+ tumbler_registry_set_preferred (manager->registry, hash_key, thumbnailer);
}
-static void
-tumbler_manager_load_overrides (TumblerManager *manager,
- GFile *directory)
-{
- GPtrArray *overrides;
- GKeyFile *key_file;
- GError *error = NULL;
- gchar **sections;
- gchar *dirname;
- gchar *filename;
- gchar *uri_type;
- guint n;
-
- g_return_if_fail (TUMBLER_IS_MANAGER (manager));
- g_return_if_fail (G_IS_FILE (directory));
-
- /* get the overrides file */
- dirname = g_file_get_path (directory);
- filename = g_build_filename (dirname, "overrides", NULL);
- g_free (dirname);
+static GList *
+tumbler_manager_parse_overrides (TumblerManager *manager,
+ GFile *file)
+{
+ GKeyFile *key_file;
+ GError *error = NULL;
+ GList *overrides = NULL;
+ GFile *directory;
+ gchar **sections;
+ gchar *filename;
+ gchar *uri_type;
+ guint n;
+
+ g_return_val_if_fail (TUMBLER_IS_MANAGER (manager), NULL);
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+ filename = g_file_get_path (file);
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
{
g_free (filename);
- return;
+ return NULL;
}
- g_debug ("load_overrides: filename %s", filename);
+ g_debug ("parse_overrides: %s", filename);
/* allocate the key file */
key_file = g_key_file_new ();
@@ -336,7 +488,7 @@ tumbler_manager_load_overrides (TumblerManager *manager,
g_clear_error (&error);
g_key_file_free (key_file);
g_free (filename);
- return;
+ return NULL;
}
/* determine sections in the key file */
@@ -403,329 +555,460 @@ tumbler_manager_load_overrides (TumblerManager *manager,
}
g_free (uri_type);
- info->dir_index = g_list_index (manager->directories, directory);
-
- overrides = g_hash_table_lookup (manager->overrides, sections[n]);
- if (overrides == NULL)
- {
- overrides = g_ptr_array_new ();
- g_hash_table_insert (manager->overrides, sections[n], overrides);
- }
+ directory = g_file_get_parent (file);
+ info->dir_index = tumbler_manager_get_dir_index (manager, directory);
+ g_object_unref (directory);
- g_ptr_array_add (overrides, info);
+ overrides = g_list_prepend (overrides, info);
}
g_free (sections);
g_key_file_free (key_file);
g_free (filename);
+
+ return overrides;
}
static void
-tumbler_manager_update_overrides (TumblerManager *manager)
+tumbler_manager_load_overrides_file (TumblerManager *manager,
+ GFile *file)
{
- GHashTableIter hash_iter;
- GPtrArray *infos;
- GList *iter;
+ OverrideInfo *info;
+ OverrideInfo *info2;
+ gboolean first = FALSE;
+ gboolean inserted = FALSE;
+ GList *overrides;
+ GList *lp;
+ GList *op;
+ GList **list;
+ GFile *directory;
+ gchar *hash_key;
+ gint dir_index;
- g_return_if_fail (TUMBLER_IS_MANAGER (manager));
+ g_return_if_fail (TUMBLER_MANAGER (manager));
+ g_return_if_fail (G_IS_FILE (file));
- /* check if the overrides cache has been allocated already */
- if (manager->overrides != NULL)
- {
- /* clear the overrides cache */
- g_hash_table_remove_all (manager->overrides);
- }
- else
+ g_debug ("load_overrides_file %s", g_file_get_path (file));
+
+ directory = g_file_get_parent (file);
+ dir_index = tumbler_manager_get_dir_index (manager, directory);
+ g_object_unref (directory);
+
+ if (dir_index < 0)
+ return;
+
+ overrides = tumbler_manager_parse_overrides (manager, file);
+
+ for (op = overrides; op != NULL; op = op->next)
{
- /* otherwise allocate the overrides cache on-demand */
- manager->overrides = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, override_info_array_free);
- }
+ info = op->data;
- /* iterate over all thumbnailer directories with increasing priority */
- for (iter = manager->directories; iter != NULL; iter = iter->next)
- tumbler_manager_load_overrides (manager, iter->data);
+ hash_key = g_strdup_printf ("%s-%s", info->uri_scheme, info->mime_type);
+ list = g_hash_table_lookup (manager->overrides, hash_key);
+
+ first = FALSE;
+
+ if (list == NULL)
+ {
+ g_debug (" creating %s for %s", info->name, hash_key);
+
+ list = g_slice_alloc0 (sizeof (GList *));
+
+ *list = g_list_prepend (*list, info);
+
+ g_hash_table_insert (manager->overrides, g_strdup (hash_key), list);
+
+ first = TRUE;
+ }
+ else
+ {
+ inserted = FALSE;
+
+ for (lp = *list; !inserted && lp != NULL; lp = lp->next)
+ {
+ info2 = lp->data;
- g_hash_table_iter_init (&hash_iter, manager->overrides);
- while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &infos))
- g_ptr_array_sort (infos, override_info_compare);
+ g_assert (info2->dir_index != dir_index);
+
+ if (info2->dir_index > dir_index)
+ {
+ if (lp == *list)
+ first = TRUE;
+
+ *list = g_list_insert_before (*list, lp, info);
+
+ g_debug (" inserting %s in %s", info->name, hash_key);
+
+ inserted = TRUE;
+ }
+ }
+
+ if (!inserted)
+ *list = g_list_append (*list, info);
+ }
+
+ if (first)
+ {
+ g_debug (" first");
+ tumbler_manager_update_preferred (manager, hash_key);
+ }
+
+ g_free (hash_key);
+ }
+
+ g_list_free (overrides);
}
-static ThumbnailerInfo *
-thumbnailer_info_new (void)
+static void
+tumbler_manager_load_overrides (TumblerManager *manager)
{
- return g_slice_new0 (ThumbnailerInfo);
+ GFileType type;
+ GFile *file;
+ GList *lp;
+
+ g_return_if_fail (TUMBLER_IS_MANAGER (manager));
+
+ for (lp = manager->directories; lp != NULL; lp = lp->next)
+ {
+ file = g_file_get_child (lp->data, "overrides");
+ type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
+
+ if (type == G_FILE_TYPE_REGULAR)
+ tumbler_manager_load_overrides_file (manager, file);
+
+ g_object_unref (file);
+ }
+
+ dump_overrides (manager);
}
static void
-thumbnailer_info_free (ThumbnailerInfo *info)
+tumbler_manager_unload_overrides_file (TumblerManager *manager,
+ GFile *file)
{
- if (info == NULL)
+ GHashTableIter iter;
+ OverrideInfo *info;
+ const gchar *hash_key;
+ gboolean first;
+ GFile *directory;
+ GList *delete_keys = NULL;
+ GList *lp;
+ GList **overrides;
+ gint dir_index;
+
+ g_return_if_fail (TUMBLER_IS_MANAGER (manager));
+ g_return_if_fail (G_IS_FILE (file));
+
+ g_debug ("unload_overrides_file: %s", g_file_get_path (file));
+
+ directory = g_file_get_parent (file);
+ dir_index = tumbler_manager_get_dir_index (manager, directory);
+ g_object_unref (directory);
+
+ if (dir_index < 0)
return;
- g_free (info->base_name);
- if (info->thumbnailer != NULL)
- g_object_unref (info->thumbnailer);
- g_slice_free (ThumbnailerInfo, info);
+ g_hash_table_iter_init (&iter, manager->overrides);
+ while (g_hash_table_iter_next (&iter, (gpointer) &hash_key, (gpointer) &overrides))
+ {
+ first = FALSE;
+
+ g_assert (overrides != NULL);
+ g_assert (*overrides != NULL);
+
+ for (lp = *overrides; lp != NULL; lp = lp->next)
+ {
+ info = (OverrideInfo *)lp->data;
+
+ g_assert (info != NULL);
+
+ if (info->dir_index == dir_index)
+ {
+ if (lp == *overrides)
+ first = TRUE;
+
+ g_debug (" deleting info %s", info->name);
+ override_info_free (info);
+ *overrides = g_list_delete_link (*overrides, lp);
+
+ break;
+ }
+ }
+
+ if (*overrides == NULL)
+ delete_keys = g_list_prepend (delete_keys, (gpointer) hash_key);
+
+ if (first)
+ tumbler_manager_update_preferred (manager, hash_key);
+ }
+
+ for (lp = delete_keys; lp != NULL; lp = lp->next)
+ {
+ g_debug (" deleting key %s", (const gchar *)lp->data);
+ g_hash_table_remove (manager->overrides, (const gchar *)lp->data);
+ }
+
+ g_list_free (delete_keys);
}
static void
-tumbler_manager_load_thumbnailer_infos (TumblerManager *manager,
- GFile *directory)
+tumbler_manager_load_thumbnailer (TumblerManager *manager,
+ GFile *file)
{
ThumbnailerInfo *info;
+ ThumbnailerInfo *info2;
struct stat file_stat;
- const gchar *base_name;
GKeyFile *key_file;
+ gboolean first = FALSE;
+ gboolean inserted = FALSE;
GError *error = NULL;
- GDir *dir;
- gchar *dirname;
+ GFile *directory;
+ GList **list;
+ GList *lp;
+ GStrv hash_keys;
+ gchar *base_name;
gchar *filename;
gchar *name;
gchar *object_path;
gchar **uri_schemes;
gchar **mime_types;
+ guint n;
g_return_if_fail (TUMBLER_IS_MANAGER (manager));
- g_return_if_fail (G_IS_FILE (directory));
+ g_return_if_fail (G_IS_FILE (file));
- dirname = g_file_get_path (directory);
+ g_debug ("load_thumbnailer: %s", g_file_get_path (file));
- dir = g_dir_open (dirname, 0, NULL);
+ filename = g_file_get_path (file);
- if (dir == NULL)
+ key_file = g_key_file_new ();
+
+ if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &error))
{
- g_free (dirname);
+ g_warning (_("Failed to load the file \"%s\": %s"), filename, error->message);
+ g_clear_error (&error);
+
+ g_key_file_free (key_file);
+ g_free (filename);
+
return;
}
- for (base_name = g_dir_read_name (dir);
- base_name != NULL;
- base_name = g_dir_read_name (dir))
+ name = g_key_file_get_string (key_file, "Specialized Thumbnailer", "Name", &error);
+ if (name == NULL)
{
- /* skip non-service files */
- if (!g_str_has_suffix (base_name, ".service"))
- continue;
+ g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
+ g_clear_error (&error);
- /* skip .service files if files with the same filename appeared in
- * directories with higher priorities */
- if (g_hash_table_lookup (manager->thumbnailers, base_name) != NULL)
- continue;
+ g_key_file_free (key_file);
+ g_free (filename);
- filename = g_build_filename (dirname, base_name, NULL);
+ return;
+ }
- if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
- {
- g_free (filename);
- continue;
- }
+ object_path = g_key_file_get_string (key_file, "Specialized Thumbnailer",
+ "ObjectPath", &error);
+ if (object_path == NULL)
+ {
+ g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
+ g_clear_error (&error);
- g_debug ("load_thumbnailer_infos: filename %s", filename);
+ g_key_file_free (key_file);
+ g_free (filename);
- key_file = g_key_file_new ();
+ return;
+ }
- if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &error))
- {
- g_warning (_("Failed to load the file \"%s\": %s"), filename, error->message);
- g_clear_error (&error);
+ mime_types = g_key_file_get_string_list (key_file, "Specialized Thumbnailer",
+ "MimeTypes", NULL, &error);
+ if (mime_types == NULL)
+ {
+ g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
+ g_clear_error (&error);
- g_key_file_free (key_file);
- g_free (filename);
+ g_free (object_path);
+ g_free (name);
+ g_key_file_free (key_file);
+ g_free (filename);
- continue;
- }
+ return;
+ }
- name = g_key_file_get_string (key_file, "Specialized Thumbnailer", "Name", &error);
- if (name == NULL)
- {
- g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
- g_clear_error (&error);
+ uri_schemes = g_key_file_get_string_list (key_file, "Specialized Thumbnailer",
+ "UriSchemes", NULL, &error);
+ if (uri_schemes == NULL)
+ {
+ uri_schemes = g_new0 (gchar *, 2);
+ uri_schemes[0] = g_strdup ("file");
+ uri_schemes[1] = NULL;
+ }
- g_key_file_free (key_file);
- g_free (filename);
+ if (g_stat (filename, &file_stat) != 0)
+ {
+ g_warning (_("Failed to determine last modified time of \"%s\""), filename);
- continue;
- }
+ g_strfreev (uri_schemes);
+ g_strfreev (mime_types);
+ g_free (object_path);
+ g_free (name);
+ g_key_file_free (key_file);
+ g_free (filename);
- object_path = g_key_file_get_string (key_file, "Specialized Thumbnailer",
- "ObjectPath", &error);
- if (object_path == NULL)
- {
- g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
- g_clear_error (&error);
+ return;
+ }
- g_key_file_free (key_file);
- g_free (filename);
+ info = thumbnailer_info_new ();
+ info->file = g_object_ref (file);
- continue;
- }
+ directory = g_file_get_parent (file);
+ info->dir_index = tumbler_manager_get_dir_index (manager, directory);
+ g_object_unref (directory);
- mime_types = g_key_file_get_string_list (key_file, "Specialized Thumbnailer",
- "MimeTypes", NULL, &error);
- if (mime_types == NULL)
- {
- g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
- g_clear_error (&error);
+ info->thumbnailer =
+ tumbler_specialized_thumbnailer_new (manager->connection, name, object_path,
+ (const gchar *const *)uri_schemes,
+ (const gchar *const *)mime_types,
+ file_stat.st_mtime);
- g_free (object_path);
- g_free (name);
- g_key_file_free (key_file);
- g_free (filename);
+ g_strfreev (uri_schemes);
+ g_strfreev (mime_types);
+ g_free (object_path);
+ g_free (name);
+ g_key_file_free (key_file);
- continue;
- }
+ g_free (filename);
+
+ if (info == NULL)
+ return;
- uri_schemes = g_key_file_get_string_list (key_file, "Specialized Thumbnailer",
- "UriSchemes", NULL, &error);
- if (uri_schemes == NULL)
- {
- uri_schemes = g_new0 (gchar *, 2);
- uri_schemes[0] = g_strdup ("file");
- uri_schemes[1] = NULL;
- }
+ base_name = g_file_get_basename (file);
- if (g_stat (filename, &file_stat) != 0)
+ list = g_hash_table_lookup (manager->thumbnailers, base_name);
+
+ first = FALSE;
+
+ if (list == NULL)
+ {
+ list = g_slice_alloc0 (sizeof (GList *));
+ *list = g_list_prepend (*list, info);
+ g_hash_table_insert (manager->thumbnailers, g_strdup (base_name), list);
+
+ first = TRUE;
+ }
+ else
+ {
+ inserted = FALSE;
+
+ for (lp = *list; lp != NULL; lp = lp->next)
{
- g_warning (_("Failed to determine last modified time of \"%s\""), filename);
+ info2 = lp->data;
- g_strfreev (uri_schemes);
- g_strfreev (mime_types);
- g_free (object_path);
- g_free (name);
- g_key_file_free (key_file);
- g_free (filename);
+ g_assert (info2->dir_index != info->dir_index);
- continue;
+ if (info2->dir_index > info->dir_index)
+ {
+ if (lp == *list)
+ first = TRUE;
+
+ *list = g_list_insert_before (*list, lp, info);
+
+ inserted = TRUE;
+ }
}
- info = thumbnailer_info_new ();
- info->base_name = g_strdup (base_name);
- info->dir_index = g_list_index (manager->directories, directory);
- info->thumbnailer =
- tumbler_specialized_thumbnailer_new (manager->connection, name, object_path,
- (const gchar *const *)uri_schemes,
- (const gchar *const *)mime_types,
- file_stat.st_mtime);
+ if (!inserted)
+ *list = g_list_append (*list, info);
+ }
- g_hash_table_insert (manager->thumbnailers, g_strdup (base_name), info);
+ if (first)
+ {
+ if ((*list)->next != NULL)
+ {
+ info2 = (*list)->next->data;
+ tumbler_registry_remove (manager->registry, info2->thumbnailer);
+ }
- g_strfreev (uri_schemes);
- g_strfreev (mime_types);
- g_free (object_path);
- g_free (name);
- g_key_file_free (key_file);
+ tumbler_registry_add (manager->registry, info->thumbnailer);
- g_free (filename);
+ hash_keys = tumbler_thumbnailer_get_hash_keys (info->thumbnailer);
+
+ for (n = 0; hash_keys != NULL && hash_keys[n] != NULL; ++n)
+ {
+ /* TODO we could check if an update is needed here */
+ tumbler_manager_update_preferred (manager, hash_keys[n]);
+ }
+
+ g_strfreev (hash_keys);
}
+
+ g_free (base_name);
}
static void
-tumbler_manager_update_thumbnailers (TumblerManager *manager)
-{
- TumblerThumbnailer *preferred;
- ThumbnailerInfo *thumbnailer_info;
- GHashTableIter thumbnailer_iter;
- GHashTableIter override_iter;
- OverrideInfo *override_info;
- const gchar *hash_key;
- const gchar *name;
- const gchar *preferred_name;
- GPtrArray *overrides;
- GList *iter;
- guint n;
+tumbler_manager_load_thumbnailers (TumblerManager *manager,
+ GFile *directory)
+{
+ const gchar *base_name;
+ GFileType type;
+ GFile *file;
+ gchar *dirname;
+ GDir *dir;
g_return_if_fail (TUMBLER_IS_MANAGER (manager));
+ g_return_if_fail (G_IS_FILE (directory));
- if (manager->thumbnailers != NULL)
- {
- /* clear the thumbnailer cache */
- g_hash_table_remove_all (manager->thumbnailers);
- }
- else
+ dirname = g_file_get_path (directory);
+
+ g_debug ("load_thumbnailers %s", dirname);
+
+ dir = g_dir_open (dirname, 0, NULL);
+
+ if (dir == NULL)
{
- /* otheriwse allocate the thumbnailer cache on-demand */
- manager->thumbnailers =
- g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
- (GDestroyNotify) thumbnailer_info_free);
+ g_free (dirname);
+ return;
}
- /* iterate over all thumbnailer directories with increasing priority */
- for (iter = manager->directories; iter != NULL; iter = iter->next)
- tumbler_manager_load_thumbnailer_infos (manager, iter->data);
-
- /* iterate over all thumbnailers */
- g_hash_table_iter_init (&thumbnailer_iter, manager->thumbnailers);
- while (g_hash_table_iter_next (&thumbnailer_iter, NULL, (gpointer) &thumbnailer_info))
+ for (base_name = g_dir_read_name (dir);
+ base_name != NULL;
+ base_name = g_dir_read_name (dir))
{
- /* add the thumbnailer to the registry */
- tumbler_registry_add (manager->registry, thumbnailer_info->thumbnailer);
+ if (!g_str_has_suffix (base_name, ".service"))
+ continue;
- /* get the name of the current thumbnailer */
- name = tumbler_specialized_thumbnailer_get_name (
- TUMBLER_SPECIALIZED_THUMBNAILER (thumbnailer_info->thumbnailer));
+ file = g_file_get_child (directory, base_name);
+ type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
- /* iterate over all override info arrays */
- g_hash_table_iter_init (&override_iter, manager->overrides);
- while (g_hash_table_iter_next (&override_iter, (gpointer) &hash_key,
- (gpointer) &overrides))
+ if (type != G_FILE_TYPE_REGULAR)
{
- /* get the current preferred thumbnailer for this URI/MIME pair */
- preferred = tumbler_registry_get_preferred (manager->registry, hash_key);
-
- /* determine its name */
- if (preferred != NULL)
- {
- preferred_name = tumbler_specialized_thumbnailer_get_name (
- TUMBLER_SPECIALIZED_THUMBNAILER (preferred));
- }
- else
- {
- preferred_name = NULL;
- }
-
- /* iterate over all infos in the current array */
- for (n = 0; n < overrides->len; ++n)
- {
- override_info = g_ptr_array_index (overrides, n);
+ g_object_unref (file);
+ continue;
+ }
+
+ tumbler_manager_load_thumbnailer (manager, file);
- /* stop searching if the info matches the already preferred thumbnailer */
- if (preferred_name != NULL
- && g_strcmp0 (preferred_name, override_info->name) == 0)
- {
- break;
- }
+ g_object_unref (file);
+ }
- /* check if the info matches the current thumbnailer */
- if (g_strcmp0 (name, override_info->name) == 0)
- {
- /* make the current thumbnailer the preferred thumbnailer for the
- * hash key */
- tumbler_registry_set_preferred (manager->registry, hash_key,
- thumbnailer_info->thumbnailer);
- }
- }
+ g_dir_close (dir);
- /* release the preferred thumbnailer */
- if (preferred != NULL)
- g_object_unref (preferred);
- }
- }
+ g_free (dirname);
}
static void
-tumbler_manager_load_thumbnailers (TumblerManager *manager)
+tumbler_manager_load (TumblerManager *manager)
{
const gchar *const *data_dirs;
GFileMonitor *monitor;
@@ -770,11 +1053,14 @@ tumbler_manager_load_thumbnailers (TumblerManager *manager)
manager->directories = directories;
manager->monitors = NULL;
- /* update the overrides cache */
- tumbler_manager_update_overrides (manager);
-
/* update the thumbnailer cache */
- tumbler_manager_update_thumbnailers (manager);
+ for (iter = manager->directories; iter != NULL; iter = iter->next)
+ tumbler_manager_load_thumbnailers (manager, iter->data);
+
+ dump_thumbnailers (manager);
+
+ /* update the overrides cache */
+ tumbler_manager_load_overrides (manager);
/* update the supported information */
tumbler_registry_update_supported (manager->registry);
@@ -795,6 +1081,79 @@ tumbler_manager_load_thumbnailers (TumblerManager *manager)
static void
+tumbler_manager_thumbnailer_file_deleted (TumblerManager *manager,
+ GFile *file)
+{
+ ThumbnailerInfo *info;
+ ThumbnailerInfo *info2;
+ GFile *directory;
+ GList **list;
+ GList *lp;
+ GStrv hash_keys;
+ gchar *base_name;
+ guint n;
+ gint dir_index;
+
+ g_return_if_fail (TUMBLER_IS_MANAGER (manager));
+ g_return_if_fail (G_IS_FILE (file));
+
+ g_debug ("file_deleted: %s", g_file_get_path (file));
+
+ directory = g_file_get_parent (file);
+ dir_index = tumbler_manager_get_dir_index (manager, directory);
+ g_object_unref (directory);
+
+ base_name = g_file_get_basename (file);
+ list = g_hash_table_lookup (manager->thumbnailers, base_name);
+ g_free (base_name);
+
+ g_assert (list != NULL);
+ g_assert (*list != NULL);
+
+ for (lp = *list; lp != NULL; lp = lp->next)
+ {
+ info = lp->data;
+
+ if (info->dir_index == dir_index)
+ {
+ if (lp == *list)
+ {
+ *list = g_list_delete_link (*list, lp);
+
+ tumbler_registry_remove (manager->registry, info->thumbnailer);
+
+ if (*list != NULL)
+ {
+ info2 = (*list)->data;
+ g_assert (info2 != NULL);
+ tumbler_registry_add (manager->registry, info2->thumbnailer);
+ }
+
+ hash_keys = tumbler_thumbnailer_get_hash_keys (info->thumbnailer);
+
+ for (n = 0; hash_keys != NULL && hash_keys[n] != NULL; ++n)
+ {
+ /* TODO we could check if an update is needed here */
+ tumbler_manager_update_preferred (manager, hash_keys[n]);
+ }
+
+ g_strfreev (hash_keys);
+ }
+ else
+ {
+ *list = g_list_delete_link (*list, lp);
+ }
+
+ thumbnailer_info_free (info);
+
+ break;
+ }
+ }
+}
+
+
+
+static void
tumbler_manager_directory_changed (TumblerManager *manager,
GFile *file,
GFile *other_file,
@@ -803,43 +1162,77 @@ tumbler_manager_directory_changed (TumblerManager *manager,
{
GFileType type;
gchar *base_name;
+ gint dir_index;
g_return_if_fail (TUMBLER_IS_MANAGER (manager));
g_return_if_fail (G_IS_FILE (file));
g_return_if_fail (G_IS_FILE_MONITOR (monitor));
- type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
-
- if (type == G_FILE_TYPE_REGULAR)
+ if (event_type == G_FILE_MONITOR_EVENT_DELETED)
{
base_name = g_file_get_basename (file);
if (g_strcmp0 (base_name, "overrides") == 0)
{
- g_debug ("overrides file %s changed", g_file_get_path (file));
-
- tumbler_manager_update_overrides (manager);
-
- /* TODO recreate the preferred mapping of the registry */
+ g_mutex_lock (manager->mutex);
+ tumbler_manager_unload_overrides_file (manager, file);
+ dump_overrides (manager);
+ g_mutex_unlock (manager->mutex);
}
else if (g_str_has_suffix (base_name, ".service"))
{
- if (event_type == G_FILE_MONITOR_EVENT_DELETED)
+ g_debug ("service file %s deleted", g_file_get_path (file));
+
+ g_mutex_lock (manager->mutex);
+ tumbler_manager_thumbnailer_file_deleted (manager, file);
+ dump_thumbnailers (manager);
+ g_mutex_unlock (manager->mutex);
+ }
+ else
+ {
+ g_mutex_lock (manager->mutex);
+ dir_index = tumbler_manager_get_dir_index (manager, file);
+ g_mutex_unlock (manager->mutex);
+
+ if (dir_index >= 0)
{
- g_debug ("service file %s deleted", g_file_get_path (file));
+#if 0
+ g_mutex_lock (manager->mutex);
+ tumbler_manager_thumbnailer_dir_deleted (manager, dir_index);
+ g_mutex_unlock (manager->mutex);
+#endif
+ }
+ }
+ }
+ else
+ {
+ type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
+
+ if (type == G_FILE_TYPE_REGULAR)
+ {
+ base_name = g_file_get_basename (file);
- /* TODO remove the thumbnailer from the registry */
- /* TODO if the thumbnailer is preferred, determine which
- * replaces it in the preferred mapping */
+ if (g_strcmp0 (base_name, "overrides") == 0)
+ {
+ if (event_type == G_FILE_MONITOR_EVENT_CREATED)
+ {
+ g_debug ("override file %s created", g_file_get_path (file));
+ g_mutex_lock (manager->mutex);
+ tumbler_manager_load_overrides_file (manager, file);
+ dump_overrides (manager);
+ g_mutex_unlock (manager->mutex);
+ }
}
- else if (event_type == G_FILE_MONITOR_EVENT_CREATED)
+ else if (g_str_has_suffix (base_name, ".service"))
{
- g_debug ("service file %s created", g_file_get_path (file));
-
- /* TODO load the thumbnailer */
- /* TODO add the thumbnailer to the registry */
- /* TODO check if it needs to replace anything else in the
- * preferred mapping */
+ if (event_type == G_FILE_MONITOR_EVENT_CREATED)
+ {
+ g_debug ("service file %s created", g_file_get_path (file));
+ g_mutex_lock (manager->mutex);
+ tumbler_manager_load_thumbnailer (manager, file);
+ dump_thumbnailers (manager);
+ g_mutex_unlock (manager->mutex);
+ }
}
}
}
@@ -915,7 +1308,7 @@ tumbler_manager_start (TumblerManager *manager,
g_mutex_unlock (manager->mutex);
/* load thumbnailers installed into the system permanently */
- tumbler_manager_load_thumbnailers (manager);
+ tumbler_manager_load (manager);
/* this is how I roll */
return TRUE;
diff --git a/tumblerd/tumbler-registry.c b/tumblerd/tumbler-registry.c
index 5b216d0..fac3ef1 100644
--- a/tumblerd/tumbler-registry.c
+++ b/tumblerd/tumbler-registry.c
@@ -33,11 +33,9 @@
static void tumbler_registry_finalize (GObject *object);
-static void tumbler_registry_remove (const gchar *key,
+static void tumbler_registry_remove_thumbnailer (const gchar *key,
GList **list,
TumblerThumbnailer *thumbnailer);
-static void tumbler_registry_unregister (TumblerThumbnailer *thumbnailer,
- TumblerRegistry *registry);
static void tumbler_registry_list_free (gpointer data);
static GList *tumbler_registry_get_thumbnailers_internal (TumblerRegistry *registry);
static gint tumbler_registry_compare (TumblerThumbnailer *a,
@@ -115,35 +113,60 @@ tumbler_registry_finalize (GObject *object)
static void
-tumbler_registry_remove (const gchar *key,
- GList **list,
- TumblerThumbnailer *thumbnailer)
+dump_registry (TumblerRegistry *registry)
{
- GList *lp;
+ TumblerThumbnailer *thumbnailer;
+ GHashTableIter iter;
+ const gchar *hash_key;
+ GList **thumbnailers;
+ GList *lp;
- for (lp = *list; lp != NULL; lp = lp->next)
+ g_print ("\nRegistry:\n");
+
+ g_print (" Preferred Thumbnailers:\n");
+ g_hash_table_iter_init (&iter, registry->preferred_thumbnailers);
+ while (g_hash_table_iter_next (&iter, (gpointer) &hash_key, (gpointer) &thumbnailer))
{
- if (lp->data == thumbnailer)
- *list = g_list_delete_link (*list, lp);
+ g_print (" %s: %s\n", hash_key,
+ tumbler_specialized_thumbnailer_get_name (TUMBLER_SPECIALIZED_THUMBNAILER (thumbnailer)));
}
+ g_print ("\n");
+
+ g_print (" Registry Thumbnailers:\n");
+ g_hash_table_iter_init (&iter, registry->thumbnailers);
+ while (g_hash_table_iter_next (&iter, (gpointer) &hash_key, (gpointer) &thumbnailers))
+ {
+ for (lp = *thumbnailers; lp != NULL; lp = lp->next)
+ {
+ if (TUMBLER_IS_SPECIALIZED_THUMBNAILER (lp->data))
+ {
+ g_print (" %s: %s\n",
+ hash_key, tumbler_specialized_thumbnailer_get_name (lp->data));
+ }
+ }
+ }
+
+ g_print ("\n");
}
static void
-tumbler_registry_unregister (TumblerThumbnailer *thumbnailer,
- TumblerRegistry *registry)
+tumbler_registry_remove_thumbnailer (const gchar *key,
+ GList **list,
+ TumblerThumbnailer *thumbnailer)
{
- g_return_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer));
- g_return_if_fail (TUMBLER_IS_REGISTRY (registry));
-
- g_mutex_lock (registry->mutex);
-
- /* remove the thumbnailer from all hash key lists */
- g_hash_table_foreach (registry->thumbnailers, (GHFunc) tumbler_registry_remove,
- thumbnailer);
+ GList *lp;
- g_mutex_unlock (registry->mutex);
+ for (lp = *list; lp != NULL; lp = lp->next)
+ {
+ if (lp->data == thumbnailer)
+ {
+ g_object_unref (lp->data);
+ *list = g_list_delete_link (*list, lp);
+ break;
+ }
+ }
}
@@ -346,14 +369,37 @@ tumbler_registry_add (TumblerRegistry *registry,
/* insert the pointer to the list in the hash table */
g_hash_table_insert (registry->thumbnailers, g_strdup (hash_keys[n]), list);
}
-
- /* connect to the unregister signal of the thumbnailer */
- g_signal_connect (thumbnailer, "unregister",
- G_CALLBACK (tumbler_registry_unregister), registry);
}
+ /* connect to the unregister signal of the thumbnailer */
+ g_signal_connect_swapped (thumbnailer, "unregister",
+ G_CALLBACK (tumbler_registry_remove), registry);
+
g_strfreev (hash_keys);
+ dump_registry (registry);
+
+ g_mutex_unlock (registry->mutex);
+}
+
+
+
+void
+tumbler_registry_remove (TumblerRegistry *registry,
+ TumblerThumbnailer *thumbnailer)
+{
+ g_return_if_fail (TUMBLER_IS_REGISTRY (registry));
+ g_return_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer));
+
+ g_mutex_lock (registry->mutex);
+
+ g_signal_handlers_disconnect_matched (thumbnailer, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, registry);
+
+ /* remove the thumbnailer from all hash key lists */
+ g_hash_table_foreach (registry->thumbnailers,
+ (GHFunc) tumbler_registry_remove_thumbnailer, thumbnailer);
+
g_mutex_unlock (registry->mutex);
}
@@ -593,7 +639,7 @@ tumbler_registry_get_preferred (TumblerRegistry *registry,
thumbnailer = g_hash_table_lookup (registry->preferred_thumbnailers, hash_key);
g_mutex_unlock (registry->mutex);
- return thumbnailer;
+ return thumbnailer != NULL ? g_object_ref (thumbnailer) : NULL;
}
@@ -605,16 +651,21 @@ tumbler_registry_set_preferred (TumblerRegistry *registry,
{
g_return_if_fail (TUMBLER_IS_REGISTRY (registry));
g_return_if_fail (hash_key != NULL && *hash_key != '\0');
- g_return_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer));
+ g_return_if_fail (thumbnailer == NULL || TUMBLER_IS_THUMBNAILER (thumbnailer));
g_mutex_lock (registry->mutex);
- g_debug ("preferring %s for %s",
- tumbler_specialized_thumbnailer_get_name (TUMBLER_SPECIALIZED_THUMBNAILER (thumbnailer)),
- hash_key);
+ if (thumbnailer == NULL)
+ {
+ g_hash_table_remove (registry->preferred_thumbnailers, hash_key);
+ }
+ else
+ {
+ g_hash_table_insert (registry->preferred_thumbnailers,
+ g_strdup (hash_key), g_object_ref (thumbnailer));
+ }
- g_hash_table_insert (registry->preferred_thumbnailers,
- g_strdup (hash_key), g_object_ref (thumbnailer));
+ dump_registry (registry);
g_mutex_unlock (registry->mutex);
}
diff --git a/tumblerd/tumbler-registry.h b/tumblerd/tumbler-registry.h
index 057ddfa..c58a0e0 100644
--- a/tumblerd/tumbler-registry.h
+++ b/tumblerd/tumbler-registry.h
@@ -42,6 +42,8 @@ gboolean tumbler_registry_load (TumblerRegistry
GError **error);
void tumbler_registry_add (TumblerRegistry *registry,
TumblerThumbnailer *thumbnailer);
+void tumbler_registry_remove (TumblerRegistry *registry,
+ TumblerThumbnailer *thumbnailer);
GList *tumbler_registry_get_thumbnailers (TumblerRegistry *registry) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
TumblerThumbnailer **tumbler_registry_get_thumbnailer_array (TumblerRegistry *registry,
TumblerFileInfo **infos,
diff --git a/tumblerd/tumbler-specialized-thumbnailer.c b/tumblerd/tumbler-specialized-thumbnailer.c
index 3345bca..6642518 100644
--- a/tumblerd/tumbler-specialized-thumbnailer.c
+++ b/tumblerd/tumbler-specialized-thumbnailer.c
@@ -393,8 +393,8 @@ tumbler_specialized_thumbnailer_new (DBusGConnection *connection,
TumblerSpecializedThumbnailer *thumbnailer;
g_return_val_if_fail (connection != NULL, NULL);
- g_return_val_if_fail (object_path != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (object_path != NULL && *object_path != '\0', NULL);
+ g_return_val_if_fail (name != NULL && *name != '\0', NULL);
g_return_val_if_fail (uri_schemes != NULL, NULL);
g_return_val_if_fail (mime_types != NULL, NULL);
More information about the Xfce4-commits
mailing list