[Xfce4-commits] r30018 - in thunar/branches/migration-to-gio: . thunar

Jannis Pohlmann jannis at xfce.org
Mon Jun 15 00:58:18 CEST 2009


Author: jannis
Date: 2009-06-14 22:58:18 +0000 (Sun, 14 Jun 2009)
New Revision: 30018

Modified:
   thunar/branches/migration-to-gio/ChangeLog
   thunar/branches/migration-to-gio/thunar/thunar-icon-factory.c
   thunar/branches/migration-to-gio/thunar/thunar-image.c
   thunar/branches/migration-to-gio/thunar/thunar-list-model.c
   thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.c
   thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.h
Log:
	* thunar/thunar-icon-factory.c: Rewrite the file icon loading process
	  once again, this time based on the also rewritten ThunarThumbnailer.
	  We first assume no thumbnail exists and use the default icon for the
	  MIME type. At the same time we request a thumbnail. Once the
	  thumbnailer has started processing the request, we change to a
	  loading icon. Once thumbnailer has the thumbnail ready, we change
	  to the thumbnail. If there's an error with the thumbnail, we
	  fall back to the default icon.
	* thunar/thunar-image.c: Simplify this one. It now always requests the
	  icon from the icon factory and uses ThunarFileMonitor to watch the
	  file for changes. After each change it requests the icon from the
	  factory again. It's probably a good idea to use the thumbnailer
	  directly, so this will change in the future.
	* thunar/thunar-list-model.c: Don't request thumbnails for the entire
	  content of new folders. Instead, just let the icon renderers do
	  their job. In the future, the model should at least unqueue all
	  requests for the old folder when the folder changes.
	* thunar/thunar-thumbnailer.{c,h}: Rewrite the class entirely. It does
	  asynchronous D-Bus calls now and uses idle sources for updating the
	  thumbnail state of the ThunarFiles for which it requests the
	  thumbnails. It doesn't emit any signals anymore. In the future,
	  there should be a method to cancel all requests made by a component
	  for a certain base URI, so that we can cancel all pending requests
	  when leaving a folder.

Modified: thunar/branches/migration-to-gio/ChangeLog
===================================================================
--- thunar/branches/migration-to-gio/ChangeLog	2009-06-14 22:58:11 UTC (rev 30017)
+++ thunar/branches/migration-to-gio/ChangeLog	2009-06-14 22:58:18 UTC (rev 30018)
@@ -1,3 +1,30 @@
+2009-06-15	Jannis Pohlmann <jannis at xfce.org>
+
+	* thunar/thunar-icon-factory.c: Rewrite the file icon loading process
+	  once again, this time based on the also rewritten ThunarThumbnailer.
+	  We first assume no thumbnail exists and use the default icon for the
+	  MIME type. At the same time we request a thumbnail. Once the
+	  thumbnailer has started processing the request, we change to a
+	  loading icon. Once thumbnailer has the thumbnail ready, we change
+	  to the thumbnail. If there's an error with the thumbnail, we
+	  fall back to the default icon. 
+	* thunar/thunar-image.c: Simplify this one. It now always requests the
+	  icon from the icon factory and uses ThunarFileMonitor to watch the
+	  file for changes. After each change it requests the icon from the
+	  factory again. It's probably a good idea to use the thumbnailer
+	  directly, so this will change in the future.
+	* thunar/thunar-list-model.c: Don't request thumbnails for the entire
+	  content of new folders. Instead, just let the icon renderers do
+	  their job. In the future, the model should at least unqueue all
+	  requests for the old folder when the folder changes.
+	* thunar/thunar-thumbnailer.{c,h}: Rewrite the class entirely. It does
+	  asynchronous D-Bus calls now and uses idle sources for updating the
+	  thumbnail state of the ThunarFiles for which it requests the
+	  thumbnails. It doesn't emit any signals anymore. In the future,
+	  there should be a method to cancel all requests made by a component
+	  for a certain base URI, so that we can cancel all pending requests 
+	  when leaving a folder.
+
 2009-06-14	Jannis Pohlmann <jannis at xfce.org>
 
 	* thunar/thunar-file.{c,h}: Emit a ThunarFileMonitor "file-changed"

Modified: thunar/branches/migration-to-gio/thunar/thunar-icon-factory.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-icon-factory.c	2009-06-14 22:58:11 UTC (rev 30017)
+++ thunar/branches/migration-to-gio/thunar/thunar-icon-factory.c	2009-06-14 22:58:18 UTC (rev 30018)
@@ -38,6 +38,7 @@
 #include <thunar/thunar-preferences.h>
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-thumbnail-frame.h>
+#include <thunar/thunar-thumbnailer.h>
 
 
 
@@ -107,6 +108,7 @@
   GObject __parent__;
 
   ThunarVfsThumbFactory    *thumbnail_factory;
+  ThunarThumbnailer        *thumbnailer;
 
   ThunarPreferences        *preferences;
 
@@ -243,6 +245,9 @@
   factory->thumbnail_factory = thunar_vfs_thumb_factory_new ((THUNAR_THUMBNAIL_SIZE > 128)
                                                             ? THUNAR_VFS_THUMB_SIZE_LARGE
                                                             : THUNAR_VFS_THUMB_SIZE_NORMAL);
+
+  /* create a new thumbnailer */
+  factory->thumbnailer = thunar_thumbnailer_new ();
 }
 
 
@@ -284,6 +289,9 @@
   /* disconnect from the thumbnail factory */
   g_object_unref (G_OBJECT (factory->thumbnail_factory));
 
+  /* release the thumbnailer */
+  g_object_unref (G_OBJECT (factory->thumbnailer));
+
   /* remove the "changed" emission hook from the GtkIconTheme class */
   g_signal_remove_emission_hook (g_signal_lookup ("changed", GTK_TYPE_ICON_THEME), factory->changed_hook_id);
 
@@ -913,23 +921,13 @@
                                     ThunarFileIconState icon_state,
                                     gint                icon_size)
 {
-  GInputStream    *stream;
-  GtkIconInfo     *icon_info;
-#if 0
-  TumblerFileInfo *info;
-  const gchar     *content_type;
-#endif
-  const gchar     *thumbnail_path;
-  GdkPixbuf       *icon = NULL;
-  GIcon           *gicon;
-#if 0
-  gchar          **uris;
-  gchar          **types;
-#endif
-  gchar           *icon_name;
-#if 0
-  gchar           *uri;
-#endif
+  ThunarFileThumbState thumb_state;
+  GInputStream        *stream;
+  GtkIconInfo         *icon_info;
+  const gchar         *thumbnail_path;
+  GdkPixbuf           *icon = NULL;
+  GIcon               *gicon;
+  gchar               *icon_name;
 
   _thunar_return_val_if_fail (THUNAR_IS_ICON_FACTORY (factory), NULL);
   _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
@@ -949,50 +947,90 @@
   /* check if thumbnails are enabled and we can display a thumbnail for the item */
   if (G_LIKELY (factory->show_thumbnails && thunar_file_is_regular (file)))
     {
-      gicon = thunar_file_get_preview_icon (file);
+      /* determine the thumbnail state of the file */
+      thumb_state = thunar_file_get_thumb_state (file);
 
-      if (gicon != NULL)
+      if (thumb_state == THUNAR_FILE_THUMB_STATE_UNKNOWN)
         {
-          if (G_IS_THEMED_ICON (gicon))
+          /* we don't know the state yet so request a new thumbnail */
+          thunar_thumbnailer_queue_file (factory->thumbnailer, file);
+        }
+      else if (thumb_state == THUNAR_FILE_THUMB_STATE_LOADING)
+        {
+          /* we're in the process of creating a thumbnail so use a loading icon */
+          icon = thunar_icon_factory_lookup_icon (factory, "gnome-fs-loading-icon", 
+                                                  icon_size, FALSE);
+
+          if (icon != NULL)
+            return icon;
+        }
+      else if (thumb_state == THUNAR_FILE_THUMB_STATE_READY)
+        {
+          /* thumbnail is ready, but try the preview icon first */
+          gicon = thunar_file_get_preview_icon (file);
+
+          /* check if we have a preview icon */
+          if (gicon != NULL)
             {
-              icon_info = gtk_icon_theme_lookup_by_gicon (factory->icon_theme, 
-                                                          gicon, icon_size, 
-                                                          GTK_ICON_LOOKUP_USE_BUILTIN);
+              if (G_IS_THEMED_ICON (gicon))
+                {
+                  /* we have a themed preview icon, look it up using the icon theme */
+                  icon_info = 
+                    gtk_icon_theme_lookup_by_gicon (factory->icon_theme, 
+                                                    gicon, icon_size, 
+                                                    GTK_ICON_LOOKUP_USE_BUILTIN);
 
-              if (icon_info != NULL)
+                  /* check if the lookup succeeded */
+                  if (icon_info != NULL)
+                    {
+                      /* try to load the pixbuf from the icon info */
+                      icon = gtk_icon_info_load_icon (icon_info, NULL);
+                      gtk_icon_info_free (icon_info);
+                    }
+                }
+              else if (G_IS_LOADABLE_ICON (gicon))
                 {
-                  icon = gtk_icon_info_load_icon (icon_info, NULL);
-                  gtk_icon_info_free (icon_info);
+                  /* we have a loadable icon, try to open it for reading */
+                  stream = g_loadable_icon_load (G_LOADABLE_ICON (icon), icon_size, 
+                                                 NULL, NULL, NULL);
+
+                  /* check if we have a valid input stream */
+                  if (stream != NULL)
+                    {
+                      /* load the pixbuf from the stream */
+                      icon = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
+
+                      /* destroy the stream */
+                      g_object_unref (stream);
+                    }
                 }
+
+              /* release the preview icon */
+              g_object_unref (gicon);
+
+              /* return the icon if we have one */
+              if (icon != NULL)
+                return icon;
             }
-          else if (G_IS_LOADABLE_ICON (gicon))
+          else
             {
-              stream = g_loadable_icon_load (G_LOADABLE_ICON (icon), icon_size, NULL,
-                                             NULL, NULL);
+              /* we have no preview icon but the thumbnail should be ready. determine
+               * the filename of the thumbnail */
+              thumbnail_path = thunar_file_get_thumbnail_path (file);
 
-              if (stream != NULL)
+              /* check if we have a valid path */
+              if (thumbnail_path != NULL)
                 {
-                  icon = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
-                  g_object_unref (stream);
+                  /* try to load the thumbnail */
+                  icon = thunar_icon_factory_load_from_file (factory, thumbnail_path, 
+                                                             icon_size);
+
+                  /* return the thumbnail if it could be loaded */
+                  if (icon != NULL)
+                    return icon;
                 }
             }
-
-          g_object_unref (gicon);
-
-          if (icon != NULL)
-            return icon;
         }
-      else
-        {
-          thumbnail_path = thunar_file_get_thumbnail_path (file);
-          if (thumbnail_path != NULL)
-            {
-              icon = thunar_icon_factory_load_from_file (factory, thumbnail_path, 
-                                                         icon_size);
-              if (icon != NULL)
-                return icon;
-            }
-        }
     }
 
   /* lookup the icon name for the icon in the given state and load the icon */

Modified: thunar/branches/migration-to-gio/thunar/thunar-image.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-image.c	2009-06-14 22:58:11 UTC (rev 30017)
+++ thunar/branches/migration-to-gio/thunar/thunar-image.c	2009-06-14 22:58:18 UTC (rev 30018)
@@ -26,10 +26,10 @@
 #include <glib-object.h>
 
 #include <thunar/thunar-application.h>
+#include <thunar/thunar-file-monitor.h>
 #include <thunar/thunar-image.h>
 #include <thunar/thunar-icon-factory.h>
 #include <thunar/thunar-private.h>
-#include <thunar/thunar-thumbnailer.h>
 
 
 
@@ -55,19 +55,9 @@
                                                guint              prop_id,
                                                const GValue      *value,
                                                GParamSpec        *pspec);
-static void thunar_image_file_changed         (ThunarImage       *image);
-static void thunar_image_thumbnailer_error    (ThunarThumbnailer *thumbnailer,
-                                               guint              handle,
-                                               const gchar      **uris,
-                                               gint               code,
-                                               const gchar       *message,
+static void thunar_image_file_changed         (ThunarFileMonitor *monitor,
+                                               ThunarFile        *file,
                                                ThunarImage       *image);
-static void thunar_image_thumbnailer_finished (ThunarThumbnailer *thumbnailer,
-                                               guint              handle,
-                                               ThunarImage       *image);
-static void thunar_image_thumbnailer_started  (ThunarThumbnailer *thumbnailer,
-                                               guint              handle,
-                                               ThunarImage       *image);
 
 
 
@@ -85,9 +75,8 @@
 
 struct _ThunarImagePrivate
 {
-  ThunarThumbnailer *thumbnailer;
+  ThunarFileMonitor *monitor;
   ThunarFile        *file;
-  guint              thumbnailer_handle;
 };
 
 
@@ -124,9 +113,9 @@
   image->priv = THUNAR_IMAGE_GET_PRIVATE (image);
   image->priv->file = NULL;
 
-  g_signal_connect (image, "notify::file", G_CALLBACK (thunar_image_file_changed), NULL);
-
-  image->priv->thumbnailer = thunar_thumbnailer_new ();
+  image->priv->monitor = thunar_file_monitor_get_default ();
+  g_signal_connect (image->priv->monitor, "file-changed", 
+                    G_CALLBACK (thunar_image_file_changed), image);
 }
 
 
@@ -136,10 +125,12 @@
 {
   ThunarImage *image = THUNAR_IMAGE (object);
 
+  g_signal_handlers_disconnect_by_func (image->priv->monitor, 
+                                        thunar_image_file_changed, image);
+  g_object_unref (image->priv->monitor);
+
   thunar_image_set_file (image, NULL);
 
-  g_object_unref (image->priv->thumbnailer);
-
   (*G_OBJECT_CLASS (thunar_image_parent_class)->finalize) (object);
 }
 
@@ -188,7 +179,7 @@
 
 
 static void
-thunar_image_file_changed (ThunarImage *image)
+thunar_image_update (ThunarImage *image)
 {
   ThunarIconFactory *icon_factory;
   GtkIconTheme      *icon_theme;
@@ -196,79 +187,9 @@
   GdkScreen         *screen;
 
   _thunar_return_if_fail (THUNAR_IS_IMAGE (image));
-
-  if (image->priv->thumbnailer_handle != 0)
-    {
-      thunar_thumbnailer_unqueue (image->priv->thumbnailer, 
-                                  image->priv->thumbnailer_handle);
-
-      image->priv->thumbnailer_handle = 0;
-
-      g_signal_handlers_disconnect_matched (image->priv->thumbnailer, 
-                                            G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
-                                            image);
-    }
-
-  gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
-
-  if (image->priv->file != NULL)
-    {
-      g_signal_connect (image->priv->thumbnailer, "error", 
-                        G_CALLBACK (thunar_image_thumbnailer_error), image);
-      g_signal_connect (image->priv->thumbnailer, "finished", 
-                        G_CALLBACK (thunar_image_thumbnailer_finished), image);
-      g_signal_connect (image->priv->thumbnailer, "started", 
-                        G_CALLBACK (thunar_image_thumbnailer_started), image);
-
-      if (!thunar_thumbnailer_queue_file (image->priv->thumbnailer, image->priv->file, 
-                                          &image->priv->thumbnailer_handle))
-        {
-          g_signal_handlers_disconnect_matched (image->priv->thumbnailer, 
-                                                G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
-                                                image);
-        }
           
-      screen = gtk_widget_get_screen (GTK_WIDGET (image));
-      icon_theme = gtk_icon_theme_get_for_screen (screen);
-      icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
-
-      icon = thunar_icon_factory_load_file_icon (icon_factory, image->priv->file,
-                                                 THUNAR_FILE_ICON_STATE_DEFAULT, 48);
-
-      gtk_image_set_from_pixbuf (GTK_IMAGE (image), icon);
-
-      g_object_unref (icon_factory);
-    }
-}
-
-
-
-static void
-thunar_image_thumbnailer_error (ThunarThumbnailer *thumbnailer,
-                                guint              handle,
-                                const gchar      **uris,
-                                gint               code,
-                                const gchar       *message,
-                                ThunarImage       *image)
-{
-  ThunarIconFactory *icon_factory;
-  GtkIconTheme      *icon_theme;
-  GdkPixbuf         *icon;
-  GdkScreen         *screen;
-
-  _thunar_return_if_fail (THUNAR_IS_IMAGE (image));
-
-  if (image->priv->thumbnailer_handle != handle)
-    return;
-  
-  image->priv->thumbnailer_handle = 0;
-
-  if (image->priv->file == NULL)
+  if (THUNAR_IS_FILE (image->priv->file))
     {
-      gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
-    }
-  else
-    {
       screen = gtk_widget_get_screen (GTK_WIDGET (image));
       icon_theme = gtk_icon_theme_get_for_screen (screen);
       icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
@@ -285,86 +206,20 @@
 
 
 static void
-thunar_image_thumbnailer_finished (ThunarThumbnailer *thumbnailer,
-                                   guint              handle,
-                                   ThunarImage       *image)
+thunar_image_file_changed (ThunarFileMonitor *monitor,
+                           ThunarFile        *file,
+                           ThunarImage       *image)
 {
-  ThunarIconFactory *icon_factory;
-  GtkIconTheme      *icon_theme;
-  GdkPixbuf         *icon;
-  GdkScreen         *screen;
-
+  _thunar_return_if_fail (THUNAR_IS_FILE_MONITOR (monitor));
+  _thunar_return_if_fail (THUNAR_IS_FILE (file));
   _thunar_return_if_fail (THUNAR_IS_IMAGE (image));
 
-  if (image->priv->thumbnailer_handle != handle)
-    return;
-
-  image->priv->thumbnailer_handle = 0;
-
-  g_signal_handlers_disconnect_matched (image->priv->thumbnailer, 
-                                        G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
-                                        image);
-
-  if (image->priv->file == NULL)
-    {
-      gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
-    }
-  else
-    {
-      /* TODO we only need to reload if the thumbnail was regenerated */
-      thunar_file_changed (image->priv->file);
-
-      screen = gtk_widget_get_screen (GTK_WIDGET (image));
-      icon_theme = gtk_icon_theme_get_for_screen (screen);
-      icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
-
-      icon = thunar_icon_factory_load_file_icon (icon_factory, image->priv->file,
-                                                 THUNAR_FILE_ICON_STATE_DEFAULT, 48);
-
-      gtk_image_set_from_pixbuf (GTK_IMAGE (image), icon);
-      
-      g_object_unref (icon_factory);
-    }
+  if (file == image->priv->file)
+    thunar_image_update (image);
 }
 
 
 
-static void
-thunar_image_thumbnailer_started (ThunarThumbnailer *thumbnailer,
-                                  guint              handle,
-                                  ThunarImage       *image)
-{
-  ThunarIconFactory *icon_factory;
-  GtkIconTheme      *icon_theme;
-  GdkPixbuf         *icon;
-  GdkScreen         *screen;
-
-  _thunar_return_if_fail (THUNAR_IS_IMAGE (image));
-
-  if (image->priv->thumbnailer_handle != handle)
-    return;
-
-  if (image->priv->file == NULL)
-    {
-      gtk_image_set_from_pixbuf (GTK_IMAGE (image), NULL);
-    }
-  else
-    {
-      screen = gtk_widget_get_screen (GTK_WIDGET (image));
-      icon_theme = gtk_icon_theme_get_for_screen (screen);
-      icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
-
-      icon = thunar_icon_factory_load_icon (icon_factory, "gnome-fs-loading-icon", 48,
-                                            NULL, FALSE);
-
-      gtk_image_set_from_pixbuf (GTK_IMAGE (image), icon);
-      
-      g_object_unref (icon_factory);
-    }
-}
-
-
-
 GtkWidget *
 thunar_image_new (void)
 {
@@ -392,5 +247,7 @@
   else
     image->priv->file = NULL;
 
+  thunar_image_update (image);
+
   g_object_notify (G_OBJECT (image), "file");
 }

Modified: thunar/branches/migration-to-gio/thunar/thunar-list-model.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-list-model.c	2009-06-14 22:58:11 UTC (rev 30017)
+++ thunar/branches/migration-to-gio/thunar/thunar-list-model.c	2009-06-14 22:58:18 UTC (rev 30018)
@@ -34,7 +34,6 @@
 #include <thunar/thunar-gobject-extensions.h>
 #include <thunar/thunar-list-model.h>
 #include <thunar/thunar-private.h>
-#include <thunar/thunar-thumbnailer.h>
 #include <thunar/thunar-user.h>
 
 
@@ -191,21 +190,6 @@
 static gint               sort_by_type                            (const ThunarFile       *a,
                                                                    const ThunarFile       *b,
                                                                    gboolean                case_sensitive);
-static void               thunar_list_model_thumbnailer_error     (ThunarThumbnailer      *thumbnailer,
-                                                                   guint                   request,
-                                                                   const gchar           **uris,
-                                                                   gint                    code,
-                                                                   const gchar            *message,
-                                                                   ThunarListModel        *store);
-static void               thunar_list_model_thumbnailer_finished  (ThunarThumbnailer      *thumbnailer,
-                                                                   guint                   request,
-                                                                   ThunarListModel        *store);
-static void               thunar_list_model_thumbnailer_ready     (ThunarThumbnailer      *thumbnailer,
-                                                                   const gchar           **uris,
-                                                                   ThunarListModel        *store);
-static void               thunar_list_model_thumbnailer_started   (ThunarThumbnailer      *thumbnailer,
-                                                                   guint                   request,
-                                                                   ThunarListModel        *store);
 
 
 
@@ -255,10 +239,6 @@
   gint         (*sort_func) (const ThunarFile *a,
                              const ThunarFile *b,
                              gboolean          case_sensitive);
-
-  ThunarThumbnailer *thumbnailer;
-  GHashTable        *thumbnailer_files;
-  GList             *thumbnailer_requests;
 };
 
 struct _SortTuple
@@ -502,20 +482,6 @@
   store->file_monitor = thunar_file_monitor_get_default ();
   g_signal_connect (G_OBJECT (store->file_monitor), "file-changed", 
                     G_CALLBACK (thunar_list_model_file_changed), store);
-
-  store->thumbnailer_files = g_hash_table_new_full (g_str_hash, g_str_equal, 
-                                                    g_free, NULL);
-  store->thumbnailer_requests = NULL;
-
-  store->thumbnailer = thunar_thumbnailer_new ();
-  g_signal_connect (store->thumbnailer, "error",
-                    G_CALLBACK (thunar_list_model_thumbnailer_error), store);
-  g_signal_connect (store->thumbnailer, "finished",
-                    G_CALLBACK (thunar_list_model_thumbnailer_finished), store);
-  g_signal_connect (store->thumbnailer, "ready",
-                    G_CALLBACK (thunar_list_model_thumbnailer_ready), store);
-  g_signal_connect (store->thumbnailer, "started",
-                    G_CALLBACK (thunar_list_model_thumbnailer_started), store);
 }
 
 
@@ -524,20 +490,7 @@
 thunar_list_model_finalize (GObject *object)
 {
   ThunarListModel *store = THUNAR_LIST_MODEL (object);
-  GList           *lp;
 
-  /* unqueue all pending thumbnailer requests */
-  for (lp = store->thumbnailer_requests; lp != NULL; lp = lp->next)
-    thunar_thumbnailer_unqueue (store->thumbnailer, GPOINTER_TO_UINT (lp->data));
-
-  /* destroy the URI to thumbnailer request mapping */
-  g_hash_table_unref (store->thumbnailer_files);
-
-  /* release the reference on the thumbnailer */
-  g_signal_handlers_disconnect_matched (store->thumbnailer, G_SIGNAL_MATCH_DATA,
-                                        0, 0, NULL, NULL, store);
-  g_object_unref (store->thumbnailer);
-
   /* unlink from the folder (if any) */
   thunar_list_model_set_folder (store, NULL);
 
@@ -1339,8 +1292,6 @@
   ThunarFile  *file;
   GSList      *prev = NULL;
   GSList      *row;
-  GList       *lp;
-  guint        request;
   gint        *indices;
   gint         index = 0;
 
@@ -1352,19 +1303,6 @@
   path = gtk_tree_path_new_from_indices (0, -1);
   indices = gtk_tree_path_get_indices (path);
       
-  if (thunar_thumbnailer_queue_files (store->thumbnailer, files, &request))
-    {
-      for (lp = files; lp != NULL; lp = lp->next)
-        {
-          g_hash_table_insert (store->thumbnailer_files, 
-                               thunar_file_dup_uri (lp->data),
-                               GUINT_TO_POINTER (request));
-        }
-
-      store->thumbnailer_requests = g_list_prepend (store->thumbnailer_requests,
-                                                    GUINT_TO_POINTER (request));
-    }
-
   /* process all added files */
   for (; files != NULL; files = files->next)
     {
@@ -1680,82 +1618,6 @@
 
 
 
-static void
-thunar_list_model_thumbnailer_error (ThunarThumbnailer *thumbnailer,
-                                     guint              request,
-                                     const gchar      **uris,
-                                     gint               code,
-                                     const gchar       *message,
-                                     ThunarListModel   *store)
-{
-  guint n;
-
-  _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
-  _thunar_return_if_fail (uris != NULL);
-  _thunar_return_if_fail (message != NULL);
-  _thunar_return_if_fail (THUNAR_IS_LIST_MODEL (store));
-
-  for (n = 0; uris[n] != NULL; ++n)
-    g_hash_table_remove (store->thumbnailer_files, uris[n]);
-}
-
-
-
-static void
-thunar_list_model_thumbnailer_finished (ThunarThumbnailer *thumbnailer,
-                                        guint              request,
-                                        ThunarListModel   *store)
-{
-  _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
-  _thunar_return_if_fail (THUNAR_IS_LIST_MODEL (store));
-
-  store->thumbnailer_requests = g_list_remove_all (store->thumbnailer_requests,
-                                                   GUINT_TO_POINTER (request));
-}
-
-
-
-static void
-thunar_list_model_thumbnailer_ready (ThunarThumbnailer *thumbnailer,
-                                     const gchar      **uris,
-                                     ThunarListModel   *store)
-{
-  ThunarFile *file;
-  GFile      *gfile;
-  guint       n;
-
-  _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
-  _thunar_return_if_fail (uris != NULL);
-  _thunar_return_if_fail (THUNAR_IS_LIST_MODEL (store));
-
-  for (n = 0; uris[n] != NULL; ++n)
-    {
-      if (g_hash_table_lookup (store->thumbnailer_files, uris[n]) != NULL)
-        {
-          gfile = g_file_new_for_uri (uris[n]);
-          file = thunar_file_cache_lookup (gfile);
-          g_object_unref (gfile);
-
-          if (file != NULL)
-            thunar_file_changed (file);
-
-          g_hash_table_remove (store->thumbnailer_files, uris[n]);
-        }
-    }
-}
-
-
-
-static void
-thunar_list_model_thumbnailer_started (ThunarThumbnailer *thumbnailer,
-                                       guint              request,
-                                       ThunarListModel   *store)
-{
-  /* TODO Set the status of the corresponding ThunarFile's to LOADING */
-}
-
-
-
 /**
  * thunar_list_model_new:
  *
@@ -1929,11 +1791,6 @@
   if (G_UNLIKELY (store->folder == folder))
     return;
 
-  g_hash_table_remove_all (store->thumbnailer_files);
-
-  for (lp = store->thumbnailer_requests; lp != NULL; lp = lp->next)
-    thunar_thumbnailer_unqueue (store->thumbnailer, GPOINTER_TO_UINT (lp->data));
-
   /* unlink from the previously active folder (if any) */
   if (G_LIKELY (store->folder != NULL))
     {

Modified: thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.c	2009-06-14 22:58:11 UTC (rev 30017)
+++ thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.c	2009-06-14 22:58:18 UTC (rev 30018)
@@ -33,41 +33,53 @@
 
 
 
-/* signal identifiers */
-enum
+typedef enum
 {
-  SIGNAL_ERROR,
-  SIGNAL_FINISHED,
-  SIGNAL_READY,
-  SIGNAL_STARTED,
-  LAST_SIGNAL,
-};
+  THUNAR_THUMBNAILER_IDLE_ERROR,
+  THUNAR_THUMBNAILER_IDLE_READY,
+  THUNAR_THUMBNAILER_IDLE_STARTED,
+} ThunarThumbnailerIdleType;
 
 
 
-static void thunar_thumbnailer_init_thumbnailer_proxy (ThunarThumbnailer *thumbnailer,
-                                                       DBusGConnection   *connection);
-static void thunar_thumbnailer_init_manager_proxy     (ThunarThumbnailer *thumbnailer,
-                                                       DBusGConnection   *connection);
-static void thunar_thumbnailer_finalize               (GObject           *object);
-static void thunar_thumbnailer_thumbnailer_error      (DBusGProxy        *proxy,
-                                                       guint              handle,
-                                                       const gchar      **uris,
-                                                       gint               code,
-                                                       const gchar       *message,
-                                                       ThunarThumbnailer *thumbnailer);
-static void thunar_thumbnailer_thumbnailer_finished   (DBusGProxy        *proxy,
-                                                       guint              handle,
-                                                       ThunarThumbnailer *thumbnailer);
-static void thunar_thumbnailer_thumbnailer_ready      (DBusGProxy        *proxy,
-                                                       const gchar      **uris,
-                                                       ThunarThumbnailer *thumbnailer);
-static void thunar_thumbnailer_thumbnailer_started    (DBusGProxy        *proxy,
-                                                       guint              handle,
-                                                       ThunarThumbnailer *thumbnailer);
+typedef struct _ThunarThumbnailerCall ThunarThumbnailerCall;
+typedef struct _ThunarThumbnailerIdle ThunarThumbnailerIdle;
 
 
 
+static void     thunar_thumbnailer_init_thumbnailer_proxy (ThunarThumbnailer     *thumbnailer,
+                                                           DBusGConnection       *connection);
+static void     thunar_thumbnailer_init_manager_proxy     (ThunarThumbnailer     *thumbnailer,
+                                                           DBusGConnection       *connection);
+static void     thunar_thumbnailer_finalize               (GObject               *object);
+static gboolean thunar_thumbnailer_file_is_supported      (ThunarThumbnailer     *thumbnailer,
+                                                           ThunarFile            *file);
+static void     thunar_thumbnailer_thumbnailer_finished   (DBusGProxy            *proxy,
+                                                           guint                  handle,
+                                                           ThunarThumbnailer     *thumbnailer);
+static void     thunar_thumbnailer_thumbnailer_error      (DBusGProxy            *proxy,
+                                                           guint                  handle,
+                                                           const gchar          **uris,
+                                                           gint                   code,
+                                                           const gchar           *message,
+                                                           ThunarThumbnailer     *thumbnailer);
+static void     thunar_thumbnailer_thumbnailer_ready      (DBusGProxy            *proxy,
+                                                           const gchar          **uris,
+                                                           ThunarThumbnailer     *thumbnailer);
+static void     thunar_thumbnailer_thumbnailer_started    (DBusGProxy            *proxy,
+                                                           guint                  handle,
+                                                           ThunarThumbnailer     *thumbnailer);
+static gpointer thunar_thumbnailer_queue_async            (ThunarThumbnailer     *thumbnailer,
+                                                           const gchar          **uris,
+                                                           const gchar          **mime_hints);
+static gboolean thunar_thumbnailer_error_idle             (gpointer               user_data);
+static gboolean thunar_thumbnailer_ready_idle             (gpointer               user_data);
+static gboolean thunar_thumbnailer_started_idle           (gpointer               user_data);
+static void     thunar_thumbnailer_call_free              (ThunarThumbnailerCall *call);
+static void     thunar_thumbnailer_idle_free              (gpointer               data);
+
+
+
 struct _ThunarThumbnailerClass
 {
   GObjectClass __parent__;
@@ -77,20 +89,58 @@
 {
   GObject __parent__;
 
+  /* proxies to communicate with D-Bus services */
   DBusGProxy *manager_proxy;
   DBusGProxy *thumbnailer_proxy;
 
+  /* hash table to map D-Bus service handles to ThunarThumbnailer requests */
+  GHashTable *handle_request_mapping;
+
+  /* hash table to map ThunarThumbnailer requests to D-Bus service handles */
+  GHashTable *request_handle_mapping;
+
+  /* hash table to map ThunarThumbnailer requests to DBusGProxyCalls */
+  GHashTable *request_call_mapping;
+
+  /* hash table to map ThunarThumbnailer requests to URI arrays */
+  GHashTable *request_uris_mapping;
+
   GMutex     *lock;
 
+  /* cached array of MIME types for which thumbnails can be generated */
   gchar     **supported_types;
+
+  /* last ThunarThumbnailer request ID */
+  gpointer    last_request;
+
+  /* IDs of idle functions */
+  GList      *idles;
 };
 
+struct _ThunarThumbnailerCall
+{
+  ThunarThumbnailer *thumbnailer;
+  gpointer           request;
+};
 
+struct _ThunarThumbnailerIdle
+{
+  ThunarThumbnailerIdleType type;
+  ThunarThumbnailer        *thumbnailer;
+  guint                     id;
 
+  union
+  {
+    char                  **uris;
+    gpointer                request;
+  }                         data;
+};
+
+
+
 static DBusGProxy *thunar_thumbnailer_manager_proxy;
 static DBusGProxy *thunar_thumbnailer_proxy;
 static DBusGProxy *thunar_manager_proxy;
-static guint       thumbnailer_signals[LAST_SIGNAL];
 
 
 
@@ -105,54 +155,6 @@
 
   gobject_class = G_OBJECT_CLASS (klass);
   gobject_class->finalize = thunar_thumbnailer_finalize;
-
-  /* TODO this should actually be VOID:UINT,POINTER,INT,STRING */
-  thumbnailer_signals[SIGNAL_ERROR] =
-    g_signal_new ("error",
-                  THUNAR_TYPE_THUMBNAILER,
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL,
-                  _thunar_marshal_VOID__UINT_POINTER_UINT_STRING,
-                  G_TYPE_NONE,
-                  1,
-                  G_TYPE_UINT,
-                  G_TYPE_STRV,
-                  G_TYPE_UINT,
-                  G_TYPE_STRING);
-
-  thumbnailer_signals[SIGNAL_FINISHED] =
-    g_signal_new ("finished",
-                  THUNAR_TYPE_THUMBNAILER,
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL,
-                  g_cclosure_marshal_VOID__UINT,
-                  G_TYPE_NONE,
-                  1,
-                  G_TYPE_UINT);
-
-  thumbnailer_signals[SIGNAL_READY] =
-    g_signal_new ("ready",
-                  THUNAR_TYPE_THUMBNAILER,
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL,
-                  g_cclosure_marshal_VOID__POINTER,
-                  G_TYPE_NONE,
-                  1,
-                  G_TYPE_STRV);
-
-  thumbnailer_signals[SIGNAL_STARTED] =
-    g_signal_new ("started", 
-                  THUNAR_TYPE_THUMBNAILER,
-                  G_SIGNAL_RUN_LAST, 
-                  0, 
-                  NULL, NULL, 
-                  g_cclosure_marshal_VOID__UINT,
-                  G_TYPE_NONE, 
-                  1, 
-                  G_TYPE_UINT);
 }
 
 
@@ -163,14 +165,33 @@
   DBusGConnection *connection;
 
   thumbnailer->lock = g_mutex_new ();
-
   thumbnailer->supported_types = NULL;
+  thumbnailer->last_request = GUINT_TO_POINTER (0);
+  thumbnailer->idles = NULL;
 
+  /* try to connect to D-Bus */
   connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
 
+  /* initialize the proxies */
   thunar_thumbnailer_init_thumbnailer_proxy (thumbnailer, connection);
   thunar_thumbnailer_init_manager_proxy (thumbnailer, connection);
 
+  /* check if we have a thumbnailer proxy */
+  if (thumbnailer->thumbnailer_proxy != NULL)
+    {
+      /* we do, set up the hash tables */
+      thumbnailer->request_handle_mapping = 
+        g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+      thumbnailer->handle_request_mapping = 
+        g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+      thumbnailer->request_call_mapping = 
+        g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+      thumbnailer->request_uris_mapping =
+        g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, 
+                               (GDestroyNotify) g_strfreev);
+    }
+
+  /* release the D-Bus connection if we have one */
   if (connection != NULL)
     dbus_g_connection_unref (connection);
 }
@@ -181,20 +202,24 @@
 thunar_thumbnailer_init_thumbnailer_proxy (ThunarThumbnailer *thumbnailer,
                                            DBusGConnection   *connection)
 {
+  /* we can't have a proxy without a D-Bus connection */
   if (connection == NULL)
     {
       thumbnailer->thumbnailer_proxy = NULL;
       return;
     }
 
+  /* create the thumbnailer proxy shared by all ThunarThumbnailers on demand */
   if (thunar_thumbnailer_proxy == NULL)
     {
+      /* create the shared thumbnailer proxy */
       thunar_thumbnailer_proxy = 
         dbus_g_proxy_new_for_name (connection, 
                                    "org.freedesktop.thumbnails.Thumbnailer",
                                    "/org/freedesktop/thumbnails/Thumbnailer",
                                    "org.freedesktop.thumbnails.Thumbnailer");
 
+      /* make sure to set it to NULL when the last reference is dropped */
       g_object_add_weak_pointer (G_OBJECT (thunar_thumbnailer_proxy),
                                  (gpointer) &thunar_thumbnailer_proxy);
 
@@ -249,20 +274,24 @@
 thunar_thumbnailer_init_manager_proxy (ThunarThumbnailer *thumbnailer,
                                        DBusGConnection   *connection)
 {
+  /* we cannot have a proxy without a D-Bus connection */
   if (connection == NULL)
     {
       thumbnailer->manager_proxy = NULL;
       return;
     }
 
+  /* create the manager proxy shared by all ThunarThumbnailers on demand */
   if (thunar_manager_proxy == NULL)
     {
+      /* create the shared manager proxy */
       thunar_thumbnailer_manager_proxy = 
         dbus_g_proxy_new_for_name (connection, 
                                    "org.freedesktop.thumbnails.Manager",
                                    "/org/freedesktop/thumbnails/Manager",
                                    "org.freedesktop.thumbnails.Manager");
 
+      /* make sure to set it to NULL when the last reference is dropped */
       g_object_add_weak_pointer (G_OBJECT (thunar_thumbnailer_manager_proxy),
                                  (gpointer) &thunar_thumbnailer_manager_proxy);
 
@@ -279,20 +308,67 @@
 static void
 thunar_thumbnailer_finalize (GObject *object)
 {
-  ThunarThumbnailer *thumbnailer = THUNAR_THUMBNAILER (object);
+  ThunarThumbnailerIdle *idle;
+  ThunarThumbnailer     *thumbnailer = THUNAR_THUMBNAILER (object);
+  GList                 *list;
+  GList                 *lp;
 
   /* acquire the thumbnailer lock */
   g_mutex_lock (thumbnailer->lock);
 
-  /* release the thumbnail factory */
+  /* abort all pending idle functions */
+  for (lp = thumbnailer->idles; lp != NULL; lp = lp->next)
+    {
+      idle = lp->data;
+      g_source_remove (idle->id);
+    }
+
+  /* free the idle list */
+  g_list_free (thumbnailer->idles);
+
+  if (thumbnailer->manager_proxy != NULL)
+    {
+      /* disconnect from the manager proxy */
+      g_signal_handlers_disconnect_matched (thumbnailer->manager_proxy,
+                                            G_SIGNAL_MATCH_DATA, 0, 0,
+                                            NULL, NULL, thumbnailer);
+  
+      /* release the manager proxy */
+      g_object_unref (thumbnailer->manager_proxy);
+    }
+
   if (thumbnailer->thumbnailer_proxy != NULL)
     {
+      /* cancel all pending D-Bus calls */
+      list = g_hash_table_get_values (thumbnailer->request_call_mapping);
+      for (lp = list; lp != NULL; lp = lp->next)
+        dbus_g_proxy_cancel_call (thumbnailer->thumbnailer_proxy, lp->data);
+      g_list_free (list);
+
+      g_hash_table_unref (thumbnailer->request_call_mapping);
+
+#if 0 
+      /* unqueue all pending requests */
+      list = g_hash_table_get_keys (thumbnailer->handle_request_mapping);
+      for (lp = list; lp != NULL; lp = lp->next)
+        thunar_thumbnailer_unqueue_internal (thumbnailer, GPOINTER_TO_UINT (lp->data));
+      g_list_free (list);
+#endif
+
+      g_hash_table_unref (thumbnailer->handle_request_mapping);
+      g_hash_table_unref (thumbnailer->request_handle_mapping);
+      g_hash_table_unref (thumbnailer->request_uris_mapping);
+
+      /* disconnect from the thumbnailer proxy */
       g_signal_handlers_disconnect_matched (thumbnailer->thumbnailer_proxy,
                                             G_SIGNAL_MATCH_DATA, 0, 0, 
                                             NULL, NULL, thumbnailer);
+
+      /* release the thumbnailer proxy */
       g_object_unref (thumbnailer->thumbnailer_proxy);
     }
 
+  /* free the cached MIME types array */
   g_strfreev (thumbnailer->supported_types);
 
   /* release the thumbnailer lock */
@@ -306,6 +382,61 @@
 
 
 
+static gboolean
+thunar_thumbnailer_file_is_supported (ThunarThumbnailer *thumbnailer,
+                                      ThunarFile        *file)
+{
+  const gchar *content_type;
+  gboolean     supported = FALSE;
+  guint        n;
+
+  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
+  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
+
+  /* acquire the thumbnailer lock */
+  g_mutex_lock (thumbnailer->lock);
+
+  /* just assume all types are supported if we don't have a manager */
+  if (thumbnailer->manager_proxy == NULL)
+    {
+      /* release the thumbnailer lock */
+      g_mutex_unlock (thumbnailer->lock);
+      return TRUE;
+    }
+
+  /* request the supported types on demand */
+  if (thumbnailer->supported_types == NULL)
+    {
+      /* request the supported types from the manager D-Bus service. We only do
+       * this once, so using a non-async call should be ok */
+      thunar_thumbnailer_manager_proxy_get_supported (thumbnailer->manager_proxy,
+                                                      &thumbnailer->supported_types, 
+                                                      NULL);
+    }
+
+  /* check if we have supported types now */
+  if (thumbnailer->supported_types != NULL)
+    {
+      /* determine the content type of the passed file */
+      content_type = thunar_file_get_content_type (file);
+
+      /* go through all the types */
+      for (n = 0; !supported && thumbnailer->supported_types[n] != NULL; ++n)
+        {
+          /* check if the type of the file is a subtype of the supported type */
+          if (g_content_type_is_a (content_type, thumbnailer->supported_types[n]))
+            supported = TRUE;
+        }
+    }
+
+  /* release the thumbnailer lock */
+  g_mutex_unlock (thumbnailer->lock);
+
+  return supported;
+}
+
+
+
 static void
 thunar_thumbnailer_thumbnailer_error (DBusGProxy        *proxy,
                                       guint              handle,
@@ -314,15 +445,35 @@
                                       const gchar       *message,
                                       ThunarThumbnailer *thumbnailer)
 {
+  ThunarThumbnailerIdle *idle;
+  gpointer               request;
+
   _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
-  _thunar_return_if_fail (uris != NULL);
-  _thunar_return_if_fail (message != NULL);
   _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
-  
-  g_debug ("error");
 
-  g_signal_emit (thumbnailer, thumbnailer_signals[SIGNAL_ERROR], 0,
-                 handle, uris, code, message);
+  /* look up the request ID for this D-Bus service handle */
+  request = g_hash_table_lookup (thumbnailer->handle_request_mapping,
+                                 GUINT_TO_POINTER (handle));
+
+  /* check if we have a request for this handle */
+  if (request != NULL)
+    {
+      /* allocate a new idle struct */
+      idle = _thunar_slice_new0 (ThunarThumbnailerIdle);
+      idle->type = THUNAR_THUMBNAILER_IDLE_ERROR;
+      idle->thumbnailer = g_object_ref (thumbnailer);
+
+      /* copy the URIs because we need them in the idle function */
+      idle->data.uris = g_strdupv ((gchar **)uris);
+
+      /* remember the idle struct because we might have to remove it in finalize() */
+      thumbnailer->idles = g_list_prepend (thumbnailer->idles, idle);
+
+      /* call the error idle function when we have the time */
+      idle->id = g_idle_add_full (G_PRIORITY_LOW,
+                                  thunar_thumbnailer_error_idle, idle,
+                                  thunar_thumbnailer_idle_free);
+    }
 }
 
 
@@ -332,10 +483,23 @@
                                          guint              handle,
                                          ThunarThumbnailer *thumbnailer)
 {
+  gpointer request;
+
   _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
   _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
 
-  g_signal_emit (thumbnailer, thumbnailer_signals[SIGNAL_FINISHED], 0, handle);
+  /* look up the request ID for this D-Bus service handle */
+  request = g_hash_table_lookup (thumbnailer->handle_request_mapping, 
+                                 GUINT_TO_POINTER (handle));
+
+  /* check if we have a request for this handle */
+  if (request != NULL)
+    {
+      /* the request is finished, drop all the information about it */
+      g_hash_table_remove (thumbnailer->handle_request_mapping, request);
+      g_hash_table_remove (thumbnailer->request_handle_mapping, request);
+      g_hash_table_remove (thumbnailer->request_uris_mapping, request);
+    }
 }
 
 
@@ -345,11 +509,30 @@
                                       const gchar      **uris,
                                       ThunarThumbnailer *thumbnailer)
 {
+  ThunarThumbnailerIdle *idle;
+
   _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
-  _thunar_return_if_fail (uris != NULL);
   _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
-  
-  g_signal_emit (thumbnailer, thumbnailer_signals[SIGNAL_READY], 0, uris);
+
+  /* check if we have any ready URIs */
+  if (uris != NULL)
+    {
+      /* allocate a new idle struct */
+      idle = _thunar_slice_new0 (ThunarThumbnailerIdle);
+      idle->type = THUNAR_THUMBNAILER_IDLE_READY;
+      idle->thumbnailer = g_object_ref (thumbnailer);
+
+      /* copy the URI array because we need it in the idle function */
+      idle->data.uris = g_strdupv ((gchar **)uris);
+
+      /* remember the idle struct because we might have to remove it in finalize() */
+      thumbnailer->idles = g_list_prepend (thumbnailer->idles, idle);
+
+      /* call the ready idle function when we have the time */
+      idle->id = g_idle_add_full (G_PRIORITY_LOW, 
+                                 thunar_thumbnailer_ready_idle, idle, 
+                                 thunar_thumbnailer_idle_free);
+    }
 }
 
 
@@ -359,14 +542,293 @@
                                         guint              handle,
                                         ThunarThumbnailer *thumbnailer)
 {
+  ThunarThumbnailerIdle *idle;
+  gpointer               request;
+
   _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
   _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
 
-  g_signal_emit (thumbnailer, thumbnailer_signals[SIGNAL_STARTED], 0, handle);
+  /* look up the request for this D-Bus service handle */
+  request = g_hash_table_lookup (thumbnailer->handle_request_mapping, 
+                                 GUINT_TO_POINTER (handle));
+
+  /* check if we have a request for this handle */
+  if (request != NULL)
+    {
+      /* allocate a new idle struct */
+      idle = _thunar_slice_new0 (ThunarThumbnailerIdle);
+      idle->type = THUNAR_THUMBNAILER_IDLE_STARTED;
+      idle->thumbnailer = g_object_ref (thumbnailer);
+
+      /* remember the request because we need it in the idle function */
+      idle->data.request = request;
+
+      /* remember the idle struct because we might have to remove it in finalize() */
+      thumbnailer->idles = g_list_prepend (thumbnailer->idles, idle);
+
+      /* call the started idle function when we have the time */
+      idle->id = g_idle_add_full (G_PRIORITY_LOW,
+                                  thunar_thumbnailer_started_idle, idle, 
+                                  thunar_thumbnailer_idle_free);
+    }
 }
 
 
 
+static void
+thunar_thumbnailer_queue_async_reply (DBusGProxy *proxy,
+                                      guint       handle,
+                                      GError     *error,
+                                      gpointer    user_data)
+{
+  ThunarThumbnailerCall *call = user_data;
+  ThunarThumbnailer     *thumbnailer = THUNAR_THUMBNAILER (call->thumbnailer);
+  gchar                **uris;
+
+  _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
+  _thunar_return_if_fail (call != NULL);
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
+
+  g_mutex_lock (thumbnailer->lock);
+
+  if (error != NULL)
+    {
+      /* get the URIs array for this request */
+      uris = g_hash_table_lookup (thumbnailer->request_uris_mapping, call->request);
+
+      /* the array should always exist, otherwise there's a bug in the program */
+      _thunar_assert (uris != NULL);
+
+      /* the request is "finished", forget about its URIs */
+      g_hash_table_remove (thumbnailer->request_uris_mapping, call->request);
+    }
+  else
+    {
+      /* remember that this request and D-Bus handle belong together */
+      g_hash_table_insert (thumbnailer->request_handle_mapping,
+                           call->request, GUINT_TO_POINTER (handle));
+      g_hash_table_insert (thumbnailer->handle_request_mapping, 
+                           GUINT_TO_POINTER (handle), call->request);
+    }
+
+  /* the queue call is finished, we can forget about its proxy call */
+  g_hash_table_remove (thumbnailer->request_call_mapping, call->request);
+
+  thunar_thumbnailer_call_free (call);
+
+  g_mutex_unlock (thumbnailer->lock);
+}
+
+
+
+static gpointer
+thunar_thumbnailer_queue_async (ThunarThumbnailer *thumbnailer,
+                                const gchar      **uris,
+                                const gchar      **mime_hints)
+{
+  ThunarThumbnailerCall *thumbnailer_call;
+  DBusGProxyCall        *call;
+  gpointer               request;
+  guint                  request_no;
+
+  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), 0);
+  _thunar_return_val_if_fail (uris != NULL, 0);
+  _thunar_return_val_if_fail (mime_hints != NULL, 0);
+  _thunar_return_val_if_fail (DBUS_IS_G_PROXY (thumbnailer->thumbnailer_proxy), 0);
+
+  /* compute the next request ID, making sure it's never 0 */
+  request_no = GPOINTER_TO_UINT (thumbnailer->last_request) + 1;
+  request_no = MAX (request_no, 1);
+  
+  /* remember the ID for the next request */
+  thumbnailer->last_request = GUINT_TO_POINTER (request_no);
+
+  /* use the new request ID for this request */
+  request = thumbnailer->last_request;
+
+  /* allocate a new call struct for the async D-Bus call */
+  thumbnailer_call = _thunar_slice_new0 (ThunarThumbnailerCall);
+  thumbnailer_call->request = request;
+  thumbnailer_call->thumbnailer = g_object_ref (thumbnailer);
+
+  /* queue thumbnails for the given URIs asynchronously */
+  call = thunar_thumbnailer_proxy_queue_async (thumbnailer->thumbnailer_proxy,
+                                               uris, mime_hints, 0, 
+                                               thunar_thumbnailer_queue_async_reply,
+                                               thumbnailer_call);
+
+  /* remember to which request the call struct belongs */
+  g_hash_table_insert (thumbnailer->request_call_mapping, request, call);
+
+  /* return the request ID used for this request */
+  return request;
+}
+
+
+
+static gboolean
+thunar_thumbnailer_error_idle (gpointer user_data)
+{
+  ThunarThumbnailerIdle *idle = user_data;
+  ThunarFile            *file;
+  GFile                 *gfile;
+  guint                  n;
+
+  _thunar_return_val_if_fail (idle != NULL, FALSE);
+  _thunar_return_val_if_fail (idle->type == THUNAR_THUMBNAILER_IDLE_ERROR, FALSE);
+
+  /* iterate over all failed URIs */
+  for (n = 0; idle->data.uris != NULL && idle->data.uris[n] != NULL; ++n)
+    {
+      /* look up the corresponding ThunarFile from the cache */
+      gfile = g_file_new_for_uri (idle->data.uris[n]);
+      file = thunar_file_cache_lookup (gfile);
+      g_object_unref (gfile);
+
+      /* check if we have a file for this URI in the cache */
+      if (file != NULL)
+        {
+          /* set thumbnail state to none unless the thumbnail has already been created.
+           * This is to prevent race conditions with the other idle functions */
+          if (thunar_file_get_thumb_state (file) != THUNAR_FILE_THUMB_STATE_READY)
+            thunar_file_set_thumb_state (file, THUNAR_FILE_THUMB_STATE_NONE);
+        }
+    }
+
+  /* remove the idle struct */
+  g_mutex_lock (idle->thumbnailer->lock);
+  idle->thumbnailer->idles = g_list_remove (idle->thumbnailer->idles, idle);
+  g_mutex_unlock (idle->thumbnailer->lock);
+
+  /* remove the idle source, which also destroys the idle struct */
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_thumbnailer_ready_idle (gpointer user_data)
+{
+  ThunarThumbnailerIdle *idle = user_data;
+  ThunarFile            *file;
+  GFile                 *gfile;
+  guint                  n;
+
+  _thunar_return_val_if_fail (idle != NULL, FALSE);
+  _thunar_return_val_if_fail (idle->type == THUNAR_THUMBNAILER_IDLE_READY, FALSE);
+
+  /* iterate over all failed URIs */
+  for (n = 0; idle->data.uris != NULL && idle->data.uris[n] != NULL; ++n)
+    {
+      /* look up the corresponding ThunarFile from the cache */
+      gfile = g_file_new_for_uri (idle->data.uris[n]);
+      file = thunar_file_cache_lookup (gfile);
+      g_object_unref (gfile);
+
+      /* check if we have a file for this URI in the cache */
+      if (file != NULL)
+        {
+          /* set thumbnail state to ready - we now have a thumbnail */
+          thunar_file_set_thumb_state (file, THUNAR_FILE_THUMB_STATE_READY);
+        }
+    }
+
+  /* remove the idle struct */
+  g_mutex_lock (idle->thumbnailer->lock);
+  idle->thumbnailer->idles = g_list_remove (idle->thumbnailer->idles, idle);
+  g_mutex_unlock (idle->thumbnailer->lock);
+
+  /* remove the idle source, which also destroys the idle struct */
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_thumbnailer_started_idle (gpointer user_data)
+{
+  ThunarThumbnailerIdle *idle = user_data;
+  const gchar          **uris;
+  ThunarFile            *file;
+  GFile                 *gfile;
+  guint                  n;
+
+  _thunar_return_val_if_fail (idle != NULL, FALSE);
+  _thunar_return_val_if_fail (idle->type == THUNAR_THUMBNAILER_IDLE_STARTED, FALSE);
+
+  g_mutex_lock (idle->thumbnailer->lock);
+
+  /* look up the URIs that belong to this request */
+  uris = g_hash_table_lookup (idle->thumbnailer->request_uris_mapping, 
+                              idle->data.request);
+
+  /* iterate over all URIs if there are any */
+  for (n = 0; uris != NULL && uris[n] != NULL; ++n)
+    {
+      /* look up the corresponding ThunarFile from the cache */
+      gfile = g_file_new_for_uri (uris[n]);
+      file = thunar_file_cache_lookup (gfile);
+      g_object_unref (gfile);
+
+      /* check if we have a file in the cache */
+      if (file != NULL)
+        {
+          /* set the thumbnail state to loading unless we already have a thumbnail.
+           * This is to prevent race conditions with the other idle functions */
+          if (thunar_file_get_thumb_state (file) != THUNAR_FILE_THUMB_STATE_READY)
+            thunar_file_set_thumb_state (file, THUNAR_FILE_THUMB_STATE_LOADING);
+        }
+    }
+  
+
+  /* remove the idle struct */
+  idle->thumbnailer->idles = g_list_remove (idle->thumbnailer->idles, idle);
+
+  g_mutex_unlock (idle->thumbnailer->lock);
+
+  /* remove the idle source, which also destroys the idle struct */
+  return FALSE;
+}
+
+
+
+static void
+thunar_thumbnailer_call_free (ThunarThumbnailerCall *call)
+{
+  _thunar_return_if_fail (call != NULL);
+
+  /* drop the thumbnailer reference */
+  g_object_unref (call->thumbnailer);
+
+  /* free the struct */
+  _thunar_slice_free (ThunarThumbnailerCall, call);
+}
+
+
+
+static void
+thunar_thumbnailer_idle_free (gpointer data)
+{
+  ThunarThumbnailerIdle *idle = data;
+
+  _thunar_return_if_fail (idle != NULL);
+
+  /* free the URI array if necessary */
+  if (idle->type == THUNAR_THUMBNAILER_IDLE_READY 
+      || idle->type == THUNAR_THUMBNAILER_IDLE_ERROR)
+    {
+      g_strfreev (idle->data.uris);
+    }
+
+  /* drop the thumbnailer reference */
+  g_object_unref (idle->thumbnailer);
+
+  /* free the struct */
+  _thunar_slice_free (ThunarThumbnailerIdle, idle);
+}
+
+
+
 /**
  * thunar_thumbnailer_new:
  *
@@ -388,63 +850,39 @@
 
 gboolean
 thunar_thumbnailer_queue_file (ThunarThumbnailer *thumbnailer,
-                               ThunarFile        *file,
-                               guint             *handle)
+                               ThunarFile        *file)
 {
-  const gchar *mime_hints[2] = { NULL, NULL };
-  gboolean     supported = FALSE;
-  gboolean     success = FALSE;
-  gchar       *uris[2] = { NULL, NULL };
+  GList files;
 
   _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
   _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
-  _thunar_return_val_if_fail (handle != NULL, FALSE);
 
-  /* acquire the thumbnailer lock */
-  g_mutex_lock (thumbnailer->lock);
+  /* fake a file list */
+  files.data = file;
+  files.next = NULL;
+  files.prev = NULL;
 
-  if (thumbnailer->thumbnailer_proxy != NULL)
-    {
-      g_mutex_unlock (thumbnailer->lock);
-      supported = thunar_thumbnailer_file_is_supported (thumbnailer, file);
-      g_mutex_lock (thumbnailer->lock);
-
-      if (supported)
-        {
-          uris[0] = thunar_file_dup_uri (file);
-          mime_hints[0] = thunar_file_get_content_type (file);
-
-          success =thunar_thumbnailer_proxy_queue (thumbnailer->thumbnailer_proxy,
-                                                   (const gchar **)uris, 
-                                                   mime_hints, 0, handle, NULL);
-
-          g_free (uris[0]);
-        }
-    }
-
-  /* release the thumbnailer lock */
-  g_mutex_unlock (thumbnailer->lock);
-
-  return success;
+  /* queue a thumbnail request for the file */
+  return thunar_thumbnailer_queue_files (thumbnailer, &files);
 }
 
 
 
 gboolean
 thunar_thumbnailer_queue_files (ThunarThumbnailer *thumbnailer,
-                                GList             *files,
-                                guint             *handle)
+                                GList             *files)
 {
   const gchar **mime_hints;
   gboolean      success = FALSE;
+  gpointer      request;
   GList        *lp;
   GList        *supported_files = NULL;
   gchar       **uris;
+  guint         n_supported = 0;
   guint         n;
 
   _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
   _thunar_return_val_if_fail (files != NULL, FALSE);
-  _thunar_return_val_if_fail (handle != NULL, FALSE);
 
   /* acquire the thumbnailer lock */
   g_mutex_lock (thumbnailer->lock);
@@ -453,34 +891,50 @@
     {
       g_mutex_unlock (thumbnailer->lock);
 
+      /* collect all supported files from the list */
       for (lp = g_list_last (files); lp != NULL; lp = lp->prev)
         if (thunar_thumbnailer_file_is_supported (thumbnailer, lp->data))
-          supported_files = g_list_prepend (supported_files, lp->data);
+          {
+            supported_files = g_list_prepend (supported_files, lp->data);
+            n_supported += 1;
+          }
 
       g_mutex_lock (thumbnailer->lock);
 
+      /* check if we have any supported files */
       if (supported_files != NULL)
         {
-          uris = g_new0 (gchar *, g_list_length (supported_files) + 1);
-          mime_hints = g_new0 (const gchar *, g_list_length (supported_files) + 1);
+          /* allocate arrays for URIs and mime hints */
+          uris = g_new0 (gchar *, n_supported + 1);
+          mime_hints = g_new0 (const gchar *, n_supported + 1);
 
+          /* fill arrays with data from the supported files */
           for (lp = supported_files, n = 0; lp != NULL; lp = lp->next, ++n)
             {
               uris[n] = thunar_file_dup_uri (lp->data);
               mime_hints[n] = thunar_file_get_content_type (lp->data);
             }
 
+          /* NULL-terminate both arrays */
           uris[n] = NULL;
           mime_hints[n] = NULL;
 
+          /* queue a thumbnail request for the supported files */
+          request = thunar_thumbnailer_queue_async (thumbnailer, 
+                                                    (const gchar **)uris,
+                                                    mime_hints);
+
+          /* remember the URIs for this request */
+          g_hash_table_insert (thumbnailer->request_uris_mapping, request, uris);
+
+          /* free mime hints array */
+          g_free (mime_hints);
+
+          /* free the list of supported files */
           g_list_free (supported_files);
-              
-          success = thunar_thumbnailer_proxy_queue (thumbnailer->thumbnailer_proxy, 
-                                                    (const gchar **)uris, mime_hints, 
-                                                    0, handle, NULL);
 
-          g_strfreev (uris);
-          g_free (mime_hints);
+          /* we assume success if we've come so far */
+          success = TRUE;
         }
     }
 
@@ -494,63 +948,27 @@
 
 void
 thunar_thumbnailer_unqueue (ThunarThumbnailer *thumbnailer,
-                            guint              handle)
+                            gpointer           request)
 {
+  gpointer handle;
+
   _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
 
   /* acquire the thumbnailer lock */
   g_mutex_lock (thumbnailer->lock);
 
   if (thumbnailer->thumbnailer_proxy != NULL)
-    thunar_thumbnailer_proxy_unqueue (thumbnailer->thumbnailer_proxy, handle, NULL);
-
-  /* release the thumbnailer lock */
-  g_mutex_unlock (thumbnailer->lock);
-}
-
-
-
-gboolean
-thunar_thumbnailer_file_is_supported (ThunarThumbnailer *thumbnailer,
-                                      ThunarFile        *file)
-{
-  const gchar *content_type;
-  gboolean     supported = FALSE;
-  guint        n;
-
-  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
-  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
-
-  /* acquire the thumbnailer lock */
-  g_mutex_lock (thumbnailer->lock);
-
-  if (thumbnailer->manager_proxy == NULL)
     {
-      /* release the thumbnailer lock */
-      g_mutex_unlock (thumbnailer->lock);
-      return TRUE;
-    }
+      handle = g_hash_table_lookup (thumbnailer->request_handle_mapping, request);
 
-  if (thumbnailer->supported_types == NULL)
-    {
-      thunar_thumbnailer_manager_proxy_get_supported (thumbnailer->manager_proxy,
-                                                      &thumbnailer->supported_types, 
-                                                      NULL);
-    }
+      thunar_thumbnailer_proxy_unqueue (thumbnailer->thumbnailer_proxy, 
+                                        GPOINTER_TO_UINT (handle), NULL);
 
-  if (thumbnailer->supported_types != NULL)
-    {
-      for (n = 0; !supported && thumbnailer->supported_types[n] != NULL; ++n)
-        {
-          content_type = thunar_file_get_content_type (file);
-
-          if (g_content_type_is_a (content_type, thumbnailer->supported_types[n]))
-            supported = TRUE;
-        }
+      g_hash_table_remove (thumbnailer->handle_request_mapping, handle);
+      g_hash_table_remove (thumbnailer->request_handle_mapping, request);
+      g_hash_table_remove (thumbnailer->request_uris_mapping, request);
     }
 
   /* release the thumbnailer lock */
   g_mutex_unlock (thumbnailer->lock);
-
-  return supported;
 }

Modified: thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.h
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.h	2009-06-14 22:58:11 UTC (rev 30017)
+++ thunar/branches/migration-to-gio/thunar/thunar-thumbnailer.h	2009-06-14 22:58:18 UTC (rev 30018)
@@ -39,15 +39,9 @@
 ThunarThumbnailer *thunar_thumbnailer_new               (void) G_GNUC_MALLOC;
 
 gboolean           thunar_thumbnailer_queue_file        (ThunarThumbnailer *generator,
-                                                         ThunarFile        *file,
-                                                         guint             *handle);
-gboolean           thunar_thumbnailer_queue_files       (ThunarThumbnailer *generator,
-                                                         GList             *files,
-                                                         guint             *handle);
-void               thunar_thumbnailer_unqueue           (ThunarThumbnailer *thumbnailer,
-                                                         guint              handle);
-gboolean           thunar_thumbnailer_file_is_supported (ThunarThumbnailer *thumbnailer,
                                                          ThunarFile        *file);
+gboolean           thunar_thumbnailer_queue_files       (ThunarThumbnailer *generator,
+                                                         GList             *files);
 
 G_END_DECLS;
 




More information about the Xfce4-commits mailing list