[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