diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 0b45ce907454ad9c94dc783a59c4423e231089f6..b715fea7d6e192cf6ea8c92c1ed6eb4d1c802b3e 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -201,6 +201,8 @@ Thunar_SOURCES =							\
 	thunar-throbber.h						\
 	thunar-throbber-fallback.c					\
 	thunar-throbber-fallback.h					\
+	thunar-thumbnail-cache.c					\
+	thunar-thumbnail-cache.h					\
 	thunar-thumbnailer.c						\
 	thunar-thumbnailer.h						\
 	thunar-thumbnail-frame.c					\
@@ -260,6 +262,7 @@ Thunar_DEPENDENCIES =							\
 if HAVE_DBUS
 thunar_built_sources +=							\
 	thunar-dbus-service-infos.h					\
+	thunar-thumbnail-cache-proxy.h					\
 	thunar-thumbnailer-proxy.h
 
 thunar_dbus_sources =							\
@@ -267,6 +270,7 @@ thunar_dbus_sources =							\
 	thunar-dbus-client.h						\
 	thunar-dbus-service.c						\
 	thunar-dbus-service.h						\
+	thunar-thumbnail-cache-proxy.h					\
 	thunar-thumbnailer-proxy.h
 
 Thunar_CFLAGS +=							\
@@ -344,6 +348,14 @@ thunar-thumbnailer-proxy.h: $(srcdir)/thunar-thumbnailer-dbus.xml Makefile
 		&& sed -i -e 's/org_freedesktop_thumbnails_Thumbnailer1/thunar_thumbnailer_proxy/g' \
 			thunar-thumbnailer-proxy.h \
 	)
+
+thunar-thumbnail-cache-proxy.h: $(srcdir)/thunar-thumbnail-cache-dbus.xml Makefile
+	$(AM_V_GEN) ( \
+		dbus-binding-tool --mode=glib-client \
+			$(srcdir)/thunar-thumbnail-cache-dbus.xml > thunar-thumbnail-cache-proxy.h \
+		&& sed -i -e 's/org_freedesktop_thumbnails_Cache1/thunar_thumbnail_cache_proxy/g' \
+			thunar-thumbnail-cache-proxy.h \
+	)
 endif
 
 thunar-throbber-fallback.c: $(srcdir)/thunar-throbber-fallback.png Makefile
diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c
index 4490105f0b475327082ee3212d7fa0900dd96516..8a5744a5b762ec1a56d62da601e56358d97e6eeb 100644
--- a/thunar/thunar-application.c
+++ b/thunar/thunar-application.c
@@ -1,22 +1,23 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
  * Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org>
  * Copyright (c) 2005      Jeff Franks <jcfranks@xfce.org>
- * Copyright (c) 2009-2010 Jannis Pohlmann <jannis@xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -53,6 +54,7 @@
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-progress-dialog.h>
 #include <thunar/thunar-renamer-dialog.h>
+#include <thunar/thunar-thumbnail-cache.h>
 #include <thunar/thunar-util.h>
 
 
@@ -130,6 +132,8 @@ struct _ThunarApplication
   GtkWidget             *progress_dialog;
   GList                 *windows;
 
+  ThunarThumbnailCache  *thumbnail_cache;
+
   gboolean               daemon;
 
   guint                  show_dialogs_timer_id;
@@ -205,6 +209,7 @@ thunar_application_init (ThunarApplication *application)
 
   /* initialize the application */
   application->preferences = thunar_preferences_get ();
+  application->thumbnail_cache = thunar_thumbnail_cache_new ();
 
   application->files_to_launch = NULL;
   application->progress_dialog = NULL;
@@ -279,6 +284,9 @@ thunar_application_finalize (GObject *object)
     }
   g_list_free (application->windows);
 
+  /* release the thumbnail cache */
+  g_object_unref (G_OBJECT (application->thumbnail_cache));
+
   /* disconnect from the preferences */
   g_object_unref (G_OBJECT (application->preferences));
   
@@ -1985,3 +1993,12 @@ thunar_application_restore_files (ThunarApplication *application,
 }
 
 
+
+ThunarThumbnailCache *
+thunar_application_get_thumbnail_cache (ThunarApplication *application)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_APPLICATION (application), NULL);
+  return g_object_ref (application->thumbnail_cache);
+}
+
+
diff --git a/thunar/thunar-application.h b/thunar/thunar-application.h
index cb42877a62e1ccb1779224599ae0d1ec8fc1e70a..50845a3e01a4dc6fdc236b7063c87b532257773b 100644
--- a/thunar/thunar-application.h
+++ b/thunar/thunar-application.h
@@ -1,28 +1,30 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
  * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
  * Copyright (c) 2005      Jeff Franks <jcfranks@xfce.org>
- * Copyright (c) 2009      Jannis Pohlmann <jannis@xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifndef __THUNAR_APPLICATION_H__
 #define __THUNAR_APPLICATION_H__
 
 #include <thunar/thunar-window.h>
+#include <thunar/thunar-thumbnail-cache.h>
 
 G_BEGIN_DECLS;
 
@@ -36,110 +38,112 @@ typedef struct _ThunarApplication      ThunarApplication;
 #define THUNAR_IS_APPLICATION_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_APPLICATION))
 #define THUNAR_APPLICATION_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_APPLICATION, ThunarApplicationClass))
 
-GType              thunar_application_get_type                   (void) G_GNUC_CONST;
-
-ThunarApplication *thunar_application_get                        (void);
-
-gboolean           thunar_application_get_daemon                 (ThunarApplication *application);
-void               thunar_application_set_daemon                 (ThunarApplication *application,
-                                                                  gboolean           daemon);
-
-GList             *thunar_application_get_windows                (ThunarApplication *application);
-
-gboolean           thunar_application_has_windows                (ThunarApplication *application);
-
-void               thunar_application_take_window                (ThunarApplication *application,
-                                                                  GtkWindow         *window);
-
-GtkWidget         *thunar_application_open_window                (ThunarApplication *application,
-                                                                  ThunarFile        *directory,
-                                                                  GdkScreen         *screen,
-                                                                  const gchar       *startup_id);
-
-gboolean           thunar_application_bulk_rename                (ThunarApplication *application,
-                                                                  const gchar       *working_directory,
-                                                                  gchar            **filenames,
-                                                                  gboolean           standalone,
-                                                                  GdkScreen         *screen,
-                                                                  const gchar       *startup_id,
-                                                                  GError           **error);
-
-GtkWidget         *thunar_application_get_progress_dialog        (ThunarApplication *application);
-
-gboolean           thunar_application_process_filenames          (ThunarApplication *application,
-                                                                  const gchar       *working_directory,
-                                                                  gchar            **filenames,
-                                                                  GdkScreen         *screen,
-                                                                  const gchar       *startup_id,
-                                                                  GError           **error);
-
-gboolean           thunar_application_is_processing              (ThunarApplication *application);
-
-void               thunar_application_rename_file                (ThunarApplication *application,
-                                                                  ThunarFile        *file,
-                                                                  GdkScreen         *screen,
-                                                                  const gchar       *startup_id);
-void               thunar_application_create_file                (ThunarApplication *application,
-                                                                  ThunarFile        *parent_directory,
-                                                                  const gchar       *content_type,
-                                                                  GdkScreen         *screen,
-                                                                  const gchar       *startup_id);
-void               thunar_application_create_file_from_template (ThunarApplication *application,
-                                                                 ThunarFile        *parent_directory,
-                                                                 ThunarFile        *template_file,
-                                                                 GdkScreen         *screen,
-                                                                 const gchar       *startup_id);
-void               thunar_application_copy_to                   (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *source_file_list,
-                                                                 GList             *target_file_list,
-                                                                 GClosure          *new_files_closure);
-
-void               thunar_application_copy_into                 (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *source_file_list,
-                                                                 GFile             *target_file,
-                                                                 GClosure          *new_files_closure);
-
-void               thunar_application_link_into                 (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *source_file_list,
-                                                                 GFile             *target_file,
-                                                                 GClosure          *new_files_closure);
-
-void               thunar_application_move_into                 (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *source_file_list,
-                                                                 GFile             *target_file,
-                                                                 GClosure          *new_files_closure);
-
-void               thunar_application_unlink_files              (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *file_list,
-                                                                 gboolean           permanently);
-
-void               thunar_application_trash                     (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *file_list);
-
-void               thunar_application_creat                     (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *file_list,
-                                                                 GClosure          *new_files_closure);
-
-void               thunar_application_mkdir                     (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *file_list,
-                                                                 GClosure          *new_files_closure);
-
-void               thunar_application_empty_trash               (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 const gchar       *startup_id);
-
-void               thunar_application_restore_files             (ThunarApplication *application,
-                                                                 gpointer           parent,
-                                                                 GList             *trash_file_list,
-                                                                 GClosure          *new_files_closure);
+GType                 thunar_application_get_type                   (void) G_GNUC_CONST;
+
+ThunarApplication    *thunar_application_get                        (void);
+
+gboolean              thunar_application_get_daemon                 (ThunarApplication *application);
+void                  thunar_application_set_daemon                 (ThunarApplication *application,
+                                                                     gboolean           daemon);
+
+GList                *thunar_application_get_windows                (ThunarApplication *application);
+
+gboolean              thunar_application_has_windows                (ThunarApplication *application);
+
+void                  thunar_application_take_window                (ThunarApplication *application,
+                                                                     GtkWindow         *window);
+
+GtkWidget            *thunar_application_open_window                (ThunarApplication *application,
+                                                                     ThunarFile        *directory,
+                                                                     GdkScreen         *screen,
+                                                                     const gchar       *startup_id);
+
+gboolean              thunar_application_bulk_rename                (ThunarApplication *application,
+                                                                     const gchar       *working_directory,
+                                                                     gchar            **filenames,
+                                                                     gboolean           standalone,
+                                                                     GdkScreen         *screen,
+                                                                     const gchar       *startup_id,
+                                                                     GError           **error);
+
+GtkWidget            *thunar_application_get_progress_dialog        (ThunarApplication *application);
+
+gboolean              thunar_application_process_filenames          (ThunarApplication *application,
+                                                                     const gchar       *working_directory,
+                                                                     gchar            **filenames,
+                                                                     GdkScreen         *screen,
+                                                                     const gchar       *startup_id,
+                                                                     GError           **error);
+
+gboolean              thunar_application_is_processing              (ThunarApplication *application);
+
+void                  thunar_application_rename_file                (ThunarApplication *application,
+                                                                     ThunarFile        *file,
+                                                                     GdkScreen         *screen,
+                                                                     const gchar       *startup_id);
+void                  thunar_application_create_file                (ThunarApplication *application,
+                                                                     ThunarFile        *parent_directory,
+                                                                     const gchar       *content_type,
+                                                                     GdkScreen         *screen,
+                                                                     const gchar       *startup_id);
+void                  thunar_application_create_file_from_template (ThunarApplication *application,
+                                                                    ThunarFile        *parent_directory,
+                                                                    ThunarFile        *template_file,
+                                                                    GdkScreen         *screen,
+                                                                    const gchar       *startup_id);
+void                  thunar_application_copy_to                   (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *source_file_list,
+                                                                    GList             *target_file_list,
+                                                                    GClosure          *new_files_closure);
+
+void                  thunar_application_copy_into                 (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *source_file_list,
+                                                                    GFile             *target_file,
+                                                                    GClosure          *new_files_closure);
+
+void                  thunar_application_link_into                 (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *source_file_list,
+                                                                    GFile             *target_file,
+                                                                    GClosure          *new_files_closure);
+
+void                  thunar_application_move_into                 (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *source_file_list,
+                                                                    GFile             *target_file,
+                                                                    GClosure          *new_files_closure);
+
+void                  thunar_application_unlink_files              (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *file_list,
+                                                                    gboolean           permanently);
+
+void                  thunar_application_trash                     (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *file_list);
+
+void                  thunar_application_creat                     (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *file_list,
+                                                                    GClosure          *new_files_closure);
+
+void                  thunar_application_mkdir                     (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *file_list,
+                                                                    GClosure          *new_files_closure);
+
+void                  thunar_application_empty_trash               (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    const gchar       *startup_id);
+
+void                  thunar_application_restore_files             (ThunarApplication *application,
+                                                                    gpointer           parent,
+                                                                    GList             *trash_file_list,
+                                                                    GClosure          *new_files_closure);
+
+ThunarThumbnailCache *thunar_application_get_thumbnail_cache       (ThunarApplication *application);
 
 G_END_DECLS;
 
diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index 1281841dd5e7ee5f0f190c0eedcdaaf0c3d88abe..ebb10325b1e76a03930c6a8c857bf2112454cbaf 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -1254,11 +1254,13 @@ thunar_file_rename (ThunarFile   *file,
                     gboolean      called_from_job,
                     GError      **error)
 {
-  GKeyFile *key_file;
-  GError   *err = NULL;
-  GFile    *previous_file;
-  GFile    *renamed_file;
-  gint      watch_count;
+  ThunarApplication    *application;
+  ThunarThumbnailCache *thumbnail_cache;
+  GKeyFile             *key_file;
+  GError               *err = NULL;
+  GFile                *previous_file;
+  GFile                *renamed_file;
+  gint                  watch_count;
 
   _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
   _thunar_return_val_if_fail (g_utf8_validate (name, -1, NULL), FALSE);
@@ -1317,6 +1319,13 @@ thunar_file_rename (ThunarFile   *file,
       /* try to rename the file */
       renamed_file = g_file_set_display_name (file->gfile, name, cancellable, error);
 
+      /* notify the thumbnail cache that we can now also move the thumbnail */
+      application = thunar_application_get ();
+      thumbnail_cache = thunar_application_get_thumbnail_cache (application);
+      thunar_thumbnail_cache_move_file (thumbnail_cache, previous_file, renamed_file);
+      g_object_unref (thumbnail_cache);
+      g_object_unref (application);
+
       /* check if we succeeded */
       if (renamed_file != NULL)
         {
diff --git a/thunar/thunar-icon-factory.c b/thunar/thunar-icon-factory.c
index 576329a4f3bb61ec099f533ec5795404263ecaaf..4f2ec42ddf69d433c741b6b35f8b198fd53be40f 100644
--- a/thunar/thunar-icon-factory.c
+++ b/thunar/thunar-icon-factory.c
@@ -1,25 +1,22 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
  * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
- * Copyright (c) 2009-2010 Jannis Pohlmann <jannis@xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * The basic idea for the icon factory implementation was borrowed from
- * Nautilus initially, but the implementation is very different from
- * what Nautilus does.
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -38,7 +35,6 @@
 #include <thunar/thunar-preferences.h>
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-thumbnail-frame.h>
-#include <thunar/thunar-thumbnailer.h>
 
 
 
@@ -106,8 +102,6 @@ struct _ThunarIconFactory
 {
   GObject __parent__;
 
-  ThunarThumbnailer *thumbnailer;
-
   ThunarPreferences *preferences;
 
   GdkPixbuf         *recently[MAX_RECENTLY];  /* ring buffer */
@@ -209,9 +203,6 @@ thunar_icon_factory_init (ThunarIconFactory *factory)
 
   /* allocate the hash table for the icon cache */
   factory->icon_cache = g_hash_table_new_full (thunar_icon_key_hash, thunar_icon_key_equal, g_free, g_object_unref);
-
-  /* create a new thumbnailer */
-  factory->thumbnailer = thunar_thumbnailer_new ();
 }
 
 
@@ -250,9 +241,6 @@ thunar_icon_factory_finalize (GObject *object)
   /* clear the icon cache hash table */
   g_hash_table_destroy (factory->icon_cache);
 
-  /* 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);
 
@@ -804,7 +792,6 @@ thunar_icon_factory_load_file_icon (ThunarIconFactory  *factory,
                                     ThunarFileIconState icon_state,
                                     gint                icon_size)
 {
-  ThunarFileThumbState thumb_state;
   GInputStream        *stream;
   GtkIconInfo         *icon_info;
   const gchar         *thumbnail_path;
@@ -830,20 +817,6 @@ thunar_icon_factory_load_file_icon (ThunarIconFactory  *factory,
   /* 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)))
     {
-      /* this is how thumbnails for files are loaded: first, we check the thumbnail
-       * state. If that is unknown, we request a thumbnail to be generated in the
-       * background. At the same time we already try to load the thumbnail, in case
-       * it's already there. when the thumbnail is ready, we just load it */
-
-      /* determine the thumbnail state of the file */
-      thumb_state = thunar_file_get_thumb_state (file);
-
-      if (thumb_state == THUNAR_FILE_THUMB_STATE_UNKNOWN)
-        {
-          /* we don't know the state yet so request a new thumbnail in the background */
-          thunar_thumbnailer_queue_file (factory->thumbnailer, file);
-        }
-
       /* determine the preview icon first */
       gicon = thunar_file_get_preview_icon (file);
 
diff --git a/thunar/thunar-io-jobs.c b/thunar/thunar-io-jobs.c
index 898118aa45b790fb620c21ffdcbb912b6c3e86f6..859bdef5aba82010ad1f4318bc91555fa7c749b9 100644
--- a/thunar/thunar-io-jobs.c
+++ b/thunar/thunar-io-jobs.c
@@ -24,6 +24,7 @@
 
 #include <gio/gio.h>
 
+#include <thunar/thunar-application.h>
 #include <thunar/thunar-enum-types.h>
 #include <thunar/thunar-gio-extensions.h>
 #include <thunar/thunar-io-scan-directory.h>
@@ -32,6 +33,7 @@
 #include <thunar/thunar-job.h>
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-simple-job.h>
+#include <thunar/thunar-thumbnail-cache.h>
 #include <thunar/thunar-transfer-job.h>
 
 
@@ -367,13 +369,15 @@ _thunar_io_jobs_unlink (ThunarJob   *job,
                         GValueArray *param_values,
                         GError     **error)
 {
-  ThunarJobResponse response;
-  GFileInfo        *info;
-  GError           *err = NULL;
-  GList            *file_list;
-  GList            *lp;
-  gchar            *base_name;
-  gchar            *display_name;
+  ThunarThumbnailCache *thumbnail_cache;
+  ThunarApplication    *application;
+  ThunarJobResponse     response;
+  GFileInfo            *info;
+  GError               *err = NULL;
+  GList                *file_list;
+  GList                *lp;
+  gchar                *base_name;
+  gchar                *display_name;
 
   _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
   _thunar_return_val_if_fail (param_values != NULL, FALSE);
@@ -404,6 +408,11 @@ _thunar_io_jobs_unlink (ThunarJob   *job,
   /* we know the total list of files to process */
   thunar_job_set_total_files (THUNAR_JOB (job), file_list);
 
+  /* take a reference on the thumbnail cache */
+  application = thunar_application_get ();
+  thumbnail_cache = thunar_application_get_thumbnail_cache (application);
+  g_object_unref (application);
+
   /* remove all the files */
   for (lp = file_list; lp != NULL && !exo_job_is_cancelled (EXO_JOB (job)); lp = lp->next)
     {
@@ -415,7 +424,13 @@ _thunar_io_jobs_unlink (ThunarJob   *job,
 
 again:
       /* try to delete the file */
-      if (!g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
+      if (g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
+        {
+          /* notify the thumbnail cache that the corresponding thumbnail can also
+           * be deleted now */
+          thunar_thumbnail_cache_delete_file (thumbnail_cache, lp->data);
+        }
+      else
         {
           /* query the file info for the display name */
           info = g_file_query_info (lp->data, 
@@ -459,6 +474,9 @@ again:
         }
     }
 
+  /* release the thumbnail cache */
+  g_object_unref (thumbnail_cache);
+
   /* release the file list */
   thunar_g_file_list_free (file_list);
 
@@ -646,13 +664,15 @@ _thunar_io_jobs_link (ThunarJob   *job,
                       GValueArray *param_values,
                       GError     **error)
 {
-  GError *err = NULL;
-  GFile  *real_target_file;
-  GList  *new_files_list = NULL;
-  GList  *source_file_list;
-  GList  *sp;
-  GList  *target_file_list;
-  GList  *tp;
+  ThunarThumbnailCache *thumbnail_cache;
+  ThunarApplication    *application;
+  GError               *err = NULL;
+  GFile                *real_target_file;
+  GList                *new_files_list = NULL;
+  GList                *source_file_list;
+  GList                *sp;
+  GList                *target_file_list;
+  GList                *tp;
 
   _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
   _thunar_return_val_if_fail (param_values != NULL, FALSE);
@@ -665,6 +685,11 @@ _thunar_io_jobs_link (ThunarJob   *job,
   /* we know the total list of paths to process */
   thunar_job_set_total_files (THUNAR_JOB (job), source_file_list);
 
+  /* take a reference on the thumbnail cache */
+  application = thunar_application_get ();
+  thumbnail_cache = thunar_application_get_thumbnail_cache (application);
+  g_object_unref (application);
+
   /* process all files */
   for (sp = source_file_list, tp = target_file_list;
        err == NULL && sp != NULL && tp != NULL;
@@ -685,6 +710,12 @@ _thunar_io_jobs_link (ThunarJob   *job,
             {
               new_files_list = thunar_g_file_list_prepend (new_files_list, 
                                                            real_target_file);
+
+              /* notify the thumbnail cache that we need to copy the original
+               * thumbnail for the symlink to have one too */
+              thunar_thumbnail_cache_copy_file (thumbnail_cache, sp->data, 
+                                                real_target_file);
+
             }
   
           /* release the real target file */
@@ -692,6 +723,9 @@ _thunar_io_jobs_link (ThunarJob   *job,
         }
     }
 
+  /* release the thumbnail cache */
+  g_object_unref (thumbnail_cache);
+
   if (err != NULL)
     {
       thunar_g_file_list_free (new_files_list);
@@ -728,9 +762,11 @@ _thunar_io_jobs_trash (ThunarJob   *job,
                        GValueArray *param_values,
                        GError     **error)
 {
-  GError *err = NULL;
-  GList  *file_list;
-  GList  *lp;
+  ThunarThumbnailCache *thumbnail_cache;
+  ThunarApplication    *application;
+  GError               *err = NULL;
+  GList                *file_list;
+  GList                *lp;
 
   _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
   _thunar_return_val_if_fail (param_values != NULL, FALSE);
@@ -742,12 +778,25 @@ _thunar_io_jobs_trash (ThunarJob   *job,
   if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
     return FALSE;
 
+  /* take a reference on the thumbnail cache */
+  application = thunar_application_get ();
+  thumbnail_cache = thunar_application_get_thumbnail_cache (application);
+  g_object_unref (application);
+
   for (lp = file_list; err == NULL && lp != NULL; lp = lp->next)
     {
       _thunar_assert (G_IS_FILE (lp->data));
+
+      /* trash the file or folder */
       g_file_trash (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err);
+
+      /* update the thumbnail cache */
+      thunar_thumbnail_cache_cleanup_file (thumbnail_cache, lp->data);
     }
 
+  /* release the thumbnail cache */
+  g_object_unref (thumbnail_cache);
+
   if (err != NULL)
     {
       g_propagate_error (error, err);
diff --git a/thunar/thunar-properties-dialog.c b/thunar/thunar-properties-dialog.c
index 9e5a39da6ed8e4172bce3a060532f83d492dca0d..f52c20bd8f84a7c025ff04b39c1ab1f2a9370966 100644
--- a/thunar/thunar-properties-dialog.c
+++ b/thunar/thunar-properties-dialog.c
@@ -1,21 +1,22 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
  * Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org>
- * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -52,6 +53,7 @@
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-properties-dialog.h>
 #include <thunar/thunar-size-label.h>
+#include <thunar/thunar-thumbnailer.h>
 
 
 
@@ -115,6 +117,9 @@ struct _ThunarPropertiesDialog
 
   ThunarFile             *file;
 
+  ThunarThumbnailer      *thumbnailer;
+  guint                   thumbnail_request;
+
   GtkWidget              *notebook;
   GtkWidget              *icon_button;
   GtkWidget              *icon_image;
@@ -209,6 +214,10 @@ thunar_properties_dialog_init (ThunarPropertiesDialog *dialog)
   g_signal_connect_swapped (G_OBJECT (dialog->preferences), "notify::misc-date-style",
                             G_CALLBACK (thunar_properties_dialog_reload), dialog);
 
+  /* create a new thumbnailer */
+  dialog->thumbnailer = thunar_thumbnailer_new ();
+  dialog->thumbnail_request = 0;
+
   dialog->provider_factory = thunarx_provider_factory_get_default ();
 
   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
@@ -514,6 +523,16 @@ thunar_properties_dialog_finalize (GObject *object)
   g_signal_handlers_disconnect_by_func (dialog->preferences, thunar_properties_dialog_reload, dialog);
   g_object_unref (dialog->preferences);
 
+  /* cancel any pending thumbnailer requests */
+  if (dialog->thumbnail_request > 0)
+    {
+      thunar_thumbnailer_dequeue (dialog->thumbnailer, dialog->thumbnail_request);
+      dialog->thumbnail_request = 0;
+    }
+
+  /* release the thumbnailer */
+  g_object_unref (dialog->thumbnailer);
+
   /* release the provider property pages */
   g_list_foreach (dialog->provider_pages, (GFunc) g_object_unref, NULL);
   g_list_free (dialog->provider_pages);
@@ -813,6 +832,20 @@ thunar_properties_dialog_update (ThunarPropertiesDialog *dialog)
   _thunar_return_if_fail (THUNAR_IS_PROPERTIES_DIALOG (dialog));
   _thunar_return_if_fail (THUNAR_IS_FILE (dialog->file));
 
+  /* cancel any pending thumbnail requests */
+  if (dialog->thumbnail_request > 0)
+    {
+      thunar_thumbnailer_dequeue (dialog->thumbnailer, dialog->thumbnail_request);
+      dialog->thumbnail_request = 0;
+    }
+
+  if (dialog->file != NULL)
+    {
+      /* queue a new thumbnail request */
+      thunar_thumbnailer_queue_file (dialog->thumbnailer, dialog->file, 
+                                     &dialog->thumbnail_request);
+    }
+
   icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (dialog)));
   icon_factory = thunar_icon_factory_get_for_icon_theme (icon_theme);
 
diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c
index f671f05082519fa479fd53c6250b1233110a43aa..2478d7e87b050862acf9c18389e8eb21694e4beb 100644
--- a/thunar/thunar-standard-view.c
+++ b/thunar/thunar-standard-view.c
@@ -1,21 +1,22 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
  * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
- * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -49,6 +50,7 @@
 #include <thunar/thunar-standard-view-ui.h>
 #include <thunar/thunar-templates-action.h>
 #include <thunar/thunar-text-renderer.h>
+#include <thunar/thunar-thumbnailer.h>
 
 #if defined(GDK_WINDOWING_X11)
 #include <gdk/gdkx.h>
@@ -260,6 +262,14 @@ static gboolean             thunar_standard_view_drag_scroll_timer          (gpo
 static void                 thunar_standard_view_drag_scroll_timer_destroy  (gpointer                  user_data);
 static gboolean             thunar_standard_view_drag_timer                 (gpointer                  user_data);
 static void                 thunar_standard_view_drag_timer_destroy         (gpointer                  user_data);
+static void                 thunar_standard_view_cancel_thumbnailing        (ThunarStandardView       *standard_view);
+static void                 thunar_standard_view_schedule_thumbnail_timeout (ThunarStandardView       *standard_view);
+static void                 thunar_standard_view_schedule_thumbnail_idle    (ThunarStandardView       *standard_view);
+static gboolean             thunar_standard_view_request_thumbnails         (ThunarStandardView       *standard_view);
+static void                 thunar_standard_view_scrolled                   (GtkAdjustment            *adjustment,
+                                                                             ThunarStandardView       *standard_view);
+static void                 thunar_standard_view_size_allocate              (ThunarStandardView       *standard_view,
+                                                                             GtkAllocation            *allocation);
 
 
 
@@ -326,6 +336,12 @@ struct _ThunarStandardViewPrivate
   /* selected_files support */
   GList                  *selected_files;
 
+  /* support for generating thumbnails */
+  ThunarThumbnailer      *thumbnailer;
+  guint                   thumbnail_request;
+  guint                   thumbnail_source_id;
+  gboolean                thumbnailing_scheduled;
+
   /* Tree path for restoring the selection after selecting and 
    * deleting an item */
   GtkTreePath            *selection_before_delete;
@@ -531,6 +547,10 @@ thunar_standard_view_init (ThunarStandardView *standard_view)
   /* grab a reference on the provider factory */
   standard_view->priv->provider_factory = thunarx_provider_factory_get_default ();
 
+  /* create a thumbnailer */
+  standard_view->priv->thumbnailer = thunar_thumbnailer_new ();
+  standard_view->priv->thumbnailing_scheduled = FALSE;
+
   /* initialize the scrolled window */
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (standard_view),
                                   GTK_POLICY_AUTOMATIC,
@@ -596,6 +616,10 @@ thunar_standard_view_init (ThunarStandardView *standard_view)
    * files in our model changes.
    */
   g_signal_connect_swapped (G_OBJECT (standard_view->model), "notify::num-files", G_CALLBACK (thunar_standard_view_update_statusbar_text), standard_view);
+
+  /* connect to size allocation signals for generating thumbnail requests */
+  g_signal_connect_after (G_OBJECT (standard_view), "size-allocate", 
+                          G_CALLBACK (thunar_standard_view_size_allocate), NULL);
 }
 
 
@@ -607,6 +631,7 @@ thunar_standard_view_constructor (GType                  type,
 {
   ThunarStandardView *standard_view;
   ThunarZoomLevel     zoom_level;
+  GtkAdjustment      *adjustment;
   ThunarColumn        sort_column;
   GtkSortType         sort_order;
   GtkWidget          *view;
@@ -667,6 +692,14 @@ thunar_standard_view_constructor (GType                  type,
   g_signal_connect (G_OBJECT (view), "drag-data-delete", G_CALLBACK (thunar_standard_view_drag_data_delete), object);
   g_signal_connect (G_OBJECT (view), "drag-end", G_CALLBACK (thunar_standard_view_drag_end), object);
 
+  /* connect to scroll events for generating thumbnail requests */
+  adjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (standard_view));
+  g_signal_connect (adjustment, "value-changed",
+                    G_CALLBACK (thunar_standard_view_scrolled), object);
+  adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (standard_view));
+  g_signal_connect (adjustment, "value-changed",
+                    G_CALLBACK (thunar_standard_view_scrolled), object);
+
   /* done, we have a working object */
   return object;
 }
@@ -678,6 +711,9 @@ thunar_standard_view_dispose (GObject *object)
 {
   ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (object);
 
+  /* cancel pending thumbnail sources and requests */
+  thunar_standard_view_cancel_thumbnailing (standard_view);
+
   /* unregister the "loading" binding */
   if (G_UNLIKELY (standard_view->loading_binding != NULL))
     exo_binding_unbind (standard_view->loading_binding);
@@ -709,6 +745,9 @@ thunar_standard_view_finalize (GObject *object)
   _thunar_assert (standard_view->ui_manager == NULL);
   _thunar_assert (standard_view->clipboard == NULL);
 
+  /* release the thumbnailer */
+  g_object_unref (standard_view->priv->thumbnailer);
+
   /* release the scroll_to_file reference (if any) */
   if (G_UNLIKELY (standard_view->priv->scroll_to_file != NULL))
     g_object_unref (G_OBJECT (standard_view->priv->scroll_to_file));
@@ -1128,6 +1167,9 @@ thunar_standard_view_set_current_directory (ThunarNavigator *navigator,
   _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
   _thunar_return_if_fail (current_directory == NULL || THUNAR_IS_FILE (current_directory));
 
+  /* cancel any pending thumbnail sources and requests */
+  thunar_standard_view_cancel_thumbnailing (standard_view);
+
   /* disconnect any previous "loading" binding */
   if (G_LIKELY (standard_view->loading_binding != NULL))
     exo_binding_unbind (standard_view->loading_binding);
@@ -1189,6 +1231,9 @@ thunar_standard_view_set_current_directory (ThunarNavigator *navigator,
   /* update the "Restore" action */
   gtk_action_set_visible (standard_view->priv->action_restore, trashed);
 
+  /* schedule a thumbnail timeout */
+  thunar_standard_view_schedule_thumbnail_timeout (standard_view);
+
   /* notify all listeners about the new/old current directory */
   g_object_notify (G_OBJECT (standard_view), "current-directory");
 }
@@ -1266,6 +1311,17 @@ thunar_standard_view_set_loading (ThunarStandardView *standard_view,
       thunar_file_list_free (selected_files);
     }
 
+  /* check if we're done loading and a thumbnail timeout or idle was requested */
+  if (!loading && standard_view->priv->thumbnailing_scheduled)
+    {
+      /* we've just finished loading. it will probably the user some time to
+       * understand the contents of the folder before he will start interacting
+       * with the view. so here we can safely schedule an idle function instead
+       * of a timeout */
+      thunar_standard_view_schedule_thumbnail_idle (standard_view);
+      standard_view->priv->thumbnailing_scheduled = FALSE;
+    }
+
   /* notify listeners */
   g_object_freeze_notify (G_OBJECT (standard_view));
   g_object_notify (G_OBJECT (standard_view), "loading");
@@ -3240,6 +3296,185 @@ thunar_standard_view_drag_timer_destroy (gpointer user_data)
 
 
 
+static void
+thunar_standard_view_cancel_thumbnailing (ThunarStandardView *standard_view)
+{
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+
+  /* check if we have a pending thumbnail timeout/idle handler */
+  if (standard_view->priv->thumbnail_source_id > 0)
+    {
+      /* cancel this handler */
+      g_source_remove (standard_view->priv->thumbnail_source_id);
+      standard_view->priv->thumbnail_source_id = 0;
+    }
+
+  /* check if we have a pending thumbnail request */
+  if (standard_view->priv->thumbnail_request > 0)
+    {
+      /* cancel the request */
+      thunar_thumbnailer_dequeue (standard_view->priv->thumbnailer,
+                                  standard_view->priv->thumbnail_request);
+      standard_view->priv->thumbnail_request = 0;
+    }
+}
+
+
+
+static void
+thunar_standard_view_schedule_thumbnail_timeout (ThunarStandardView *standard_view)
+{
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+  
+  /* delay creating the idle until the view has finished loading.
+   * this is done because we only can tell the visible range reliably after
+   * all items have been added and we've perhaps scrolled to the file remember
+   * the last time */
+  if (thunar_view_get_loading (THUNAR_VIEW (standard_view)))
+    {
+      standard_view->priv->thumbnailing_scheduled = TRUE;
+      return;
+    }
+
+  /* cancel any pending thumbnail sources and requests */
+  thunar_standard_view_cancel_thumbnailing (standard_view);
+
+  /* schedule the timeout handler */
+  standard_view->priv->thumbnail_source_id = 
+    g_timeout_add (175, (GSourceFunc) thunar_standard_view_request_thumbnails, 
+                   standard_view);
+}
+
+
+
+static void
+thunar_standard_view_schedule_thumbnail_idle (ThunarStandardView *standard_view)
+{
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+  
+  /* delay creating the idle until the view has finished loading.
+   * this is done because we only can tell the visible range reliably after
+   * all items have been added, layouting has finished and we've perhaps 
+   * scrolled to the file remembered the last time */
+  if (thunar_view_get_loading (THUNAR_VIEW (standard_view)))
+    {
+      standard_view->priv->thumbnailing_scheduled = TRUE;
+      return;
+    }
+
+  /* cancel any pending thumbnail sources or requests */
+  thunar_standard_view_cancel_thumbnailing (standard_view);
+
+  /* schedule the timeout or idle handler */
+  standard_view->priv->thumbnail_source_id = 
+    g_idle_add ((GSourceFunc) thunar_standard_view_request_thumbnails, standard_view);
+}
+
+
+
+static gboolean
+thunar_standard_view_request_thumbnails (ThunarStandardView *standard_view)
+{
+  GtkTreePath *start_path;
+  GtkTreePath *end_path;
+  GtkTreePath *path;
+  GtkTreeIter  iter;
+  ThunarFile  *file;
+  gboolean     valid_iter;
+  GList       *visible_files = NULL;
+
+  _thunar_return_val_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view), FALSE);
+
+  /* reschedule the source if we're still loading the folder */
+  if (thunar_view_get_loading (THUNAR_VIEW (standard_view)))
+    {
+      g_debug ("weird, this should never happen");
+      return TRUE;
+    }
+
+  /* compute visible item range */
+  if ((*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_visible_range) (standard_view,
+                                                                            &start_path,
+                                                                            &end_path))
+    {
+      /* iterate over the range to collect all files */
+      valid_iter = gtk_tree_model_get_iter (GTK_TREE_MODEL (standard_view->model),
+                                            &iter, start_path);
+
+      while (valid_iter)
+        {
+          /* prepend the file to the visible items list */
+          file = thunar_list_model_get_file (standard_view->model, &iter);
+          visible_files = g_list_prepend (visible_files, file);
+
+          /* check if we've reached the end of the visible range */
+          path = gtk_tree_model_get_path (GTK_TREE_MODEL (standard_view->model), &iter);
+          if (gtk_tree_path_compare (path, end_path) != 0)
+            {
+              /* try to compute the next visible item */
+              valid_iter = 
+                gtk_tree_model_iter_next (GTK_TREE_MODEL (standard_view->model), &iter);
+            }
+          else
+            {
+              /* we have reached the end, terminate the loop */
+              valid_iter = FALSE;
+            }
+
+          /* release the tree path */
+          gtk_tree_path_free (path);
+        }
+
+      /* queue a thumbnail request */
+      thunar_thumbnailer_queue_files (standard_view->priv->thumbnailer, visible_files,
+                                      &standard_view->priv->thumbnail_request);
+
+      /* release the file list */
+      g_list_foreach (visible_files, (GFunc) g_object_unref, NULL);
+      g_list_free (visible_files);
+
+      /* release the start and end path */
+      gtk_tree_path_free (start_path);
+      gtk_tree_path_free (end_path);
+    }
+
+  /* reset the timeout or idle handler ID */
+  standard_view->priv->thumbnail_source_id = 0;
+
+  return FALSE;
+}
+
+
+
+static void
+thunar_standard_view_scrolled (GtkAdjustment      *adjustment,
+                               ThunarStandardView *standard_view)
+{
+  _thunar_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+
+  /* ignore adjustment changes when the view is still loading */
+  if (thunar_view_get_loading (THUNAR_VIEW (standard_view)))
+    return;
+
+  /* reschedule a thumbnail request timeout */
+  thunar_standard_view_schedule_thumbnail_timeout (standard_view);
+}
+
+
+
+static void
+thunar_standard_view_size_allocate (ThunarStandardView *standard_view,
+                                    GtkAllocation      *allocation)
+{
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+
+  /* reschedule a thumbnail request timeout */
+  thunar_standard_view_schedule_thumbnail_timeout (standard_view);
+}
+
+
+
 /**
  * thunar_standard_view_context_menu:
  * @standard_view : a #ThunarStandardView instance.
diff --git a/thunar/thunar-thumbnail-cache-dbus.xml b/thunar/thunar-thumbnail-cache-dbus.xml
new file mode 100644
index 0000000000000000000000000000000000000000..92ffa422949cc21390ef32bbb4795e7356ccaf91
--- /dev/null
+++ b/thunar/thunar-thumbnail-cache-dbus.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/org/freedesktop/thumbnails/Cache1">
+  <interface name="org.freedesktop.thumbnails.Cache1">
+    <method name="Move">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="as" name="from_uris" direction="in" />
+      <arg type="as" name="to_uris" direction="in" />
+    </method>
+
+    <method name="Copy">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="as" name="from_uris" direction="in" />
+      <arg type="as" name="to_uris" direction="in" />
+    </method>
+
+    <method name="Delete">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="as" name="uris" direction="in" />
+    </method>
+
+    <method name="Cleanup">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="as" name="base_uris" direction="in" />
+      <arg type="u" name="since" direction="in" />
+    </method>
+  </interface>
+</node>
diff --git a/thunar/thunar-thumbnail-cache.c b/thunar/thunar-thumbnail-cache.c
new file mode 100644
index 0000000000000000000000000000000000000000..d1c482ecc443272eae0342ee1026b42d70e09e6b
--- /dev/null
+++ b/thunar/thunar-thumbnail-cache.c
@@ -0,0 +1,692 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2011 Jannis Pohlmann <jannis@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+
+#include <thunar/thunar-thumbnail-cache-proxy.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <thunar/thunar-private.h>
+#include <thunar/thunar-thumbnail-cache.h>
+
+
+
+static void thunar_thumbnail_cache_finalize (GObject *object);
+
+
+
+struct _ThunarThumbnailCacheClass
+{
+  GObjectClass __parent__;
+};
+
+struct _ThunarThumbnailCache
+{
+  GObject     __parent__;
+
+#ifdef HAVE_DBUS
+  DBusGProxy *cache_proxy;
+  
+  GList      *move_source_queue;
+  GList      *move_target_queue;
+  guint       move_queue_idle_id;
+
+  GList      *copy_source_queue;
+  GList      *copy_target_queue;
+  guint       copy_queue_idle_id;
+
+  GList      *delete_queue;
+  guint       delete_queue_idle_id;
+
+  GList      *cleanup_queue;
+  guint       cleanup_queue_idle_id;
+
+  GMutex     *lock;
+#endif
+};
+
+
+
+G_DEFINE_TYPE (ThunarThumbnailCache, thunar_thumbnail_cache, G_TYPE_OBJECT)
+
+
+
+static void
+thunar_thumbnail_cache_class_init (ThunarThumbnailCacheClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  /* Determine the parent type class */
+  thunar_thumbnail_cache_parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = thunar_thumbnail_cache_finalize; 
+}
+
+
+
+static void
+thunar_thumbnail_cache_init (ThunarThumbnailCache *cache)
+{
+#ifdef HAVE_DBUS
+  DBusGConnection *connection;
+
+  /* try to connect to D-Bus */
+  connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+  if (connection != NULL)
+    {
+      /* create a proxy for the thumbnail cache service */
+      cache->cache_proxy =
+        dbus_g_proxy_new_for_name (connection,
+                                   "org.freedesktop.thumbnails.Cache1",
+                                   "/org/freedesktop/thumbnails/Cache1",
+                                   "org.freedesktop.thumbnails.Cache1");
+
+      /* release the D-Bus connection */
+      dbus_g_connection_unref (connection);
+    }
+
+  /* create a new mutex for accessing the cache from different threads */
+  cache->lock = g_mutex_new ();
+#endif
+}
+
+
+
+static void
+thunar_thumbnail_cache_finalize (GObject *object)
+{
+#ifdef HAVE_DBUS
+  ThunarThumbnailCache *cache = THUNAR_THUMBNAIL_CACHE (object);
+
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+
+  /* drop the move queue idle and all queued files */
+  if (cache->move_queue_idle_id > 0)
+    g_source_remove (cache->move_queue_idle_id);
+  g_list_foreach (cache->move_source_queue, (GFunc) g_object_unref, NULL);
+  g_list_foreach (cache->move_target_queue, (GFunc) g_object_unref, NULL);
+  g_list_free (cache->move_source_queue);
+  g_list_free (cache->move_target_queue);
+
+  /* drop the copy queue idle and all queued files */
+  if (cache->copy_queue_idle_id > 0)
+    g_source_remove (cache->copy_queue_idle_id);
+  g_list_foreach (cache->copy_source_queue, (GFunc) g_object_unref, NULL);
+  g_list_foreach (cache->copy_target_queue, (GFunc) g_object_unref, NULL);
+  g_list_free (cache->copy_source_queue);
+  g_list_free (cache->copy_target_queue);
+
+  /* drop the delete queue idle and all queued files */
+  if (cache->delete_queue_idle_id > 0)
+    g_source_remove (cache->delete_queue_idle_id);
+  g_list_foreach (cache->delete_queue, (GFunc) g_object_unref, NULL);
+  g_list_free (cache->delete_queue);
+
+  /* drop the cleanup queue idle and all queued files */
+  if (cache->cleanup_queue_idle_id > 0)
+    g_source_remove (cache->cleanup_queue_idle_id);
+  g_list_foreach (cache->cleanup_queue, (GFunc) g_object_unref, NULL);
+  g_list_free (cache->cleanup_queue);
+
+  /* check if we have a valid cache proxy */
+  if (cache->cache_proxy != NULL)
+    {
+      /* release the cache proxy itself */
+      g_object_unref (cache->cache_proxy);
+    }
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+
+  /* release the mutex itself */
+  g_mutex_free (cache->lock);
+#endif
+
+  (*G_OBJECT_CLASS (thunar_thumbnail_cache_parent_class)->finalize) (object);
+}
+
+
+
+#ifdef HAVE_DBUS
+static void
+thunar_thumbnail_cache_move_async_reply (DBusGProxy *proxy,
+                                         GError     *error,
+                                         gpointer    user_data)
+{
+  _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
+}
+
+
+
+static void
+thunar_thumbnail_cache_move_async (ThunarThumbnailCache *cache,
+                                   const gchar         **source_uris,
+                                   const gchar         **target_uris)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (source_uris != NULL);
+  _thunar_return_if_fail (target_uris != NULL);
+
+  /* request a thumbnail cache update asynchronously */
+  thunar_thumbnail_cache_proxy_move_async (cache->cache_proxy,
+                                           source_uris, target_uris,
+                                           thunar_thumbnail_cache_move_async_reply,
+                                           NULL);
+}
+
+
+
+static void
+thunar_thumbnail_cache_copy_async_reply (DBusGProxy *proxy,
+                                         GError     *error,
+                                         gpointer    user_data)
+{
+  _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
+}
+
+
+
+static void
+thunar_thumbnail_cache_copy_async (ThunarThumbnailCache *cache,
+                                   const gchar         **source_uris,
+                                   const gchar         **target_uris)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (source_uris != NULL);
+  _thunar_return_if_fail (target_uris != NULL);
+
+  /* request a thumbnail cache update asynchronously */
+  thunar_thumbnail_cache_proxy_copy_async (cache->cache_proxy,
+                                           source_uris, target_uris,
+                                           thunar_thumbnail_cache_copy_async_reply,
+                                           NULL);
+}
+
+
+
+static void
+thunar_thumbnail_cache_delete_async_reply (DBusGProxy *proxy,
+                                           GError     *error,
+                                           gpointer    user_data)
+{
+  _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
+}
+
+
+
+static void
+thunar_thumbnail_cache_delete_async (ThunarThumbnailCache *cache,
+                                     const gchar         **uris)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (uris != NULL);
+
+  /* request a thumbnail cache update asynchronously */
+  thunar_thumbnail_cache_proxy_delete_async (cache->cache_proxy, uris,
+                                             thunar_thumbnail_cache_delete_async_reply,
+                                             NULL);
+}
+
+
+
+static void
+thunar_thumbnail_cache_cleanup_async_reply (DBusGProxy *proxy,
+                                            GError     *error,
+                                            gpointer    user_data)
+{
+  _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
+}
+
+
+
+static void
+thunar_thumbnail_cache_cleanup_async (ThunarThumbnailCache *cache,
+                                      const gchar *const    *base_uris)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (base_uris != NULL);
+
+  /* request a thumbnail cache update asynchronously */
+  thunar_thumbnail_cache_proxy_cleanup_async (cache->cache_proxy, 
+                                              (const gchar **)base_uris, 0,
+                                              thunar_thumbnail_cache_cleanup_async_reply,
+                                              NULL);
+}
+
+
+
+static gboolean
+thunar_thumbnail_cache_process_move_queue (ThunarThumbnailCache *cache)
+{
+  GList  *sp;
+  GList  *tp;
+  gchar **source_uris;
+  gchar **target_uris;
+  guint   n_uris;
+  guint   n;
+
+  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache), FALSE);
+
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+  
+  /* compute how many URIs there are */
+  n_uris = g_list_length (cache->move_source_queue);
+
+  /* allocate a string array for the URIs */
+  source_uris = g_new0 (gchar *, n_uris + 1);
+  target_uris = g_new0 (gchar *, n_uris + 1);
+
+  /* fill URI array with file URIs from the move queue */
+  for (n = 0,
+       sp = g_list_last (cache->move_source_queue), 
+       tp = g_list_last (cache->move_target_queue);
+       sp != NULL && tp != NULL; 
+       sp = sp->prev, tp = tp->prev, ++n)
+    {
+      source_uris[n] = g_file_get_uri (sp->data);
+      target_uris[n] = g_file_get_uri (tp->data);
+
+      /* release the file objects */
+      g_object_unref (sp->data);
+      g_object_unref (tp->data);
+    }
+
+  /* NULL-terminate the URI arrays */
+  source_uris[n] = NULL;
+  target_uris[n] = NULL;
+
+  /* asynchronously move the thumbnails */
+  thunar_thumbnail_cache_move_async (cache, 
+                                     (const gchar **)source_uris,
+                                     (const gchar **)target_uris);
+
+  /* free the URI arrays */
+  g_free (source_uris);
+  g_free (target_uris);
+
+  /* release the move queue lists */
+  g_list_free (cache->move_source_queue);
+  g_list_free (cache->move_target_queue);
+  cache->move_source_queue = NULL;
+  cache->move_target_queue = NULL;
+
+  /* reset the move queue idle ID */
+  cache->move_queue_idle_id = 0;
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_thumbnail_cache_process_copy_queue (ThunarThumbnailCache *cache)
+{
+  GList  *sp;
+  GList  *tp;
+  gchar **source_uris;
+  gchar **target_uris;
+  guint   n_uris;
+  guint   n;
+
+  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache), FALSE);
+
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+  
+  /* compute how many URIs there are */
+  n_uris = g_list_length (cache->copy_source_queue);
+
+  /* allocate a string array for the URIs */
+  source_uris = g_new0 (gchar *, n_uris + 1);
+  target_uris = g_new0 (gchar *, n_uris + 1);
+
+  /* fill URI array with file URIs from the copy queue */
+  for (n = 0,
+       sp = g_list_last (cache->copy_source_queue), 
+       tp = g_list_last (cache->copy_target_queue);
+       sp != NULL && tp != NULL; 
+       sp = sp->prev, tp = tp->prev, ++n)
+    {
+      source_uris[n] = g_file_get_uri (sp->data);
+      target_uris[n] = g_file_get_uri (tp->data);
+
+      /* release the file objects */
+      g_object_unref (sp->data);
+      g_object_unref (tp->data);
+    }
+
+  /* NULL-terminate the URI arrays */
+  source_uris[n] = NULL;
+  target_uris[n] = NULL;
+
+  /* asynchronously copy the thumbnails */
+  thunar_thumbnail_cache_copy_async (cache, 
+                                     (const gchar **)source_uris,
+                                     (const gchar **)target_uris);
+
+  /* free the URI arrays */
+  g_free (source_uris);
+  g_free (target_uris);
+
+  /* release the copy queue lists */
+  g_list_free (cache->copy_source_queue);
+  g_list_free (cache->copy_target_queue);
+  cache->copy_source_queue = NULL;
+  cache->copy_target_queue = NULL;
+
+  /* reset the copy queue idle ID */
+  cache->copy_queue_idle_id = 0;
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_thumbnail_cache_process_delete_queue (ThunarThumbnailCache *cache)
+{
+  GList  *lp;
+  gchar **uris;
+  guint   n_uris;
+  guint   n;
+
+  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache), FALSE);
+
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+  
+  /* compute how many URIs there are */
+  n_uris = g_list_length (cache->delete_queue);
+
+  /* allocate a string array for the URIs */
+  uris = g_new0 (gchar *, n_uris + 1);
+
+  /* fill URI array with file URIs from the delete queue */
+  for (lp = g_list_last (cache->delete_queue), n = 0; lp != NULL; lp = lp->prev, ++n)
+    {
+      uris[n] = g_file_get_uri (lp->data);
+
+      /* release the file object */
+      g_object_unref (lp->data);
+    }
+
+  /* NULL-terminate the URI array */
+  uris[n] = NULL;
+
+  /* asynchronously delete the thumbnails */
+  thunar_thumbnail_cache_delete_async (cache, (const gchar **)uris);
+
+  /* free the URI array */
+  g_free (uris);
+
+  /* release the delete queue list */
+  g_list_free (cache->delete_queue);
+  cache->delete_queue = NULL;
+
+  /* reset the delete queue idle ID */
+  cache->delete_queue_idle_id = 0;
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_thumbnail_cache_process_cleanup_queue (ThunarThumbnailCache *cache)
+{
+  GList  *lp;
+  gchar **uris;
+  guint   n_uris;
+  guint   n;
+
+  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache), FALSE);
+
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+  
+  /* compute how many URIs there are */
+  n_uris = g_list_length (cache->cleanup_queue);
+
+  /* allocate a string array for the URIs */
+  uris = g_new0 (gchar *, n_uris + 1);
+
+  g_debug ("cleanup:");
+
+  /* fill URI array with file URIs from the cleanup queue */
+  for (lp = g_list_last (cache->cleanup_queue), n = 0; lp != NULL; lp = lp->prev, ++n)
+    {
+      uris[n] = g_file_get_uri (lp->data);
+
+      g_debug ("  %s", uris[n]);
+
+      /* release the file object */
+      g_object_unref (lp->data);
+    }
+
+  /* NULL-terminate the URI array */
+  uris[n] = NULL;
+
+  /* asynchronously cleanup the thumbnails */
+  thunar_thumbnail_cache_cleanup_async (cache, (const gchar *const *)uris);
+
+  /* free the URI array */
+  g_free (uris);
+
+  /* release the cleanup queue list */
+  g_list_free (cache->cleanup_queue);
+  cache->cleanup_queue = NULL;
+
+  /* reset the cleanup queue idle ID */
+  cache->cleanup_queue_idle_id = 0;
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+
+  return FALSE;
+}
+#endif /* HAVE_DBUS */
+
+
+
+ThunarThumbnailCache *
+thunar_thumbnail_cache_new (void)
+{
+  return g_object_new (THUNAR_TYPE_THUMBNAIL_CACHE, NULL);
+}
+
+
+
+void
+thunar_thumbnail_cache_move_file (ThunarThumbnailCache *cache,
+                                  GFile                *source_file,
+                                  GFile                *target_file)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (G_IS_FILE (source_file));
+  _thunar_return_if_fail (G_IS_FILE (target_file));
+
+#ifdef HAVE_DBUS
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+
+  /* check if we have a valid proxy for the cache service */
+  if (cache->cache_proxy != NULL)
+    {
+      /* cancel any pending timeout to process the move queue */
+      if (cache->move_queue_idle_id > 0)
+        {
+          g_source_remove (cache->move_queue_idle_id);
+          cache->move_queue_idle_id = 0;
+        }
+
+      /* add the files to the move queue */
+      cache->move_source_queue = g_list_prepend (cache->move_source_queue, 
+                                                 g_object_ref (source_file));
+      cache->move_target_queue = g_list_prepend (cache->move_target_queue,
+                                                 g_object_ref (target_file));
+
+      /* process the move queue in a 250ms timeout */
+      cache->move_queue_idle_id =
+        g_timeout_add (250, (GSourceFunc) thunar_thumbnail_cache_process_move_queue,
+                       cache);
+    }
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+#endif
+}
+
+
+
+void
+thunar_thumbnail_cache_copy_file (ThunarThumbnailCache *cache,
+                                  GFile                *source_file,
+                                  GFile                *target_file)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (G_IS_FILE (source_file));
+  _thunar_return_if_fail (G_IS_FILE (target_file));
+
+#ifdef HAVE_DBUS
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+
+  /* check if we have a valid proxy for the cache service */
+  if (cache->cache_proxy != NULL)
+    {
+      /* cancel any pending timeout to process the copy queue */
+      if (cache->copy_queue_idle_id > 0)
+        {
+          g_source_remove (cache->copy_queue_idle_id);
+          cache->copy_queue_idle_id = 0;
+        }
+
+      /* add the files to the copy queues */
+      cache->copy_source_queue = g_list_prepend (cache->copy_source_queue, 
+                                                 g_object_ref (source_file));
+      cache->copy_target_queue = g_list_prepend (cache->copy_target_queue,
+                                                 g_object_ref (target_file));
+
+      /* process the copy queue in a 250ms timeout */
+      cache->copy_queue_idle_id =
+        g_timeout_add (500, (GSourceFunc) thunar_thumbnail_cache_process_copy_queue,
+                       cache);
+    }
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+#endif
+}
+
+
+
+void
+thunar_thumbnail_cache_delete_file (ThunarThumbnailCache *cache,
+                                    GFile                *file)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (G_IS_FILE (file));
+
+#ifdef HAVE_DBUS
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+
+  /* check if we have a valid proxy for the cache service */
+  if (cache->cache_proxy)
+    {
+      /* cancel any pending timeout to process the delete queue */
+      if (cache->delete_queue_idle_id > 0)
+        {
+          g_source_remove (cache->delete_queue_idle_id);
+          cache->delete_queue_idle_id = 0;
+        }
+
+      /* add the file to the delete queue */
+      cache->delete_queue = g_list_prepend (cache->delete_queue, g_object_ref (file));
+
+      /* process the delete queue in a 250ms timeout */
+      cache->delete_queue_idle_id = 
+        g_timeout_add (500, (GSourceFunc) thunar_thumbnail_cache_process_delete_queue, 
+                       cache);
+    }
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+#endif
+}
+
+
+
+void
+thunar_thumbnail_cache_cleanup_file (ThunarThumbnailCache *cache,
+                                     GFile                *file)
+{
+  _thunar_return_if_fail (THUNAR_IS_THUMBNAIL_CACHE (cache));
+  _thunar_return_if_fail (G_IS_FILE (file));
+
+#ifdef HAVE_DBUS
+  /* acquire a cache lock */
+  g_mutex_lock (cache->lock);
+
+  /* check if we have a valid proxy for the cache service */
+  if (cache->cache_proxy)
+    {
+      /* cancel any pending timeout to process the cleanup queue */
+      if (cache->cleanup_queue_idle_id > 0)
+        {
+          g_source_remove (cache->cleanup_queue_idle_id);
+          cache->cleanup_queue_idle_id = 0;
+        }
+
+      /* add the file to the cleanup queue */
+      cache->cleanup_queue = g_list_prepend (cache->cleanup_queue, g_object_ref (file));
+
+      /* process the cleanup queue in a 250ms timeout */
+      cache->cleanup_queue_idle_id =
+        g_timeout_add (1000, (GSourceFunc) thunar_thumbnail_cache_process_cleanup_queue,
+                       cache);
+    }
+
+  /* release the cache lock */
+  g_mutex_unlock (cache->lock);
+#endif
+}
diff --git a/thunar/thunar-thumbnail-cache.h b/thunar/thunar-thumbnail-cache.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc32fc8090fe0aedfa143f1b05908d6c9aef227a
--- /dev/null
+++ b/thunar/thunar-thumbnail-cache.h
@@ -0,0 +1,56 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2011 Jannis Pohlmann <jannis@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __THUNAR_THUMBNAIL_CACHE_H__
+#define __THUNAR_THUMBNAIL_CACHE_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define THUNAR_TYPE_THUMBNAIL_CACHE            (thunar_thumbnail_cache_get_type ())
+#define THUNAR_THUMBNAIL_CACHE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_THUMBNAIL_CACHE, ThunarThumbnailCache))
+#define THUNAR_THUMBNAIL_CACHE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_THUMBNAIL_CACHE, ThunarThumbnailCacheClass))
+#define THUNAR_IS_THUMBNAIL_CACHE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_THUMBNAIL_CACHE))
+#define THUNAR_IS_THUMBNAIL_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_THUMBNAIL_CACHE)
+#define THUNAR_THUMBNAIL_CACHE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_THUMBNAIL_CACHE, ThunarThumbnailCacheClass))
+
+typedef struct _ThunarThumbnailCachePrivate ThunarThumbnailCachePrivate;
+typedef struct _ThunarThumbnailCacheClass   ThunarThumbnailCacheClass;
+typedef struct _ThunarThumbnailCache        ThunarThumbnailCache;
+
+GType                 thunar_thumbnail_cache_get_type     (void) G_GNUC_CONST;
+
+ThunarThumbnailCache *thunar_thumbnail_cache_new          (void) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+
+void                  thunar_thumbnail_cache_move_file    (ThunarThumbnailCache *cache,
+                                                           GFile                *source_file,
+                                                           GFile                *target_file);
+void                  thunar_thumbnail_cache_copy_file    (ThunarThumbnailCache *cache,
+                                                           GFile                *source_file,
+                                                           GFile                *target_file);
+void                  thunar_thumbnail_cache_delete_file  (ThunarThumbnailCache *cache,
+                                                           GFile                *file);
+void                  thunar_thumbnail_cache_cleanup_file (ThunarThumbnailCache *cache,
+                                                           GFile                *file);
+
+G_END_DECLS
+
+#endif /* !__THUNAR_THUMBNAIL_CACHE_H__ */
diff --git a/thunar/thunar-thumbnailer-dbus.xml b/thunar/thunar-thumbnailer-dbus.xml
index e6b39f7397ce9ca988fbd026bf7f72f2f65ea9ab..d0d2ada0010ba6b2102dab8a1f61c773a61b94f8 100644
--- a/thunar/thunar-thumbnailer-dbus.xml
+++ b/thunar/thunar-thumbnailer-dbus.xml
@@ -11,7 +11,7 @@
       <arg type="u" name="handle" direction="out" />
     </method>
 
-    <method name="Unqueue">
+    <method name="Dequeue">
       <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
       <arg type="u" name="handle" direction="in" />
     </method>
diff --git a/thunar/thunar-thumbnailer.c b/thunar/thunar-thumbnailer.c
index 8146d29066289ace8349637ab01d23b599602f8e..32d6218a15d6b538cbd7fdd6206813a53efcb451 100644
--- a/thunar/thunar-thumbnailer.c
+++ b/thunar/thunar-thumbnailer.c
@@ -1,6 +1,6 @@
 /* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
- * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
  * This program is free software; you can redistribute it and/or 
  * modify it under the terms of the GNU General Public License as
@@ -47,58 +47,21 @@
  * Please note that all D-Bus calls are performed asynchronously. 
  *
  *
- * Queue
- * =====
- *
- * ThunarThumbnailer maintains a wait queue to group individual thumbnail requests.
- * The wait queue is processed at most every 100ms. This is done to reduce the
- * overall D-Bus noise when dealing with a lot of requests. The more thumbnails are 
- * requested in a 100ms time slot, the less D-Bus methods are sent.
- *
- * Let N be the number of requests made for individual files in a 100ms slot. 
- * Compared to sending out one requests per file (which generates 4*N D-Bus messages,
- * 1 Queue, 1 Started, 1 Ready/Error and 1 Finished for each of the N files), the wait 
- * queue technique only causes 3+N D-Bus messages to be sent (1 Queue, 1 Started, 
- * N Ready/Error and 1 Finished). This can be further improved on the service side
- * if the D-Bus thumbnailer groups Ready/Error messages (which of course has drawbacks
- * with regards to the overall thumbnailing responsiveness).
- *
- * Before a URI is added to the wait queue, it is checked whether it isn't already
- * 1) in the wait queue, 2) part of a pending or active request or 3) part of a
- * finished request which has an idle function pending.
- *
- * When a request call is finally sent out, an internal request ID is created and 
+ * When a request call is sent out, an internal request ID is created and 
  * associated with the corresponding DBusGProxyCall via the request_call_mapping hash 
- * table. It also remembers the URIs for the internal request ID in the 
- * request_uris_mapping hash table. 
+ * table. 
  *
  * The D-Bus reply handler then checks if there was an delivery error or
  * not. If the request method was sent successfully, the handle returned by the
  * D-Bus thumbnailer is associated bidirectionally with the internal request ID via 
- * the request_handle_mapping and handle_request_mappings. If the request could
- * not be sent at all, the URIs array is dropped from request_uris_mapping. In 
- * both cases, the association of the internal request ID with the DBusGProxyCall
- * is removed from request_call_mapping.
+ * the request_handle_mapping and handle_request_mappings. In both cases, the 
+ * association of the internal request ID with the DBusGProxyCall is removed from 
+ * request_call_mapping.
  *
- * These hash tables play a major role in the Started, Finished, Error and Ready
+ * These hash tables play a major role in the Finished, Error and Ready
  * signal handlers.
  *
  *
- * Started
- * =======
- *
- * When a Started signal is emitted by the D-Bus thumbnailer, ThunarThumbnailer
- * receives the handle and looks up the corresponding internal request ID. If
- * it exists (which it should), it schedules an idle function to handle the
- * signal in the application's main loop. 
- *
- * The idle function then looks up the URIs array for the request ID from the
- * request_uris_mapping. For each of these URIs the corresponding ThunarFile
- * is looked up from the file cache (which represents files currently being
- * used somewhere in the UI), and if the ThunarFile exists in the cache it's
- * thumb state is set to _LOADING (unless it's already marked as _READY).
- *
- *
  * Ready / Error
  * =============
  *
@@ -112,12 +75,12 @@
  *
  * The Finished signal handler looks up the internal request ID based on
  * the D-Bus thumbnailer handle. It then drops all corresponding information
- * from handle_request_mapping, request_handle_mapping and request_uris_mapping.
+ * from handle_request_mapping and request_handle_mapping.
  */
 
 
 
-#if HAVE_DBUS
+#ifdef HAVE_DBUS
 typedef enum
 {
   THUNAR_THUMBNAILER_IDLE_ERROR,
@@ -153,20 +116,13 @@ static void                   thunar_thumbnailer_thumbnailer_ready      (DBusGPr
                                                                          guint32                handle,
                                                                          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,
+static guint                  thunar_thumbnailer_queue_async            (ThunarThumbnailer     *thumbnailer,
                                                                          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);
-static ThunarThumbnailerItem *thunar_thumbnailer_item_new               (GFile                 *file,
-                                                                         const gchar           *mime_hint);
-static void                   thunar_thumbnailer_item_free              (gpointer               data);
 #endif
 
 
@@ -184,10 +140,6 @@ struct _ThunarThumbnailer
   /* proxies to communicate with D-Bus services */
   DBusGProxy *thumbnailer_proxy;
 
-  /* wait queue used to delay (and thereby group) thumbnail requests */
-  GList      *wait_queue;
-  guint       wait_queue_idle_id;
-
   /* hash table to map D-Bus service handles to ThunarThumbnailer requests */
   GHashTable *handle_request_mapping;
 
@@ -197,9 +149,6 @@ struct _ThunarThumbnailer
   /* 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 arrays of URI schemes and MIME types for which thumbnails 
@@ -208,7 +157,7 @@ struct _ThunarThumbnailer
   gchar     **supported_types;
 
   /* last ThunarThumbnailer request ID */
-  gpointer    last_request;
+  guint       last_request;
 
   /* IDs of idle functions */
   GList      *idles;
@@ -244,9 +193,6 @@ struct _ThunarThumbnailerItem
 
 
 
-#ifdef HAVE_DBUS
-static DBusGProxy *thunar_thumbnailer_proxy;
-#endif
 
 
 
@@ -274,9 +220,8 @@ thunar_thumbnailer_init (ThunarThumbnailer *thumbnailer)
   thumbnailer->lock = g_mutex_new ();
   thumbnailer->supported_schemes = NULL;
   thumbnailer->supported_types = NULL;
-  thumbnailer->last_request = GUINT_TO_POINTER (0);
+  thumbnailer->last_request = 0;
   thumbnailer->idles = NULL;
-  thumbnailer->wait_queue_idle_id = 0;
 
   /* try to connect to D-Bus */
   connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
@@ -294,9 +239,6 @@ thunar_thumbnailer_init (ThunarThumbnailer *thumbnailer)
         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 */
@@ -319,14 +261,6 @@ thunar_thumbnailer_finalize (GObject *object)
   /* acquire the thumbnailer lock */
   g_mutex_lock (thumbnailer->lock);
 
-  /* clear the request queue */
-  g_list_foreach (thumbnailer->wait_queue, (GFunc) thunar_thumbnailer_item_free, NULL);
-  g_list_free (thumbnailer->wait_queue);
-
-  /* remove the request queue processing idle handler */
-  if (thumbnailer->wait_queue_idle_id > 0)
-    g_source_remove (thumbnailer->wait_queue_idle_id);
-
   /* abort all pending idle functions */
   for (lp = thumbnailer->idles; lp != NULL; lp = lp->next)
     {
@@ -348,16 +282,15 @@ thunar_thumbnailer_finalize (GObject *object)
       g_hash_table_unref (thumbnailer->request_call_mapping);
 
 #if 0 
-      /* unqueue all pending requests */
+      /* dequeue 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));
+        thunar_thumbnailer_dequeue_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,
@@ -396,51 +329,37 @@ thunar_thumbnailer_init_thumbnailer_proxy (ThunarThumbnailer *thumbnailer,
       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.Thumbnailer1",
-                                   "/org/freedesktop/thumbnails/Thumbnailer1",
-                                   "org.freedesktop.thumbnails.Thumbnailer1");
-
-      /* 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);
-
-      thumbnailer->thumbnailer_proxy = thunar_thumbnailer_proxy;
-
-      /* TODO this should actually be VOID:UINT,BOXED,INT,STRING */
-      dbus_g_object_register_marshaller (_thunar_marshal_VOID__UINT_BOXED_UINT_STRING,
-                                         G_TYPE_NONE,
-                                         G_TYPE_UINT, 
-                                         G_TYPE_STRV, 
-                                         G_TYPE_UINT, 
-                                         G_TYPE_STRING,
-                                         G_TYPE_INVALID);
-
-      dbus_g_object_register_marshaller ((GClosureMarshal) _thunar_marshal_VOID__UINT_BOXED,
-                                         G_TYPE_NONE,
-                                         G_TYPE_UINT,
-                                         G_TYPE_STRV,
-                                         G_TYPE_INVALID);
-
-      dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Error", 
-                               G_TYPE_UINT, G_TYPE_STRV, G_TYPE_UINT, G_TYPE_STRING, 
-                               G_TYPE_INVALID);
-      dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Finished", 
-                               G_TYPE_UINT, G_TYPE_INVALID);
-      dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Ready", 
-                               G_TYPE_UINT, G_TYPE_STRV, G_TYPE_INVALID);
-      dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Started", 
-                               G_TYPE_UINT, G_TYPE_INVALID);
-    }
-  else
-    {
-      thumbnailer->thumbnailer_proxy = g_object_ref (thunar_thumbnailer_proxy);
-    }
+  /* create the thumbnailer proxy */
+  thumbnailer->thumbnailer_proxy = 
+    dbus_g_proxy_new_for_name (connection, 
+                               "org.freedesktop.thumbnails.Thumbnailer1",
+                               "/org/freedesktop/thumbnails/Thumbnailer1",
+                               "org.freedesktop.thumbnails.Thumbnailer1");
+
+  /* TODO this should actually be VOID:UINT,BOXED,INT,STRING */
+  dbus_g_object_register_marshaller (_thunar_marshal_VOID__UINT_BOXED_UINT_STRING,
+                                     G_TYPE_NONE,
+                                     G_TYPE_UINT, 
+                                     G_TYPE_STRV, 
+                                     G_TYPE_UINT, 
+                                     G_TYPE_STRING,
+                                     G_TYPE_INVALID);
+
+  dbus_g_object_register_marshaller ((GClosureMarshal) _thunar_marshal_VOID__UINT_BOXED,
+                                     G_TYPE_NONE,
+                                     G_TYPE_UINT,
+                                     G_TYPE_STRV,
+                                     G_TYPE_INVALID);
+
+  dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Error", 
+                           G_TYPE_UINT, G_TYPE_STRV, G_TYPE_UINT, G_TYPE_STRING, 
+                           G_TYPE_INVALID);
+  dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Finished", 
+                           G_TYPE_UINT, G_TYPE_INVALID);
+  dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Ready", 
+                           G_TYPE_UINT, G_TYPE_STRV, G_TYPE_INVALID);
+  dbus_g_proxy_add_signal (thumbnailer->thumbnailer_proxy, "Started", 
+                           G_TYPE_UINT, G_TYPE_INVALID);
 
   dbus_g_proxy_connect_signal (thumbnailer->thumbnailer_proxy, "Error",
                                G_CALLBACK (thunar_thumbnailer_thumbnailer_error), 
@@ -451,9 +370,6 @@ thunar_thumbnailer_init_thumbnailer_proxy (ThunarThumbnailer *thumbnailer,
   dbus_g_proxy_connect_signal (thumbnailer->thumbnailer_proxy, "Ready",
                                G_CALLBACK (thunar_thumbnailer_thumbnailer_ready), 
                                thumbnailer, NULL);
-  dbus_g_proxy_connect_signal (thumbnailer->thumbnailer_proxy, "Started", 
-                               G_CALLBACK (thunar_thumbnailer_thumbnailer_started), 
-                               thumbnailer, NULL);
 }
 
 
@@ -576,12 +492,11 @@ thunar_thumbnailer_thumbnailer_finished (DBusGProxy        *proxy,
                                  GUINT_TO_POINTER (handle));
 
   /* check if we have a request for this handle */
-  if (request != NULL)
+  if (GPOINTER_TO_UINT (request) > 0)
     {
       /* 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);
     }
 }
 
@@ -621,44 +536,6 @@ thunar_thumbnailer_thumbnailer_ready (DBusGProxy        *proxy,
 
 
 
-static void
-thunar_thumbnailer_thumbnailer_started (DBusGProxy        *proxy,
-                                        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));
-
-  /* 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 = g_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,
@@ -667,9 +544,6 @@ thunar_thumbnailer_queue_async_reply (DBusGProxy *proxy,
 {
   ThunarThumbnailerCall *call = user_data;
   ThunarThumbnailer     *thumbnailer = THUNAR_THUMBNAILER (call->thumbnailer);
-#ifndef NDEBUG
-  gchar                **uris;
-#endif
 
   _thunar_return_if_fail (DBUS_IS_G_PROXY (proxy));
   _thunar_return_if_fail (call != NULL);
@@ -677,20 +551,7 @@ thunar_thumbnailer_queue_async_reply (DBusGProxy *proxy,
 
   g_mutex_lock (thumbnailer->lock);
 
-  if (error != NULL)
-    {
-#ifndef NDEBUG
-      /* 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);
-#endif
-
-      /* the request is "finished", forget about its URIs */
-      g_hash_table_remove (thumbnailer->request_uris_mapping, call->request);
-    }
-  else
+  if (error == NULL)
     {
       /* remember that this request and D-Bus handle belong together */
       g_hash_table_insert (thumbnailer->request_handle_mapping,
@@ -709,7 +570,7 @@ thunar_thumbnailer_queue_async_reply (DBusGProxy *proxy,
 
 
 
-static gpointer
+static guint
 thunar_thumbnailer_queue_async (ThunarThumbnailer *thumbnailer,
                                 gchar            **uris,
                                 const gchar      **mime_hints)
@@ -725,23 +586,20 @@ thunar_thumbnailer_queue_async (ThunarThumbnailer *thumbnailer,
   _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 = 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);
+  thumbnailer->last_request = request_no;
 
-  /* use the new request ID for this request */
-  request = thumbnailer->last_request;
+  /* use the newly generated ID for this request */
+  request = GUINT_TO_POINTER (request_no);
 
   /* allocate a new call struct for the async D-Bus call */
   thumbnailer_call = g_slice_new0 (ThunarThumbnailerCall);
   thumbnailer_call->request = request;
   thumbnailer_call->thumbnailer = g_object_ref (thumbnailer);
 
-  /* remember the URIs for this request */
-  g_hash_table_insert (thumbnailer->request_uris_mapping, request, uris);
-
   /* queue thumbnails for the given URIs asynchronously */
   call = thunar_thumbnailer_proxy_queue_async (thumbnailer->thumbnailer_proxy,
                                                (const gchar **)uris, mime_hints, 
@@ -753,7 +611,7 @@ thunar_thumbnailer_queue_async (ThunarThumbnailer *thumbnailer,
   g_hash_table_insert (thumbnailer->request_call_mapping, request, call);
 
   /* return the request ID used for this request */
-  return request;
+  return request_no;
 }
 
 
@@ -836,224 +694,6 @@ thunar_thumbnailer_ready_idle (gpointer user_data)
 
 
 
-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 gboolean
-thunar_thumbnailer_file_is_in_wait_queue (ThunarThumbnailer *thumbnailer,
-                                          ThunarFile        *file)
-{
-  ThunarThumbnailerItem *item;
-  gboolean               in_wait_queue = FALSE;
-  GList                 *lp;
-
-  g_mutex_lock (thumbnailer->lock);
-
-  for (lp = thumbnailer->wait_queue; !in_wait_queue && lp != NULL; lp = lp->next)
-    {
-      item = lp->data;
-
-      if (g_file_equal (item->file, thunar_file_get_file (file)))
-        in_wait_queue = TRUE;
-    }
-
-  g_mutex_unlock (thumbnailer->lock);
-
-  return in_wait_queue;
-}
-
-
-
-static gboolean
-thunar_thumbnailer_process_wait_queue (ThunarThumbnailer *thumbnailer)
-{
-  ThunarThumbnailerItem *item;
-  gpointer               request;
-  GList                 *lp;
-  gchar                **mime_hints;
-  gchar                **uris;
-  guint                  n_items;
-  guint                  n;
-
-  _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
-
-  g_mutex_lock (thumbnailer->lock);
-
-  /* determine how many URIs are in the wait queue */
-  n_items = g_list_length (thumbnailer->wait_queue);
-
-  /* allocate arrays for URIs and mime hints */
-  uris = g_new0 (gchar *, n_items + 1);
-  mime_hints = g_new0 (gchar *, n_items + 1);
-
-  /* fill URI and MIME hint arrays with items from the wait queue */
-  for (lp = g_list_last (thumbnailer->wait_queue), n = 0; lp != NULL; lp = lp->prev, ++n)
-    {
-      /* fetch the next item from the queue */
-      item = lp->data;
-
-      /* save URI and MIME hint in the arrays */
-      uris[n] = g_file_get_uri (item->file);
-      mime_hints[n] = item->mime_hint;
-
-      /* destroy the GFile and the queue item. The MIME hints are free'd later */
-      g_object_unref (item->file);
-      g_slice_free (ThunarThumbnailerItem, item);
-    }
-
-  /* NULL-terminate both arrays */
-  uris[n] = NULL;
-  mime_hints[n] = NULL;
-
-  /* queue a thumbnail request for the URIs from the wait queue */
-  request = thunar_thumbnailer_queue_async (thumbnailer, uris, 
-                                            (const gchar **)mime_hints);
-
-  /* free mime hints array */
-  g_strfreev (mime_hints);
-
-  /* clear the wait queue */
-  g_list_free (thumbnailer->wait_queue);
-  thumbnailer->wait_queue = NULL;
-
-  /* reset the wait queue idle ID */
-  thumbnailer->wait_queue_idle_id = 0;
-
-  g_mutex_unlock (thumbnailer->lock);
-
-  return FALSE;
-}
-
-
-
-static gboolean
-thunar_thumbnailer_file_is_queued (ThunarThumbnailer *thumbnailer,
-                                   ThunarFile        *file)
-{
-  gboolean is_queued = FALSE;
-  GList   *values;
-  GList   *lp;
-  gchar  **uris;
-  gchar   *uri;
-  guint    n;
-
-  /* get a list with all URI arrays of already queued requests */
-  values = g_hash_table_get_values (thumbnailer->request_uris_mapping);
-
-  /* if we have none, the file cannot be queued ... or can it? ;) */
-  if (values == NULL)
-    return FALSE;
-
-  /* determine the URI for this file */
-  uri = thunar_file_dup_uri (file);
-
-  /* iterate over all URI arrays */
-  for (lp = values; !is_queued && lp != NULL; lp = lp->next)
-    {
-      uris = lp->data;
-
-      /* check if the file is included in the URI array of the current request */
-      for (n = 0; !is_queued && uris != NULL && uris[n] != NULL; ++n)
-        if (g_utf8_collate (uri, uris[n]) == 0)
-          is_queued = TRUE;
-    }
-
-  /* free the file URI */
-  g_free (uri);
-
-  /* free the URI array list */
-  g_list_free (values);
-
-  return is_queued;
-}
-
-
-
-static gboolean
-thunar_thumbnailer_file_is_ready (ThunarThumbnailer *thumbnailer,
-                                  ThunarFile        *file)
-{
-  ThunarThumbnailerIdle *idle;
-  gboolean               is_ready = FALSE;
-  GList                 *lp;
-  gchar                 *uri;
-  guint                  n;
-
-  /* determine the URI or this file */
-  uri = thunar_file_dup_uri (file);
-
-  /* iterate over all idle structs */
-  for (lp = thumbnailer->idles; !is_ready && lp != NULL; lp = lp->next)
-    {
-      /* skip invalid idles */
-      if (lp->data != NULL)
-        continue;
-
-      idle = lp->data;
-
-      /* skip non-ready idles and idles without any URIs */
-      if (idle->type != THUNAR_THUMBNAILER_IDLE_READY || idle->data.uris == NULL)
-        continue;
-
-      /* check if the file is included in this ready idle */
-      for (n = 0; !is_ready && idle->data.uris[n] != NULL; ++n)
-        if (g_utf8_collate (uri, idle->data.uris[n]) == 0)
-          is_ready = TRUE;
-    }
-
-  /* free the file URI */
-  g_free (uri);
-
-  return is_ready;
-}
-
-
-
 static void
 thunar_thumbnailer_call_free (ThunarThumbnailerCall *call)
 {
@@ -1088,35 +728,6 @@ thunar_thumbnailer_idle_free (gpointer data)
   /* free the struct */
   g_slice_free (ThunarThumbnailerIdle, idle);
 }
-
-
-
-static ThunarThumbnailerItem *
-thunar_thumbnailer_item_new (GFile       *file,
-                             const gchar *mime_hint)
-{
-  ThunarThumbnailerItem *item;
-
-  _thunar_return_val_if_fail (G_IS_FILE (file), NULL);
-  _thunar_return_val_if_fail (mime_hint != NULL && mime_hint != '\0', NULL);
-
-  item = g_slice_new0 (ThunarThumbnailerItem);
-  item->file = g_object_ref (file);
-  item->mime_hint = g_strdup (mime_hint);
-
-  return item;
-}
-
-
-static void
-thunar_thumbnailer_item_free (gpointer data)
-{
-  ThunarThumbnailerItem *item = data;
-
-  g_object_unref (item->file);
-  g_free (item->mime_hint);
-  g_slice_free (ThunarThumbnailerItem, item);
-}
 #endif /* HAVE_DBUS */
 
 
@@ -1142,7 +753,8 @@ thunar_thumbnailer_new (void)
 
 gboolean
 thunar_thumbnailer_queue_file (ThunarThumbnailer *thumbnailer,
-                               ThunarFile        *file)
+                               ThunarFile        *file,
+                               guint             *request)
 {
   GList files;
 
@@ -1155,22 +767,24 @@ thunar_thumbnailer_queue_file (ThunarThumbnailer *thumbnailer,
   files.prev = NULL;
 
   /* queue a thumbnail request for the file */
-  return thunar_thumbnailer_queue_files (thumbnailer, &files);
+  return thunar_thumbnailer_queue_files (thumbnailer, &files, request);
 }
 
 
 
 gboolean
 thunar_thumbnailer_queue_files (ThunarThumbnailer *thumbnailer,
-                                GList             *files)
+                                GList             *files,
+                                guint             *request)
 {
+  gboolean      success = FALSE;
 #ifdef HAVE_DBUS
-  ThunarThumbnailerItem *item;
-#endif
-  gboolean               success = FALSE;
-#ifdef HAVE_DBUS
-  GList                 *lp;
-  GList                 *supported_files = NULL;
+  const gchar **mime_hints;
+  gchar       **uris;
+  GList        *lp;
+  GList        *supported_files = NULL;
+  guint         n;
+  guint         n_items;
 #endif
 
   _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
@@ -1194,44 +808,49 @@ thunar_thumbnailer_queue_files (ThunarThumbnailer *thumbnailer,
    * about to be queued (wait queue), nor already queued, nor already 
    * processed (and awaiting to be refreshed) */
   for (lp = g_list_last (files); lp != NULL; lp = lp->prev)
-    if (thunar_thumbnailer_file_is_supported (thumbnailer, lp->data))
-      {
-        if (!thunar_thumbnailer_file_is_in_wait_queue (thumbnailer, lp->data)
-            && !thunar_thumbnailer_file_is_queued (thumbnailer, lp->data)
-            && !thunar_thumbnailer_file_is_ready (thumbnailer, lp->data))
-          {
-            supported_files = g_list_prepend (supported_files, lp->data);
-          }
-      }
+    {
+      if (thunar_thumbnailer_file_is_supported (thumbnailer, lp->data))
+        supported_files = g_list_prepend (supported_files, lp->data);
+    }
+
+  /* determine how many URIs are in the wait queue */
+  n_items = g_list_length (supported_files);
 
   /* check if we have any supported files */
-  if (supported_files != NULL)
+  if (n_items > 0)
     {
-      for (lp = supported_files; lp != NULL; lp = lp->next)
-        {
-          g_mutex_lock (thumbnailer->lock);
-
-          /* allocate a thumbnailer item for the wait queue */
-          item = thunar_thumbnailer_item_new (thunar_file_get_file (lp->data),
-                                              thunar_file_get_content_type (lp->data));
+      /* allocate arrays for URIs and mime hints */
+      uris = g_new0 (gchar *, n_items + 1);
+      mime_hints = g_new0 (const gchar *, n_items + 1);
 
-          /* add the item to the wait queue */
-          thumbnailer->wait_queue = g_list_prepend (thumbnailer->wait_queue, item);
+      /* fill URI and MIME hint arrays with items from the wait queue */
+      for (lp = g_list_last (supported_files), n = 0; lp != NULL; lp = lp->prev, ++n)
+        {
+          /* set the thumbnail state to loading */
+          thunar_file_set_thumb_state (lp->data, THUNAR_FILE_THUMB_STATE_LOADING);
 
-          g_mutex_unlock (thumbnailer->lock);
+          /* save URI and MIME hint in the arrays */
+          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;
+
       g_mutex_lock (thumbnailer->lock);
 
-      if (thumbnailer->wait_queue_idle_id == 0)
-        {
-          thumbnailer->wait_queue_idle_id = 
-            g_timeout_add (100, (GSourceFunc) thunar_thumbnailer_process_wait_queue, 
-                           thumbnailer);
-        }
+      /* queue a thumbnail request for the URIs from the wait queue */
+      if (request != NULL)
+        *request = thunar_thumbnailer_queue_async (thumbnailer, uris, mime_hints);
+      else
+        thunar_thumbnailer_queue_async (thumbnailer, uris, mime_hints);
 
       g_mutex_unlock (thumbnailer->lock);
-      
+
+      /* free mime hints array */
+      g_free (mime_hints);
+
       /* free the list of supported files */
       g_list_free (supported_files);
 
@@ -1244,35 +863,42 @@ thunar_thumbnailer_queue_files (ThunarThumbnailer *thumbnailer,
 }
 
 
-#if 0 
-static void
-thunar_thumbnailer_unqueue (ThunarThumbnailer *thumbnailer,
-                            gpointer           request)
+void
+thunar_thumbnailer_dequeue (ThunarThumbnailer *thumbnailer,
+                            guint              request)
 {
 #ifdef HAVE_DBUS
+  gpointer request_ptr;
   gpointer handle;
 #endif
 
   _thunar_return_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer));
 
 #ifdef HAVE_DBUS
+  /* convert the number to a pointer */
+  request_ptr = GUINT_TO_POINTER (request);
+
   /* acquire the thumbnailer lock */
   g_mutex_lock (thumbnailer->lock);
 
+  /* check if we have a valid thumbnailer proxy */
   if (thumbnailer->thumbnailer_proxy != NULL)
     {
-      handle = g_hash_table_lookup (thumbnailer->request_handle_mapping, request);
-
-      thunar_thumbnailer_proxy_unqueue (thumbnailer->thumbnailer_proxy, 
-                                        GPOINTER_TO_UINT (handle), NULL);
+      /* check if there is a pending tumbler request handle for this request */
+      handle = g_hash_table_lookup (thumbnailer->request_handle_mapping, request_ptr);
+      if (GPOINTER_TO_UINT (handle) > 0)
+        {
+          /* Dequeue the request */
+          thunar_thumbnailer_proxy_dequeue (thumbnailer->thumbnailer_proxy, 
+                                            GPOINTER_TO_UINT (handle), NULL);
 
-      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);
+          /* drop all the request information */
+          g_hash_table_remove (thumbnailer->handle_request_mapping, handle);
+          g_hash_table_remove (thumbnailer->request_handle_mapping, request_ptr);
+        }
     }
 
   /* release the thumbnailer lock */
   g_mutex_unlock (thumbnailer->lock);
 #endif
 }
-#endif
diff --git a/thunar/thunar-thumbnailer.h b/thunar/thunar-thumbnailer.h
index 83fa4ce6d2eed58e30a4e72377c1bc8939e37d5c..81caf8328ba31ed0df66e0d78e77f768d0b06cbd 100644
--- a/thunar/thunar-thumbnailer.h
+++ b/thunar/thunar-thumbnailer.h
@@ -1,20 +1,21 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
- * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifndef __THUNAR_THUMBNAILER_H__
@@ -22,7 +23,7 @@
 
 #include <thunar/thunar-file.h>
 
-G_BEGIN_DECLS;
+G_BEGIN_DECLS
 
 typedef struct _ThunarThumbnailerClass ThunarThumbnailerClass;
 typedef struct _ThunarThumbnailer      ThunarThumbnailer;
@@ -34,15 +35,19 @@ typedef struct _ThunarThumbnailer      ThunarThumbnailer;
 #define THUNAR_IS_THUMBNAILER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_THUMBNAILER))
 #define THUNAR_THUMBNAILER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_THUMBNAILER, ThunarThumbnailerClass))
 
-GType              thunar_thumbnailer_get_type          (void) G_GNUC_CONST;
+GType              thunar_thumbnailer_get_type        (void) G_GNUC_CONST;
 
-ThunarThumbnailer *thunar_thumbnailer_new               (void) G_GNUC_MALLOC;
+ThunarThumbnailer *thunar_thumbnailer_new             (void) G_GNUC_MALLOC;
 
-gboolean           thunar_thumbnailer_queue_file        (ThunarThumbnailer *generator,
-                                                         ThunarFile        *file);
-gboolean           thunar_thumbnailer_queue_files       (ThunarThumbnailer *generator,
-                                                         GList             *files);
+gboolean           thunar_thumbnailer_queue_file      (ThunarThumbnailer        *thumbnailer,
+                                                       ThunarFile               *file,
+                                                       guint                    *request);
+gboolean           thunar_thumbnailer_queue_files     (ThunarThumbnailer        *thumbnailer,
+                                                       GList                    *files,
+                                                       guint                    *request);
+void               thunar_thumbnailer_dequeue         (ThunarThumbnailer        *thumbnailer,
+                                                       guint                     request);
 
-G_END_DECLS;
+G_END_DECLS
 
 #endif /* !__THUNAR_THUMBNAILER_H__ */
diff --git a/thunar/thunar-transfer-job.c b/thunar/thunar-transfer-job.c
index 364bd4ec624c7bfa25901ec4a1e6e5554cb3a877..f77839f396f854f28aa3d8f9bc940f50739a3d2d 100644
--- a/thunar/thunar-transfer-job.c
+++ b/thunar/thunar-transfer-job.c
@@ -1,22 +1,22 @@
-/* vi:set sw=2 sts=2 ts=2 et ai: */
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
  * Copyright (c) 2005-2007 Benedikt Meurer <benny@xfce.org>
  * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
  *
- * This program is free software; you can redistribute it and/or modify 
- * it under the terms of the GNU General Public License as published by 
- * the Free Software Foundation; either version 2 of the License, or (at 
- * your option) any later version.
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of 
+ * the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty of 
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
- * General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License 
- * along with this program; if not, write to the Free Software 
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
- * MA  02111-1307  USA
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write to the Free 
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -25,11 +25,13 @@
 
 #include <gio/gio.h>
 
+#include <thunar/thunar-application.h>
 #include <thunar/thunar-gio-extensions.h>
 #include <thunar/thunar-io-scan-directory.h>
 #include <thunar/thunar-io-jobs-util.h>
 #include <thunar/thunar-job.h>
 #include <thunar/thunar-private.h>
+#include <thunar/thunar-thumbnail-cache.h>
 #include <thunar/thunar-transfer-job.h>
 
 
@@ -481,11 +483,13 @@ thunar_transfer_job_copy_node (ThunarTransferJob  *job,
                                GList             **target_file_list_return,
                                GError            **error)
 {
-  ThunarJobResponse response;
-  GFileInfo        *info;
-  GError           *err = NULL;
-  GFile            *real_target_file = NULL;
-  gchar            *base_name;
+  ThunarThumbnailCache *thumbnail_cache;
+  ThunarApplication    *application;
+  ThunarJobResponse     response;
+  GFileInfo            *info;
+  GError               *err = NULL;
+  GFile                *real_target_file = NULL;
+  gchar                *base_name;
 
   _thunar_return_if_fail (THUNAR_IS_TRANSFER_JOB (job));
   _thunar_return_if_fail (node != NULL && G_IS_FILE (node->source_file));
@@ -498,6 +502,11 @@ thunar_transfer_job_copy_node (ThunarTransferJob  *job,
    * wrt restoring files from the trash. Other transfer_nodes will be called with target_parent_file.
    */
 
+  /* take a reference on the thumbnail cache */
+  application = thunar_application_get ();
+  thumbnail_cache = thunar_application_get_thumbnail_cache (application);
+  g_object_unref (application);
+
   for (; err == NULL && node != NULL; node = node->next)
     {
       /* guess the target file for this node (unless already provided) */
@@ -536,6 +545,11 @@ retry_copy:
           /* node->source_file == real_target_file means to skip the file */
           if (G_LIKELY (node->source_file != real_target_file))
             {
+              /* notify the thumbnail cache of the copy operation */
+              thunar_thumbnail_cache_copy_file (thumbnail_cache, 
+                                                node->source_file, 
+                                                real_target_file);
+
               /* check if we have children to copy */
               if (node->children != NULL)
                 {
@@ -558,22 +572,37 @@ retry_copy:
 
               /* add the real target file to the return list */
               if (G_LIKELY (target_file_list_return != NULL))
-                *target_file_list_return = thunar_g_file_list_prepend (*target_file_list_return, real_target_file);
+                {
+                  *target_file_list_return = 
+                    thunar_g_file_list_prepend (*target_file_list_return, 
+                                                real_target_file);
+                }
 
 retry_remove:
               /* try to remove the source directory if we are on copy+remove fallback for move */
-              if (job->type == THUNAR_TRANSFER_JOB_MOVE && 
-                  !g_file_delete (node->source_file, exo_job_get_cancellable (EXO_JOB (job)), &err))
+              if (job->type == THUNAR_TRANSFER_JOB_MOVE)
                 {
-                  /* ask the user to retry */
-                  response = thunar_job_ask_skip (THUNAR_JOB (job), "%s", err->message);
+                  if (g_file_delete (node->source_file, 
+                                     exo_job_get_cancellable (EXO_JOB (job)), 
+                                     &err))
+                    {
+                      /* notify the thumbnail cache of the delete operation */
+                      thunar_thumbnail_cache_delete_file (thumbnail_cache, 
+                                                          node->source_file);
+                    }
+                  else
+                    {
+                      /* ask the user to retry */
+                      response = thunar_job_ask_skip (THUNAR_JOB (job), "%s", 
+                                                      err->message);
 
-                  /* reset the error */
-                  g_clear_error (&err);
+                      /* reset the error */
+                      g_clear_error (&err);
 
-                  /* check whether to retry */
-                  if (G_UNLIKELY (response == THUNAR_JOB_RESPONSE_RETRY))
-                    goto retry_remove;
+                      /* check whether to retry */
+                      if (G_UNLIKELY (response == THUNAR_JOB_RESPONSE_RETRY))
+                        goto retry_remove;
+                    }
                 }
             }
 
@@ -604,6 +633,9 @@ retry_remove:
       g_object_unref (info);
     }
 
+  /* release the thumbnail cache */
+  g_object_unref (thumbnail_cache);
+
   /* propagate error if we failed or the job was cancelled */
   if (G_UNLIKELY (err != NULL))
     g_propagate_error (error, err);
@@ -614,20 +646,22 @@ static gboolean
 thunar_transfer_job_execute (ExoJob  *job,
                              GError **error)
 {
-  ThunarTransferNode *node;
-  ThunarJobResponse   response;
-  ThunarTransferJob  *transfer_job = THUNAR_TRANSFER_JOB (job);
-  GFileInfo          *info;
-  gboolean            parent_exists;
-  GError             *err = NULL;
-  GList              *new_files_list = NULL;
-  GList              *snext;
-  GList              *sp;
-  GList              *tnext;
-  GList              *tp;
-  GFile              *target_parent;
-  gchar              *base_name;
-  gchar              *parent_display_name;
+  ThunarThumbnailCache *thumbnail_cache;
+  ThunarTransferNode   *node;
+  ThunarApplication    *application;
+  ThunarJobResponse     response;
+  ThunarTransferJob    *transfer_job = THUNAR_TRANSFER_JOB (job);
+  GFileInfo            *info;
+  gboolean              parent_exists;
+  GError               *err = NULL;
+  GList                *new_files_list = NULL;
+  GList                *snext;
+  GList                *sp;
+  GList                *tnext;
+  GList                *tp;
+  GFile                *target_parent;
+  gchar                *base_name;
+  gchar                *parent_display_name;
 
   _thunar_return_val_if_fail (THUNAR_IS_TRANSFER_JOB (job), FALSE);
   _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -637,6 +671,11 @@ thunar_transfer_job_execute (ExoJob  *job,
 
   exo_job_info_message (job, _("Collecting files..."));
 
+  /* take a reference on the thumbnail cache */
+  application = thunar_application_get ();
+  thumbnail_cache = thunar_application_get_thumbnail_cache (application);
+  g_object_unref (application);
+
   for (sp = transfer_job->source_node_list, tp = transfer_job->target_file_list;
        sp != NULL && tp != NULL && err == NULL;
        sp = snext, tp = tnext)
@@ -742,6 +781,11 @@ thunar_transfer_job_execute (ExoJob  *job,
                            exo_job_get_cancellable (job),
                            NULL, NULL, &err))
             {
+              /* notify the thumbnail cache of the move operation */
+              thunar_thumbnail_cache_move_file (thumbnail_cache, 
+                                                node->source_file, 
+                                                tp->data);
+
               /* add the target file to the new files list */
               new_files_list = thunar_g_file_list_prepend (new_files_list, tp->data);
 
@@ -779,6 +823,9 @@ thunar_transfer_job_execute (ExoJob  *job,
       g_object_unref (info);
     }
 
+  /* release the thumbnail cache */
+  g_object_unref (thumbnail_cache);
+
   /* continue if there were no errors yet */
   if (G_LIKELY (err == NULL))
     {