[Xfce4-commits] <thunar:master> Merge branch 'jannis/thumbnailer-improvements'

Jannis Pohlmann noreply at xfce.org
Mon Feb 14 14:12:03 CET 2011


Updating branch refs/heads/master
         to 6ebca95f7cd2b2de82057994c7b8239f7cc3b5fb (commit)
       from 26d6c13238f21f0967aa0ad4506e433934558c2e (commit)

commit 6ebca95f7cd2b2de82057994c7b8239f7cc3b5fb
Merge: 26d6c13 3415bea
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 14 14:09:15 2011 +0100

    Merge branch 'jannis/thumbnailer-improvements'

commit 3415bea8e7624012c4104791f0caf839b689636d
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Sun Feb 13 14:36:08 2011 +0100

    Call thunar_thumbnail_cache_cleanup_file() when trashing a file/folder.
    
    When trashing a directory we cannot call the Delete() method of the
    thumbnailer service as that would not delete thumbnails of its
    descendants. Using the base URI parameter of Cleanup() we can achieve
    this however.

commit 9beaffa4809e88a52bd84bb0d51180bfd47ed2a0
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Sun Feb 13 14:32:58 2011 +0100

    Add thunar_thumbnail_cache_cleanup_file(). Sync with thumbnailer spec.
    
    Also increase the timeouts for Copy() and Delete() D-Bus method calls to
    500ms to reduce the D-Bus traffic.

commit 5a20e93a0d2734e8cb200d29dcb0ca31560805d0
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Tue Feb 8 11:40:07 2011 +0100

    Fix build without D-Bus.

commit 216f3e9921557ddf2c763ac12d95ec085836cf14
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 22:24:55 2011 +0100

    Make the thumbnailing in ThunarStandardView a bit more responsive.
    
    Use a timeout of 175ms instead of 250ms.

commit d52a31fda15823809f23c42724ae43c39ecd20df
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 22:22:40 2011 +0100

    Improve the thumbnail cache support in transfer jobs a tiny bit.

commit 9317f1b660ac0e3753c5a6cc6341a1b59d609381
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 22:17:35 2011 +0100

    Add thumbnail cache update support to the link job.
    
    This does wonders when linking stuff from slow remote locations into
    your local system.

commit ee3d81ed900dfd3e23b374504f34cc264abb3d2f
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 21:54:58 2011 +0100

    Use Move(), Copy() and Delete() cache methods in transfer jobs.
    
    This probably has to be improved (at least Copy() sometimes causes weird
    icon view behavior when copying a lot of files to an open window).
    Move transfer jobs work fine.

commit 4f6e985763adc4c6dfed5153aaa5ec973f498f82
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 21:51:17 2011 +0100

    Call thunar_thumbnail_cache_delete_file() in the unlink job.
    
    This helps removing thumbnails from the on-disk cache that are no longer
    needed because the original file no longer exists. It does a pretty good
    job at that but there's more work to do to integrate Copy(), Move() and
    Delete() in all the jobs.

commit bdfbba792be55b094647fe06c739c5ac151b134f
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 21:49:22 2011 +0100

    Add thunar_thumbnail_cache_copy_file().
    
    This one also uses a queue and a timeout of 250ms to group Copy() D-Bus
    method calls.

commit 133d32f0fcc2c37f5c581d647ae5fd02014244f3
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 21:21:58 2011 +0100

    Add thunar_thumbnail_cache_delete_file(). Use queues for processing.
    
    We again use something like the wait queue in the old ThunarThumbnailer
    here for grouping Move() and Delete() calls. The same will be done for
    Copy(). It performs really well, moving 200 images from one folder to
    another only generates a single Move() request with all images. At least
    on my fast machine.
    
    The actual calls to thunar_thumbnail_cache_move_file() and
    thunar_thumbnail_cache_delete_file() in the transfer and I/O jobs still
    have to be added.

commit 57cee92472be55feb9cb3549725190dfc035c314
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 16:50:15 2011 +0100

    Make sure to reset the thumbnail timeout/idle handler ID.

commit d2dd3f68af0afaf4035a3ffbc7340d257703a003
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 16:34:47 2011 +0100

    Add a ThunarThumbnailCache to ThunarApplication, implement Move().
    
    With this tumblerd can just copy the thumbnail and adjust its meta data
    when a file is renamed. We thereby avoid regenerating thumbnails for
    files that are simply renamed but whose contents don't change at all.
    
    We probably need some extra code to check whether the file type has now
    changed or become incompatible with tumbler. In that case we will have
    to drop the thumbnail. But how often does this really happen?

commit 834e6455488ccfb505127ba175e5366e1c652691
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 15:12:29 2011 +0100

    Use a timeout/idle to request thumbnails in ThunarStandardView.
    
    This is the second part of redesigning how thumbnails are requested in
    Thunar. Each ThunarStandardView now has a ThunerThumbnailer object.
    On scroll and resize events and whenever a new directory has finished
    loading, ThunarStandardView now schedules a timeout or idle handler
    (depending on the situation) to request thumbnails for all visible items
    of the view.
    
    This timeout/idle handler is rescheduled whenever the user starts
    or continues scrolling or resizing. This avoids sending requests while
    the user is scrolling and its important to not have D-Bus interfere with
    the Thunar main loop. We now have a much more responsive thumbnailing
    and scrolling experience!
    
    Requests are also dropped by each view when a directory is closed/left.
    This means that we no longer generate thumbnails the user is not
    interested in any more.
    
    This commit also uses the proper D-Bus method for cancelling thumbnail
    requests (it's called "Dequeue", not "Unqueue").
    
    The properties dialog is updated to match changes in the
    ThunarThumbnailer API.

commit f19df728cf8798152b175dd61467ea1633663660
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Mon Feb 7 02:41:23 2011 +0100

    Refactor ThunarThumbnailer and implement unqueue.
    
    This commit also drops ThunarThumbnailer in ThunarIconFactory and adds
    it to ThunarPropertiesDialog. There will be one ThunarThumbnailer for
    each ThunarStandardView soon in order to bring back normal thumbnail
    generation.

 thunar/Makefile.am                     |   12 +
 thunar/thunar-application.c            |   43 ++-
 thunar/thunar-application.h            |  238 ++++++------
 thunar/thunar-file.c                   |   19 +-
 thunar/thunar-icon-factory.c           |   55 +--
 thunar/thunar-io-jobs.c                |   85 +++-
 thunar/thunar-properties-dialog.c      |   59 +++-
 thunar/thunar-standard-view.c          |  261 ++++++++++++-
 thunar/thunar-thumbnail-cache-dbus.xml |   27 ++
 thunar/thunar-thumbnail-cache.c        |  692 ++++++++++++++++++++++++++++++++
 thunar/thunar-thumbnail-cache.h        |   56 +++
 thunar/thunar-thumbnailer-dbus.xml     |    2 +-
 thunar/thunar-thumbnailer.c            |  606 ++++++----------------------
 thunar/thunar-thumbnailer.h            |   47 ++-
 thunar/thunar-transfer-job.c           |  131 ++++--
 15 files changed, 1559 insertions(+), 774 deletions(-)

diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 0b45ce9..b715fea 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 4490105..8a5744a 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 at xfce.org>
  * Copyright (c) 2005      Jeff Franks <jcfranks at xfce.org>
- * Copyright (c) 2009-2010 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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 cb42877..50845a3 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 at xfce.org>
  * Copyright (c) 2005      Jeff Franks <jcfranks at xfce.org>
- * Copyright (c) 2009      Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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 1281841..ebb1032 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 576329a..4f2ec42 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 at xfce.org>
- * Copyright (c) 2009-2010 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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 898118a..859bdef 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 9e5a39d..f52c20b 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 at xfce.org>
- * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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 f671f05..2478d7e 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 at xfce.org>
- * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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 0000000..92ffa42
--- /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 0000000..d1c482e
--- /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 at 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 0000000..dc32fc8
--- /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 at 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 e6b39f7..d0d2ada 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 8146d29..32d6218 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 at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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);
     }
 }
 
@@ -622,44 +537,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,
                                       GError     *error,
@@ -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 83fa4ce..81caf83 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 at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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 364bd4e..f77839f 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 at xfce.org>
  * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at 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))
     {



More information about the Xfce4-commits mailing list