[Xfce4-commits] <xfdesktop:master> Merge branch 'eric/bugzilla-patches'

Eric Koegel noreply at xfce.org
Mon Mar 5 19:30:26 CET 2012


Updating branch refs/heads/master
         to 22a94a56372747c16a5084291bfa05fb1a82ac8c (commit)
       from ec6d521940cf48a8732bfd09085d3b99891c6133 (commit)

commit 22a94a56372747c16a5084291bfa05fb1a82ac8c
Merge: ec6d521 2fac2c9
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Mon Mar 5 21:25:08 2012 +0300

    Merge branch 'eric/bugzilla-patches'

commit 2fac2c92ccb2fec0d6b64aa97c1f2315836d3ab1
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Fri Mar 2 15:00:36 2012 +0300

    Comments in .desktop files are displayed in the tooltip (bug 8509)

commit d3211fcb34491200bf60d1e38ace87f0ca8ee4c0
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sat Mar 3 18:08:45 2012 +0300

    Get correct workspace size with multimon display
    
    When multiple montiors are used and a Virtual desktop size is
    configured in Xorg, it will always return that size rather than
    the actual size displayed. This patch changes how the size is
    calculated so that icons stay in their location when the resolution
    reverts back.

commit a18cb32c970f2355cfa86bf6763e31efa93e1df5
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sat Mar 3 16:20:29 2012 +0300

    Fix xinerama_stretch not refreshing on all monitors

commit 1a13ea55d5d25479ec3b4e849505b32ee2193854
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Fri Mar 2 10:42:50 2012 +0300

    Change g_debug messages to DBG

commit bae29238768a138626db145600f424b80bb171ce
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sun Feb 26 16:54:15 2012 +0300

    Added the root menu popup when there are no icons shown on the desktop.

commit ada952534e6d740cf3a8309c6465d853d9c253ad
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sun Feb 26 15:49:11 2012 +0300

    Fix a segfault when tumbler isn't available.
    
    The patch was provided by Lionel Le Folgoc <lionel at lefolgoc.net>

commit 95a5f72c444ff26777831fdffcffe64015324c4c
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sun Feb 19 23:29:17 2012 +0300

    Require libexo & update min requirements in readme

commit bab7bc4b9af228f5e1b313ebd83f1cfd655dde10
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sat Feb 11 12:50:09 2012 +0300

    Single click option to open items on desktop
    
    This patch adds support to launch items from a single click based
    on an xfconf property /desktop-icons/single-click. Also adds a
    checkbox to xfdesktop-settings. Bug 1797.
    Code for changing the cursor to a "hand" when hovering over items
    was provided by Lionel Le Folgoc <lionel at lefolgoc.net>

commit ddc632474a7b4522fd84c5bbb599bf53103dbc07
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sat Feb 11 14:52:42 2012 +0300

    Arrange icons on the desktop
    
    This patch adds code to arrange the desktop icons. First,
    it sorts and adds all the special icons such as the trash, home
    folder, and any volumes. Next, it sorts and adds all the folder
    icons. Finally, it adds the regular file icons. It can be invoked
    by  a root menu option or via a command line --arrange so it can
    be used as a keyboard binding.
    The xfdesktop_icon_view_compare_icons function was written by
    Nick Schermer <nick at xfce.org>
    For bug 2833.

commit c72329f0c4efa0b8cb062cf55e06026b23e1ac0a
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Wed Feb 8 11:18:19 2012 +0300

    Always use gdk_screen_get_monitor_geometry
    
    Drop the single monitor code in  backdrop_changed_cb and instead
    use gdk_screen_get_monitor_geometry since a single montior can
    have an offset.

commit 9cf3b10cf57a6e5f9a07536ef6056ce321abbc90
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Thu Feb 9 16:48:12 2012 +0300

    Stretch background across all monitors setting
    
    Added a 'Stretch background across all monitors.' checkbox to the
    xfdesktop-settings app. It will only be visible on the first monitor tab and
    only when multiple monitors are present. Bug 5690

commit 0af2c17f9ff3f3a64da7bc3f07ce06cf6bb107fc
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Thu Jan 19 16:54:05 2012 +0300

    Unmounted volumes are semi-transparent.
    
    Added code so that when an volume is shown but not currently
    mounted it is a semi-transparent icon. Also added an internal
    helper function to check if a volume is mounted to avoid some code
    duplication. For bug 3963.

commit fc683b2be9893f61bc4ab7b9a8bcfb6a940fbd3a
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Wed Feb 8 09:14:13 2012 +0300

    Fix typos in the README file

commit dba89439ee41f3cc793b44d9dc3630e3238228db
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sun Feb 19 09:32:01 2012 +0300

    Fix for moving files instead of copy when src isn't writable
    
    Fixed a bug where a user drags and drops a file from a folder on the
    same filesystem as the desktop but the src isn't writable by the user
    so they can't delete the src file. The user will still see an error
    message if they explicitly try to move the file via the right click
    drag and drop menu.

commit 578732b85aee34d0d48b4c16ac9ef398b644a9fc
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sat Nov 19 13:38:56 2011 +0300

    Modified xfdesktop_icon_view_drag_drop to allow all selected files to drag and drop. Fixes Bug #5025

commit 600504bab2c3067515e225136afa765a6e93e6bb
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sun Feb 12 13:12:32 2012 +0300

    Backdrop image cycling on a timer
    
    This code adds the ability to change the backdrop image when it's
    set to an image-list and the backdrop-cycle-enable setting is TRUE.
    It will then change the background every backdrop-cycle-timer
    minutes. The settings app allows the user to change these settings.
    Bug 4850

commit 1264428edda474f7c59befee1b0d779bc385fc14
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sat Feb 11 21:22:26 2012 +0300

    Change to POINTER_MOTION_HINT_MASK & use gdk_event_request_motions

commit dc4f69b84425cc135c8a70ac04ea3e6ba318d02e
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Tue Feb 7 15:26:20 2012 +0300

    Icon positions are saved/restored per resolution
    
    Icon positions are now stored in seperate rc files per screen
    resolution so that when reverting from a lower screen resolution
    the icons aren't stuck at the upper-left. The old rc file is used
    as a fallback so that the migration is seemless. For bug 6149.

commit ab5aac37a7855b79c2bb1b2df686e938c477ff34
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Tue Feb 7 17:34:11 2012 +0300

    Fix for shift + drag selections
    
    Selecting icons during a shift drag action now works. Doing a
    right click or shift + left click without dragging the mouse will
    cause the root menu to popup. For bug 7525.

commit c5dccaa729d20dccb8ee220e06b31a41a79850da
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Fri Jan 20 22:24:28 2012 +0300

    Display correct trash icon on menu & desktop
    
    Added a check to see if the user can delete files in their trash
    before counting it against them. Also added code to load the
    correct trash icon based on the trash_item_count. Bug 6256.

commit 48e0ab66233c95a7f5a5890f580761fd8e40a275
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Sat Dec 17 10:37:04 2011 +0300

    Adds the code required to perform a paste on the on the desktop. Fixes bug 3804.

commit d5e4dbea733153b74caba0e7a9c2bccc2ea5bf9c
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Fri Feb 10 19:56:59 2012 +0300

    Thumbnail desktop icon previews using tumblerd
    
    Adds support for drawing thumbnails from the dbus thumbnail
    service. Adds a show-thumbnails xfconf property to toggle showing
    thumbnails. Moves the marshal.list into the common folder. Creates
    a checkbox option on the xfdesktop-settings app to toggle
    thumbnails. Adds a tooltip-size gtk style property to change the
    tooltip image size, ranges from 0 (not shown) to 512, with 128
    as the default. Added a timer when the icon size spinner changed
    value in the settings app to prevent the icons redrawing on every
    value change. Removed xfdesktop_icon_mark_extents_dirty so that
    size changes to the pixbuf are properly rendered. Bug 4344.

commit 803ea66061417317df2b2968a81a4cfdfd052e8d
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Mon Dec 5 14:44:59 2011 +0300

    Added a check for GDK_GRAB_INVALID_TIME in xfdesktop_popup_grab_available to mitigate slow menu popups on a right mouse click. Fixes bug 7172.

commit cf1ba8ecefacca369c4f83ece0b6d03b718fce06
Author: Eric Koegel <eric.koegel at gmail.com>
Date:   Mon Feb 6 08:45:06 2012 +0300

    Right-click Drag and Drop
    
    Drag and drop right-click to and from the desktop will cause a
    menu pop-up. Additionally, this patch also fixes the issue where
    files that were dropped onto the desktop were always copied by
    default instead of doing a move when they were on the same
    filesystem. They were combined because the move/copy bug requires
    code implemented in this right click drag and drop patch.

 README                                             |   30 +-
 common/Makefile.am                                 |   37 ++-
 common/xfdesktop-common.c                          |    5 +-
 common/xfdesktop-common.h                          |    1 +
 common/xfdesktop-marshal.list                      |    4 +
 common/xfdesktop-thumbnailer.c                     |  606 ++++++++++++++++++++
 common/xfdesktop-thumbnailer.h                     |   76 +++
 configure.ac.in                                    |    5 +-
 doc/README.xfconf                                  |    2 +
 settings/main.c                                    |  138 ++++-
 .../xfdesktop-settings-appearance-frame-ui.glade   |   64 ++
 settings/xfdesktop-settings-ui.glade               |   21 +
 src/Makefile.am                                    |   16 +-
 src/main.c                                         |   12 +-
 src/xfce-backdrop.c                                |  158 +++++-
 src/xfce-backdrop.h                                |   14 +
 src/xfce-desktop.c                                 |  140 ++++--
 src/xfce-desktop.h                                 |    2 +
 src/xfdesktop-clipboard-manager.c                  |  114 +++-
 src/xfdesktop-file-icon-manager.c                  |  386 ++++++++++++-
 src/xfdesktop-file-icon-manager.h                  |    9 +
 src/xfdesktop-file-utils.c                         |    2 -
 src/xfdesktop-icon-view.c                          |  429 ++++++++++++---
 src/xfdesktop-icon-view.h                          |   10 +
 src/xfdesktop-icon.c                               |   51 +-
 src/xfdesktop-icon.h                               |    7 +-
 src/xfdesktop-marshal.list                         |    2 -
 src/xfdesktop-regular-file-icon.c                  |  126 ++++-
 src/xfdesktop-special-file-icon.c                  |  135 +++--
 src/xfdesktop-volume-icon.c                        |   58 ++-
 30 files changed, 2382 insertions(+), 278 deletions(-)

diff --git a/README b/README
index e8aad4b..987d7b1 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-README for xfdesktop version 4.5
+README for xfdesktop
 ================================
 
 WHAT IS IT?
@@ -17,14 +17,16 @@ MINIMUM REQUIREMENTS
 ~~~~~~~~~~~~~~~~~~~~
 
 * intltool 0.34
-* GTK+ 2.10.0
-* libxfce4util 4.5.0svn-r26490
-* libxfcegui4 4.5.2svn-r27035
-* libwnck 2.12.0
-* libxfce4menu 0.1.0svn-r26507 (optional; required for apps menu)
-* libthunar-vfs 0.8.0  (optional; required for file icons)
+* GTK+ 2.14.0
+* libxfce4util 4.8
+* libxfce4ui 4.9
+* libwnck 2.22
+* libexo 0.6
+* xfconf 4.8
+* garcon 0.1.2 (optional; required for apps menu)
+* thunar 1.2 (optional; required for file icons)
 * dbus-glib 0.34  (optional; required for file icons)
-* libexo 0.3.2 (optional)
+* tumbler 1.6 (optional; enables thumbnail previews for file icons)
 
 
 HIDDEN CUSTOMISATIONS
@@ -40,7 +42,8 @@ You'd want to add something like this to your ~/.gtkrc-2.0 file:
 style "xfdesktop-icon-view" {
     XfdesktopIconView::label-alpha = 75
     XfdesktopIconView::selected-label-alpha = 100
-    XfdesktopIconVIew::ellipsize-icon-labels = 1
+    XfdesktopIconView::ellipsize-icon-labels = 1
+    XfdesktopIconView::tooltip-size = 128
 
     XfdesktopIconView::shadow-x-offset = 1
     XfdesktopIconView::shadow-y-offset = 1
@@ -49,7 +52,7 @@ style "xfdesktop-icon-view" {
     XfdesktopIconView::selected-shadow-y-offset = 2
     XfdesktopIconView::selected-shadow-color = "#00ff00"
 
-    XfdesktopIconVIew::cell-spacing = 6
+    XfdesktopIconView::cell-spacing = 6
     XfdesktopIconView::cell-padding = 6
     XfdesktopIconView::cell-text-width-proportion = 2.5
 
@@ -63,11 +66,14 @@ style "xfdesktop-icon-view" {
 }
 widget_class "*XfdesktopIconView*" style "xfdesktop-icon-view"
 
-The first three entries set the opacity of the rounded text background
+The first four entries set the opacity of the rounded text background
 (allowed values are from 0 (totally transparent) to 255 (totally opaque),
 and whether or not unselected icons get their labels ellipsized
 (truncated) to fit on one line.  (The 'selected-' version controls the
-opacity of icons that have been selected with the mouse.)
+opacity of icons that have been selected with the mouse.) The tooltip-size
+determines how large the image preview will be when the mouse is hovered
+over an icon (allowed values are from 0 (not shown) to 512, values larger
+than 256 may cause poor image quality however.)
 
 The second six entries can be used to enable a text shadow to be painted
 with the icon labels.  The offsets are in pixels.  Setting them to 0 (the
diff --git a/common/Makefile.am b/common/Makefile.am
index b6145ba..1af6ac8 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -2,9 +2,44 @@ noinst_LTLIBRARIES = libxfdesktop.la
 
 libxfdesktop_la_SOURCES = \
 	xfdesktop-common.c \
-	xfdesktop-common.h
+	xfdesktop-common.h \
+	xfdesktop-marshal.c \
+	xfdesktop-marshal.h
 
 libxfdesktop_la_CFLAGS = \
 	-I$(top_srcdir)/src \
 	$(LIBXFCE4UTIL_CFLAGS) \
 	$(GTK_CFLAGS)
+
+if ENABLE_DESKTOP_ICONS
+if ENABLE_FILE_ICONS
+
+libxfdesktop_la_SOURCES += \
+	xfdesktop-thumbnailer.c \
+	xfdesktop-thumbnailer.h
+
+libxfdesktop_la_CFLAGS += \
+	-DDBUS_API_SUBJECT_TO_CHANGE \
+	$(DBUS_CFLAGS)
+
+endif
+endif
+
+DISTCLEANFILES = \
+	$(xfdesktop_built_sources) \
+	stamp-xfdesktop-marshal.h \
+	xfdesktop-marshal.c \
+	xfdesktop-marshal.h
+
+xfdesktop-marshal.h: stamp-xfdesktop-marshal.h
+	@true
+stamp-xfdesktop-marshal.h: xfdesktop-marshal.list Makefile
+	$(AM_V_GEN) glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --header > xfdesktop-marshal.h && \
+	echo timestamp > $(@F)
+xfdesktop-marshal.c: xfdesktop-marshal.list Makefile
+	$(AM_V_GEN) echo '#include "xfdesktop-marshal.h"' > xfdesktop-marshal.c && \
+	glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --body >> xfdesktop-marshal.c && \
+	glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --header > xfdesktop-marshal.h
+
+EXTRA_DIST = \
+	xfdesktop-marshal.list
diff --git a/common/xfdesktop-common.c b/common/xfdesktop-common.c
index 9e4f22c..64aee8d 100644
--- a/common/xfdesktop-common.c
+++ b/common/xfdesktop-common.c
@@ -370,7 +370,10 @@ xfdesktop_popup_grab_available (GdkWindow *win, guint32 timestamp)
     while ((i++ < 2500) && (grab_failed = ((g1 != GDK_GRAB_SUCCESS)
                 || (g2 != GDK_GRAB_SUCCESS))))
     {
-        TRACE ("grab not available yet, waiting... (%i)", i);
+        TRACE ("grab not available yet, mouse reason: %d, keyboard reason: %d, waiting... (%i)", g1, g2, i);
+        if(g1 == GDK_GRAB_INVALID_TIME || g2 == GDK_GRAB_INVALID_TIME)
+            break;
+
         g_usleep (100);
         if (g1 != GDK_GRAB_SUCCESS)
         {
diff --git a/common/xfdesktop-common.h b/common/xfdesktop-common.h
index 58a6f45..151487e 100644
--- a/common/xfdesktop-common.h
+++ b/common/xfdesktop-common.h
@@ -47,6 +47,7 @@
 #define RELOAD_MESSAGE     "reload"
 #define MENU_MESSAGE       "menu"
 #define WINDOWLIST_MESSAGE "windowlist"
+#define ARRANGE_MESSAGE    "arrange"
 #define QUIT_MESSAGE       "quit"
 
 /**
diff --git a/common/xfdesktop-marshal.list b/common/xfdesktop-marshal.list
new file mode 100644
index 0000000..8fe4148
--- /dev/null
+++ b/common/xfdesktop-marshal.list
@@ -0,0 +1,4 @@
+BOOLEAN:VOID
+BOOLEAN:ENUM,INT
+VOID:UINT,BOXED
+VOID:STRING,STRING
diff --git a/common/xfdesktop-thumbnailer.c b/common/xfdesktop-thumbnailer.c
new file mode 100644
index 0000000..8f39fe9
--- /dev/null
+++ b/common/xfdesktop-thumbnailer.c
@@ -0,0 +1,606 @@
+/*
+ *  xfdesktop - xfce4's desktop manager
+ *
+ *  Copyright(c) 2006 Brian Tarricone, <bjt23 at cornell.edu>
+ *  Copyright(c) 2006 Benedikt Meurer, <benny at xfce.org>
+ *  Copyright(c) 2010-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 Library 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.
+ *
+ *  xfdesktop-thumbnailer is based on thumbnailer code from Ristretto
+ *  Copyright (c) Stephan Arts 2009-2011 <stephan at xfce.org>
+ *
+ *  Thumbnailer Spec
+ *  http://live.gnome.org/ThumbnailerSpec
+ *  Thumbnail Managing Standard
+ *  http://people.freedesktop.org/~vuntz/thumbnail-spec-cache/creation.html
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+#include <dbus/dbus-glib.h>
+
+#include <libxfce4util/libxfce4util.h>
+#include "xfdesktop-thumbnailer.h"
+#include "xfdesktop-marshal.h"
+
+static void xfdesktop_thumbnailer_init(GObject *);
+static void xfdesktop_thumbnailer_class_init(GObjectClass *);
+
+static void xfdesktop_thumbnailer_dispose(GObject *object);
+static void xfdesktop_thumbnailer_finalize(GObject *object);
+
+static void xfdesktop_thumbnailer_request_finished_dbus(DBusGProxy *proxy,
+                                                        gint handle,
+                                                        gpointer data);
+
+static void xfdesktop_thumbnailer_thumbnail_ready_dbus(DBusGProxy *proxy,
+                                                       gint handle,
+                                                       const gchar **uri,
+                                                       gpointer data);
+
+static gboolean xfdesktop_thumbnailer_queue_request_timer(XfdesktopThumbnailer *thumbnailer);
+
+static GObjectClass *parent_class = NULL;
+static XfdesktopThumbnailer *thumbnailer_object = NULL;
+
+enum
+{
+    THUMBNAIL_READY,
+    LAST_SIGNAL,
+};
+
+static guint thumbnailer_signals[LAST_SIGNAL] = { 0, };
+
+GType
+xfdesktop_thumbnailer_get_type(void)
+{
+    static GType xfdesktop_thumbnailer_type = 0;
+
+    if(!xfdesktop_thumbnailer_type) {
+        static const GTypeInfo xfdesktop_thumbnailer_info =
+        {
+            sizeof (XfdesktopThumbnailerClass),
+            (GBaseInitFunc) NULL,
+            (GBaseFinalizeFunc) NULL,
+            (GClassInitFunc) xfdesktop_thumbnailer_class_init,
+            (GClassFinalizeFunc) NULL,
+            NULL,
+            sizeof (XfdesktopThumbnailer),
+            0,
+            (GInstanceInitFunc) xfdesktop_thumbnailer_init,
+            NULL
+        };
+
+        xfdesktop_thumbnailer_type = g_type_register_static(
+                                                    G_TYPE_OBJECT,
+                                                    "XfdesktopThumbnailer",
+                                                    &xfdesktop_thumbnailer_info,
+                                                    0);
+    }
+    return xfdesktop_thumbnailer_type;
+}
+
+struct _XfdesktopThumbnailerPriv
+{
+    DBusGProxy               *proxy;
+
+    GSList                   *queue;
+    gchar                   **supported_mimetypes;
+    gboolean                  big_thumbnails;
+    gint                      handle;
+
+    gint                      request_timer_id;
+};
+
+static void
+xfdesktop_thumbnailer_init(GObject *object)
+{
+    XfdesktopThumbnailer *thumbnailer;
+    DBusGConnection      *connection;
+
+    thumbnailer = XFDESKTOP_THUMBNAILER(object);
+
+    thumbnailer->priv = g_new0(XfdesktopThumbnailerPriv, 1);
+
+    connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+
+    if(connection) {
+        thumbnailer->priv->proxy = dbus_g_proxy_new_for_name(
+                                    connection,
+                                    "org.freedesktop.thumbnails.Thumbnailer1",
+                                    "/org/freedesktop/thumbnails/Thumbnailer1",
+                                    "org.freedesktop.thumbnails.Thumbnailer1");
+
+        if(thumbnailer->priv->proxy) {
+            gchar **supported_uris = NULL;
+            gchar **supported_flavors = NULL;
+
+            dbus_g_object_register_marshaller(
+                    (GClosureMarshal) xfdesktop_marshal_VOID__UINT_BOXED,
+                    G_TYPE_NONE, G_TYPE_UINT,
+                    G_TYPE_STRV, G_TYPE_INVALID);
+
+            dbus_g_proxy_add_signal(
+                    thumbnailer->priv->proxy,
+                    "Finished", G_TYPE_UINT, G_TYPE_INVALID);
+            dbus_g_proxy_add_signal(
+                    thumbnailer->priv->proxy,
+                    "Ready", G_TYPE_UINT, G_TYPE_STRV, G_TYPE_INVALID);
+
+            dbus_g_proxy_connect_signal(
+                    thumbnailer->priv->proxy,
+                    "Finished", G_CALLBACK (xfdesktop_thumbnailer_request_finished_dbus),
+                    thumbnailer, NULL);
+            dbus_g_proxy_connect_signal(
+                    thumbnailer->priv->proxy,
+                    "Ready", G_CALLBACK(xfdesktop_thumbnailer_thumbnail_ready_dbus),
+                    thumbnailer, NULL);
+
+            dbus_g_proxy_call(thumbnailer->priv->proxy, "GetSupported", NULL, G_TYPE_INVALID,
+                              G_TYPE_STRV, &supported_uris,
+                              G_TYPE_STRV, &thumbnailer->priv->supported_mimetypes,
+                              G_TYPE_INVALID);
+
+            dbus_g_proxy_call(thumbnailer->priv->proxy, "GetFlavors", NULL, G_TYPE_INVALID,
+                              G_TYPE_STRV, &supported_flavors,
+                              G_TYPE_INVALID);
+
+            if(supported_flavors != NULL) {
+                gint n;
+                for(n = 0; supported_flavors[n] != NULL; ++n) {
+                    if(g_strcmp0(supported_flavors[n], "large")) {
+                        thumbnailer->priv->big_thumbnails = TRUE;
+                    }
+                }
+            } else {
+                thumbnailer->priv->big_thumbnails = FALSE;
+                g_warning("Thumbnailer failed calling GetFlavors");
+            }
+
+            g_strfreev(supported_flavors);
+            g_strfreev(supported_uris);
+        }
+
+        dbus_g_connection_unref(connection);
+    }
+}
+
+static void
+xfdesktop_thumbnailer_class_init (GObjectClass *object_class)
+{
+    XfdesktopThumbnailerClass *thumbnailer_class = XFDESKTOP_THUMBNAILER_CLASS(object_class);
+
+    parent_class = g_type_class_peek_parent(thumbnailer_class);
+
+    object_class->dispose = xfdesktop_thumbnailer_dispose;
+    object_class->finalize = xfdesktop_thumbnailer_finalize;
+
+    thumbnailer_signals[THUMBNAIL_READY] = g_signal_new (
+                        "thumbnail-ready",
+                        G_OBJECT_CLASS_TYPE (object_class),
+                        G_SIGNAL_RUN_LAST,
+                        G_STRUCT_OFFSET(XfdesktopThumbnailerClass, thumbnail_ready),
+                        NULL, NULL,
+                        xfdesktop_marshal_VOID__STRING_STRING,
+                        G_TYPE_NONE, 2,
+                        G_TYPE_STRING, G_TYPE_STRING);
+}
+
+/**
+ * xfdesktop_thumbnailer_dispose:
+ * @object:
+ *
+ */
+static void
+xfdesktop_thumbnailer_dispose(GObject *object)
+{
+    XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER(object);
+
+    if(thumbnailer->priv->proxy)
+        g_object_unref(thumbnailer->priv->proxy);
+
+    if(thumbnailer->priv->supported_mimetypes)
+        g_free(thumbnailer->priv->supported_mimetypes);
+
+    if(thumbnailer->priv) {
+        g_free(thumbnailer->priv);
+        thumbnailer->priv = NULL;
+    }
+
+    thumbnailer_object = NULL;
+}
+
+/**
+ * xfdesktop_thumbnailer_finalize:
+ * @object:
+ *
+ */
+static void
+xfdesktop_thumbnailer_finalize(GObject *object)
+{
+}
+
+/**
+ * xfdesktop_thumbnailer_new:
+ *
+ *
+ * Singleton
+ */
+XfdesktopThumbnailer *
+xfdesktop_thumbnailer_new(void)
+{
+    if(thumbnailer_object == NULL) {
+        thumbnailer_object = g_object_new(XFDESKTOP_TYPE_THUMBNAILER, NULL);
+    } else {
+        g_object_ref(thumbnailer_object);
+    }
+
+    return thumbnailer_object;
+}
+
+static gchar *
+xfdesktop_get_file_mimetype(gchar *file)
+{
+    GFile *temp_file;
+    GFileInfo *file_info;
+    gchar *mime_type = NULL;
+
+    g_return_val_if_fail(file != NULL, NULL);
+
+    temp_file = g_file_new_for_path(file);
+
+    g_return_val_if_fail(temp_file != NULL, NULL);
+
+    file_info = g_file_query_info(temp_file,
+                                  "standard::content-type",
+                                  0,
+                                  NULL,
+                                  NULL);
+
+    if(file_info != NULL) {
+        mime_type = g_strdup(g_file_info_get_content_type(file_info));
+
+        g_object_unref(file_info);
+    }
+
+    g_object_unref(temp_file);
+    
+    return mime_type;
+}
+
+gboolean
+xfdesktop_thumbnailer_is_supported(XfdesktopThumbnailer *thumbnailer,
+                                   gchar *file)
+{
+    guint        n;
+    gchar       *mime_type = NULL;
+
+    g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);
+    g_return_val_if_fail(file != NULL, FALSE);
+
+    mime_type = xfdesktop_get_file_mimetype(file);
+
+    if(mime_type == NULL) {
+        DBG("File %s has no mime type", file);
+        return FALSE;
+    }
+
+    if(thumbnailer->priv->supported_mimetypes != NULL) {
+        for(n = 0; thumbnailer->priv->supported_mimetypes[n] != NULL; ++n) {
+            if(g_content_type_is_a (mime_type, thumbnailer->priv->supported_mimetypes[n])) {
+                g_free(mime_type);
+                return TRUE;
+            }
+        }
+    }
+
+    g_free(mime_type);
+    return FALSE;
+}
+
+/**
+ * xfdesktop_thumbnailer_queue_thumbnail:
+ *
+ * Queues a file for thumbnail creation.
+ * A "thumbnail-ready" signal will be emitted when the thumbnail is ready.
+ * The signal will pass 2 parameters: a gchar *file which will be file
+ * that's passed in here and a gchar *thumbnail_file which will be the
+ * location of the thumbnail.
+ */
+gboolean
+xfdesktop_thumbnailer_queue_thumbnail(XfdesktopThumbnailer *thumbnailer,
+                                      gchar *file)
+{
+    g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);
+    g_return_val_if_fail(file != NULL, FALSE);
+
+    if(!xfdesktop_thumbnailer_is_supported(thumbnailer, file)) {
+        DBG("file: %s not supported", file);
+        return FALSE;
+    }
+    if(thumbnailer->priv->request_timer_id) {
+        g_source_remove(thumbnailer->priv->request_timer_id);
+
+        if(thumbnailer->priv->handle && thumbnailer->priv->proxy != NULL) {
+            if(dbus_g_proxy_call(thumbnailer->priv->proxy,
+                                 "Dequeue",
+                                 NULL,
+                                 G_TYPE_UINT, thumbnailer->priv->handle,
+                                 G_TYPE_INVALID) == FALSE)
+            {
+                g_warning("Dequeue of thumbnailer->priv->handle: %d failed",
+                          thumbnailer->priv->handle);
+            }
+
+            thumbnailer->priv->handle = 0;
+        }
+    }
+
+    if(g_slist_find(thumbnailer->priv->queue, file) == NULL) {
+        thumbnailer->priv->queue = g_slist_prepend(thumbnailer->priv->queue,
+                                                   file);
+    }
+
+    thumbnailer->priv->request_timer_id = g_timeout_add_full(
+                        G_PRIORITY_LOW,
+                        300,
+                        (GSourceFunc)xfdesktop_thumbnailer_queue_request_timer,
+                        thumbnailer,
+                        NULL);
+
+    return TRUE;
+}
+
+/**
+ * xfdesktop_thumbnailer_dequeue_thumbnail:
+ * 
+ * Removes a file from the list of pending thumbnail creations.
+ * This is not guaranteed to always remove the file, if processing
+ * of that thumbnail has started it won't stop.
+ */
+void
+xfdesktop_thumbnailer_dequeue_thumbnail(XfdesktopThumbnailer *thumbnailer,
+                                        gchar *file)
+{
+    g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));
+    g_return_if_fail(file != NULL);
+
+    if(thumbnailer->priv->request_timer_id) {
+        g_source_remove(thumbnailer->priv->request_timer_id);
+
+        if(thumbnailer->priv->handle && thumbnailer->priv->proxy) {
+            if(dbus_g_proxy_call(thumbnailer->priv->proxy,
+                                 "Dequeue",
+                                 NULL,
+                                 G_TYPE_UINT, thumbnailer->priv->handle,
+                                 G_TYPE_INVALID) == FALSE)
+            {
+                g_warning("Dequeue of thumbnailer->priv->handle: %d failed",
+                          thumbnailer->priv->handle);
+            }
+        }
+        thumbnailer->priv->handle = 0;
+    }
+
+    if(g_slist_find(thumbnailer->priv->queue, file) != NULL) {
+            thumbnailer->priv->queue = g_slist_remove_all(
+                                                    thumbnailer->priv->queue,
+                                                    file);
+    }
+
+    thumbnailer->priv->request_timer_id = g_timeout_add_full(
+                        G_PRIORITY_LOW,
+                        300,
+                        (GSourceFunc)xfdesktop_thumbnailer_queue_request_timer,
+                        thumbnailer,
+                        NULL);
+}
+
+static gboolean
+xfdesktop_thumbnailer_queue_request_timer(XfdesktopThumbnailer *thumbnailer)
+{
+    gchar **uris;
+    gchar **mimetypes;
+    GSList *iter;
+    gint i = 0;
+    GFile *file;
+    GError *error = NULL;
+    gchar *thumbnail_flavor;
+
+    g_return_val_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer), FALSE);
+
+    uris = g_new0(gchar *,
+                  g_slist_length(thumbnailer->priv->queue) + 1);
+    mimetypes = g_new0(gchar *,
+                       g_slist_length (thumbnailer->priv->queue) + 1);
+
+    iter = thumbnailer->priv->queue;
+    while(iter) {
+        if(iter->data) {
+            file = g_file_new_for_path(iter->data);
+            uris[i] = g_file_get_uri(file);
+            mimetypes[i] = xfdesktop_get_file_mimetype(iter->data);
+            g_object_unref(file);
+        }
+        iter = g_slist_next(iter);
+        i++;
+    }
+
+    if(thumbnailer->priv->big_thumbnails == TRUE)
+        thumbnail_flavor = "large";
+    else
+        thumbnail_flavor = "normal";
+
+    if(thumbnailer->priv->proxy != NULL) {
+        if(dbus_g_proxy_call(thumbnailer->priv->proxy,
+                             "Queue",
+                             &error,
+                             G_TYPE_STRV, uris,
+                             G_TYPE_STRV, mimetypes,
+                             G_TYPE_STRING, thumbnail_flavor,
+                             G_TYPE_STRING, "default",
+                             G_TYPE_UINT, 0,
+                             G_TYPE_INVALID,
+                             G_TYPE_UINT, &thumbnailer->priv->handle,
+                             G_TYPE_INVALID) == FALSE)
+        {
+            if(error != NULL)
+                g_warning("DBUS-call failed: %s", error->message);
+        }
+    }
+
+    g_free(uris);
+    g_free(mimetypes);
+
+    if(error)
+        g_error_free(error);
+
+    thumbnailer->priv->request_timer_id = 0;
+
+    return FALSE;
+}
+
+static void
+xfdesktop_thumbnailer_request_finished_dbus(DBusGProxy *proxy,
+                                            gint handle,
+                                            gpointer data)
+{
+    XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER(data);
+
+    g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));
+
+    thumbnailer->priv->handle = 0;
+}
+
+static void
+xfdesktop_thumbnailer_thumbnail_ready_dbus(DBusGProxy *proxy,
+                                           gint handle,
+                                           const gchar **uri,
+                                           gpointer data)
+{
+    XfdesktopThumbnailer *thumbnailer = XFDESKTOP_THUMBNAILER(data);
+    gchar *thumbnail_location;
+    GFile *file;
+    GSList *iter = thumbnailer->priv->queue;
+    gchar *f_uri, *f_uri_checksum, *filename;
+    gchar *thumbnail_flavor;
+    gint x = 0;
+
+    g_return_if_fail(XFDESKTOP_IS_THUMBNAILER(thumbnailer));
+
+    while(iter) {
+        if((uri[x] == NULL) || (iter->data == NULL)) {
+            break;
+        }
+
+        file = g_file_new_for_path(iter->data);
+        f_uri = g_file_get_uri(file);
+
+        if(strcmp (uri[x], f_uri) == 0) {
+            /* The thumbnail is in the format/location
+             * /homedir/.thumbnails/(normal|large)/MD5_Hash_Of_URI.png
+             */
+            f_uri_checksum = g_compute_checksum_for_string(G_CHECKSUM_MD5,
+                                                           f_uri, strlen (f_uri));
+
+            if(thumbnailer->priv->big_thumbnails == TRUE)
+                thumbnail_flavor = "large";
+            else
+                thumbnail_flavor = "normal";
+
+            filename = g_strconcat(f_uri_checksum, ".png", NULL);
+
+            thumbnail_location = g_build_path("/", g_get_home_dir(),
+                                              ".thumbnails", thumbnail_flavor,
+                                              filename, NULL);
+
+            DBG("thumbnail-ready src: %s thumbnail: %s",
+                    (char*)iter->data,
+                    thumbnail_location);
+
+            g_signal_emit(G_OBJECT(thumbnailer),
+                          thumbnailer_signals[THUMBNAIL_READY],
+                          0,
+                          iter->data,
+                          thumbnail_location);
+
+            thumbnailer->priv->queue = g_slist_remove(thumbnailer->priv->queue,
+                                                      iter->data);
+
+            iter = thumbnailer->priv->queue;
+            x++;
+            
+            g_free(filename);
+            g_free(f_uri_checksum);
+        } else {
+            iter = g_slist_next(iter);
+        }
+        
+        g_object_unref(file);
+        g_free(f_uri);
+    }
+}
+
+/**
+ * xfdesktop_thumbnailer_delete_thumbnail:
+ * 
+ * Tells the thumbnail service the src_file will be deleted.
+ * This function should be called when the file is deleted or moved so
+ * the thumbnail file doesn't take up space on the user's drive.
+ */
+void
+xfdesktop_thumbnailer_delete_thumbnail(XfdesktopThumbnailer *thumbnailer, gchar *src_file)
+{
+    DBusGConnection *connection;
+    gchar **uris;
+    GFile *file;
+    GError *error = NULL;
+    static DBusGProxy *cache = NULL;
+
+    if(!cache) {
+        connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+        if (connection != NULL) {
+            cache = dbus_g_proxy_new_for_name(connection,
+                                           "org.freedesktop.thumbnails.Cache1",
+                                           "/org/freedesktop/thumbnails/Cache1",
+                                           "org.freedesktop.thumbnails.Cache1");
+
+        dbus_g_connection_unref(connection);
+        }
+    }
+
+    file = g_file_new_for_path(src_file);
+
+    if(cache) {
+        uris = g_new0 (gchar *, 2);
+        uris[0] = g_file_get_uri(file);
+        dbus_g_proxy_call(cache, "Delete", &error, G_TYPE_STRV, uris, G_TYPE_INVALID, G_TYPE_INVALID);
+        if(error != NULL) {
+            g_warning("DBUS-call failed:%s", error->message);
+        }
+        g_free(uris);
+    }
+
+    g_object_unref(file);
+    if(error)
+        g_error_free(error);
+}
diff --git a/common/xfdesktop-thumbnailer.h b/common/xfdesktop-thumbnailer.h
new file mode 100644
index 0000000..842f155
--- /dev/null
+++ b/common/xfdesktop-thumbnailer.h
@@ -0,0 +1,76 @@
+/*
+ *  xfdesktop - xfce4's desktop manager
+ *
+ *  Copyright(c) 2006 Brian Tarricone, <bjt23 at cornell.edu>
+ *  Copyright(c) 2006 Benedikt Meurer, <benny at xfce.org>
+ *  Copyright(c) 2010-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 Library 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.
+ *
+ *  xfdesktop-thumbnailer is based on thumbnailer code from Ristretto
+ *  Copyright (c) Stephan Arts 2009-2011 <stephan at xfce.org>
+ */
+
+#ifndef __XFDESKTOP_THUMBNAILER_H__
+#define __XFDESKTOP_THUMBNAILER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define XFDESKTOP_TYPE_THUMBNAILER             (xfdesktop_thumbnailer_get_type())
+#define XFDESKTOP_THUMBNAILER(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), XFDESKTOP_TYPE_THUMBNAILER, XfdesktopThumbnailer))
+#define XFDESKTOP_IS_THUMBNAILER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDESKTOP_TYPE_THUMBNAILER))
+#define XFDESKTOP_THUMBNAILER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), XFDESKTOP_TYPE_THUMBNAILER, XfdesktopThumbnailerClass))
+#define XFDESKTOP_IS_THUMBNAILER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), XFDESKTOP_TYPE_THUMBNAILER()))
+
+typedef struct _XfdesktopThumbnailer XfdesktopThumbnailer;
+typedef struct _XfdesktopThumbnailerPriv XfdesktopThumbnailerPriv;
+
+struct _XfdesktopThumbnailer
+{
+    GObject parent;
+
+    XfdesktopThumbnailerPriv *priv;
+};
+
+typedef struct _XfdesktopThumbnailerClass XfdesktopThumbnailerClass;
+
+struct _XfdesktopThumbnailerClass
+{
+    GObjectClass parent_class;
+
+    /*< signals >*/
+    void (*thumbnail_ready)(gchar *src_file, gchar *thumb_file);
+};
+
+XfdesktopThumbnailer * xfdesktop_thumbnailer_new(void);
+
+GType xfdesktop_thumbnailer_get_type(void);
+
+gboolean xfdesktop_thumbnailer_is_supported(XfdesktopThumbnailer *thumbnailer,
+                                            gchar *file);
+
+gboolean xfdesktop_thumbnailer_queue_thumbnail(XfdesktopThumbnailer *thumbnailer,
+                                               gchar *file);
+void xfdesktop_thumbnailer_dequeue_thumbnail(XfdesktopThumbnailer *thumbnailer,
+                                             gchar *file);
+
+void xfdesktop_thumbnailer_delete_thumbnail(XfdesktopThumbnailer *thumbnailer,
+                                            gchar *src_file);
+
+G_END_DECLS
+
+#endif /* __XFDESKTOP_THUMBNAILER_H__ */
diff --git a/configure.ac.in b/configure.ac.in
index b22e8dc..ca0277f 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -145,8 +145,9 @@ dnl calls AM_CONDITIONAL(), which cannot be in an 'if' block
 XDT_CHECK_OPTIONAL_PACKAGE([THUNARX], [thunarx-2], [thunar_minimum_version],
     [thunarx],
     [Thunar's extension mechanism, to add external features to the desktop icon implementation])
-XDT_CHECK_OPTIONAL_PACKAGE([LIBEXO], [exo-1], [exo_minimum_version], [exo],
-    [libexo, for nifty icon effects])
+
+dnl LIBEXO is required if file icons are enabled
+XDT_CHECK_PACKAGE([LIBEXO], [exo-1], [exo_minimum_version])
 
 
 AC_ARG_ENABLE([desktop-menu],
diff --git a/doc/README.xfconf b/doc/README.xfconf
index 2fa1c40..74bf96e 100644
--- a/doc/README.xfconf
+++ b/doc/README.xfconf
@@ -37,6 +37,8 @@ property is listd after the name.
     <use-custom-font-size bool>
     <font-size uint>
     <icon-size uint>
+    <single-click bool>
+    <show-thumbnails bool>
     <file-icons>
         <show-filesystem bool>
         <show-home bool>
diff --git a/settings/main.c b/settings/main.c
index 1f76be9..c6fbaad 100644
--- a/settings/main.c
+++ b/settings/main.c
@@ -46,10 +46,7 @@
 #include <libxfce4util/libxfce4util.h>
 #include <xfconf/xfconf.h>
 #include <libxfce4ui/libxfce4ui.h>
-
-#ifdef HAVE_LIBEXO
 #include <exo/exo.h>
-#endif
 
 #include "xfdesktop-common.h"
 #include "xfdesktop-settings-ui.h"
@@ -70,6 +67,8 @@
 #define DESKTOP_ICONS_ICON_SIZE_PROP         "/desktop-icons/icon-size"
 #define DESKTOP_ICONS_FONT_SIZE_PROP         "/desktop-icons/font-size"
 #define DESKTOP_ICONS_CUSTOM_FONT_SIZE_PROP  "/desktop-icons/use-custom-font-size"
+#define DESKTOP_ICONS_SINGLE_CLICK_PROP      "/desktop-icons/single-click"
+#define DESKTOP_ICONS_SHOW_THUMBNAILS_PROP   "/desktop-icons/show-thumbnails"
 #define DESKTOP_ICONS_SHOW_HOME              "/desktop-icons/file-icons/show-home"
 #define DESKTOP_ICONS_SHOW_TRASH             "/desktop-icons/file-icons/show-trash"
 #define DESKTOP_ICONS_SHOW_FILESYSTEM        "/desktop-icons/file-icons/show-filesystem"
@@ -103,6 +102,11 @@ typedef struct
 
     GtkWidget *brightness_slider;
     GtkWidget *saturation_slider;
+
+    GtkWidget *backdrop_cycle_spinbox;
+    GtkWidget *backdrop_cycle_chkbox;
+
+    GtkWidget *chk_xinerama_stretch;
 } AppearancePanel;
 
 typedef struct
@@ -757,6 +761,56 @@ cb_xfdesktop_chk_custom_font_size_toggled(GtkCheckButton *button,
                              gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
 }
 
+static void
+cb_xfdesktop_chk_cycle_backdrop_toggled(GtkCheckButton *button,
+                                        gpointer user_data)
+{
+    gboolean sensitive = FALSE;
+    GtkWidget *spin_button = GTK_WIDGET(user_data);
+
+    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) &&
+       gtk_widget_get_sensitive(GTK_WIDGET(button))) {
+           sensitive = TRUE;
+    }
+
+    gtk_widget_set_sensitive(spin_button, sensitive);
+}
+
+static gboolean
+xfdesktop_spin_icon_size_timer(GtkSpinButton *button)
+{
+    XfconfChannel *channel = g_object_get_data(G_OBJECT(button), "xfconf-chanel");
+
+    g_return_val_if_fail(XFCONF_IS_CHANNEL(channel), FALSE);
+
+    xfconf_channel_set_uint(channel,
+                            DESKTOP_ICONS_ICON_SIZE_PROP,
+                            gtk_spin_button_get_value(button));
+
+    return FALSE;
+}
+
+static void
+cb_xfdesktop_spin_icon_size_changed(GtkSpinButton *button,
+                                    gpointer user_data)
+{
+    guint timer_id = 0;
+
+    g_object_set_data(G_OBJECT(button), "xfconf-chanel", user_data);
+
+    timer_id = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(button), "timer-id"));
+    if(timer_id != 0) {
+        g_source_remove(timer_id);
+        timer_id = 0;
+    }
+
+    timer_id = g_timeout_add(2000,
+                             (GSourceFunc)xfdesktop_spin_icon_size_timer,
+                             button);
+
+    g_object_set_data(G_OBJECT(button), "timer-id", GUINT_TO_POINTER(timer_id));
+}
+
 static gboolean
 xfdesktop_settings_save_backdrop_list(AppearancePanel *panel,
                                       GtkTreeModel *model)
@@ -840,9 +894,7 @@ add_file_button_clicked(GtkWidget *button,
                                (GtkFileFilterFunc)gtk_true, NULL, NULL);
     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
 
-#ifdef HAVE_LIBEXO
     exo_gtk_file_chooser_add_thumbnail_preview(GTK_FILE_CHOOSER(chooser));
-#endif
 
     if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) {
         GSList *filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chooser));
@@ -988,6 +1040,8 @@ cb_image_type_radio_clicked(GtkWidget *w,
         gtk_widget_set_sensitive(panel->btn_minus, FALSE);
         gtk_widget_set_sensitive(panel->btn_newlist, FALSE);
         gtk_widget_set_sensitive(panel->frame_image_list, TRUE);
+        gtk_widget_set_sensitive(panel->backdrop_cycle_chkbox, FALSE);
+        gtk_widget_set_sensitive(panel->backdrop_cycle_spinbox, FALSE);
         DBG("show_image=%s", panel->show_image?"true":"false");
         if(!panel->show_image) {
             panel->show_image = TRUE;
@@ -1013,6 +1067,11 @@ cb_image_type_radio_clicked(GtkWidget *w,
         gtk_widget_set_sensitive(panel->btn_minus, TRUE);
         gtk_widget_set_sensitive(panel->btn_newlist, TRUE);
         gtk_widget_set_sensitive(panel->frame_image_list, TRUE);
+        gtk_widget_set_sensitive(panel->backdrop_cycle_chkbox, TRUE);
+        if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(panel->backdrop_cycle_chkbox)))
+            gtk_widget_set_sensitive(panel->backdrop_cycle_spinbox, TRUE);
+        else
+            gtk_widget_set_sensitive(panel->backdrop_cycle_spinbox, FALSE);
         DBG("show_image=%s", panel->show_image?"true":"false");
         if(!panel->show_image) {
             panel->show_image = TRUE;
@@ -1021,6 +1080,8 @@ cb_image_type_radio_clicked(GtkWidget *w,
     } else if(w == panel->radio_none) {
         DBG("widget is none");
         gtk_widget_set_sensitive(panel->frame_image_list, FALSE);
+        gtk_widget_set_sensitive(panel->backdrop_cycle_chkbox, FALSE);
+        gtk_widget_set_sensitive(panel->backdrop_cycle_spinbox, FALSE);
         DBG("show_image=%s", panel->show_image?"true":"false");
         if(panel->show_image) {
             panel->show_image = FALSE;
@@ -1225,19 +1286,37 @@ xfdesktop_settings_dialog_add_screens(GtkBuilder *main_gxml,
 {
     gint i, j, nmonitors, nscreens;
     GtkWidget *appearance_container, *chk_custom_font_size,
-              *spin_font_size, *color_style_widget, *w, *box;
+              *spin_font_size, *color_style_widget, *w, *box,
+              *spin_icon_size, *chk_show_thumbnails, *chk_single_click;
 
     appearance_container = GTK_WIDGET(gtk_builder_get_object(main_gxml,
                                                              "notebook_screens"));
 
+    spin_icon_size = GTK_WIDGET(gtk_builder_get_object(main_gxml, "spin_icon_size"));
+
+    g_signal_connect(G_OBJECT(spin_icon_size), "value-changed",
+                     G_CALLBACK(cb_xfdesktop_spin_icon_size_changed),
+                     channel);
+
+    gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_icon_size),
+                              xfconf_channel_get_uint(channel,
+                                                      DESKTOP_ICONS_ICON_SIZE_PROP,
+                                                      DEFAULT_ICON_SIZE));
+
     chk_custom_font_size = GTK_WIDGET(gtk_builder_get_object(main_gxml,
                                                              "chk_custom_font_size"));
     spin_font_size = GTK_WIDGET(gtk_builder_get_object(main_gxml, "spin_font_size"));
 
+    chk_single_click = GTK_WIDGET(gtk_builder_get_object(main_gxml,
+                                                         "chk_single_click"));
+
     g_signal_connect(G_OBJECT(chk_custom_font_size), "toggled",
                      G_CALLBACK(cb_xfdesktop_chk_custom_font_size_toggled),
                      spin_font_size);
 
+    chk_show_thumbnails = GTK_WIDGET(gtk_builder_get_object(main_gxml,
+                                                            "chk_show_thumbnails"));
+
     nscreens = gdk_display_get_n_screens(gdk_display_get_default());
 
     for(i = 0; i < nscreens; ++i) {
@@ -1382,6 +1461,43 @@ xfdesktop_settings_dialog_add_screens(GtkBuilder *main_gxml,
             g_signal_connect(G_OBJECT(panel->btn_newlist), "clicked",
                              G_CALLBACK(newlist_button_clicked), panel);
 
+            panel->chk_xinerama_stretch = GTK_WIDGET(gtk_builder_get_object(appearance_gxml,
+                                                                            "chk_xinerama_stretch"));
+
+            /* The first monitor has the option of doing the xinerama-stretch,
+             * but only if there's multiple monitors attached. Make it invisible
+             * in all other cases.
+             */
+            if(j == 0 && nmonitors > 1) {
+                g_snprintf(buf, sizeof(buf), "/backdrop/screen%d/xinerama-stretch",
+                           i);
+                xfconf_g_property_bind(channel, buf, G_TYPE_BOOLEAN,
+                                        G_OBJECT(panel->chk_xinerama_stretch), "active");
+                gtk_widget_set_sensitive(panel->chk_xinerama_stretch, TRUE);
+            } else {
+                gtk_widget_hide(panel->chk_xinerama_stretch);
+            }
+
+            panel->backdrop_cycle_chkbox = GTK_WIDGET(gtk_builder_get_object(appearance_gxml,
+                                                                             "chk_cycle_backdrop"));
+            panel->backdrop_cycle_spinbox = GTK_WIDGET(gtk_builder_get_object(appearance_gxml,
+                                                                             "spin_backdrop_time_minutes"));
+
+            g_signal_connect(G_OBJECT(panel->backdrop_cycle_chkbox), "toggled",
+                            G_CALLBACK(cb_xfdesktop_chk_cycle_backdrop_toggled),
+                            panel->backdrop_cycle_spinbox);
+
+            g_snprintf(buf, sizeof(buf), PER_SCREEN_PROP_FORMAT "/backdrop-cycle-enable",
+                       i, j);
+            xfconf_g_property_bind(channel, buf, G_TYPE_BOOLEAN,
+                                   G_OBJECT(panel->backdrop_cycle_chkbox), "active");
+
+            g_snprintf(buf, sizeof(buf), PER_SCREEN_PROP_FORMAT "/backdrop-cycle-timer",
+                       i, j);
+            xfconf_g_property_bind(channel, buf, G_TYPE_UINT,
+                           G_OBJECT(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(panel->backdrop_cycle_spinbox))),
+                           "value");
+
             panel->radio_singleimage = GTK_WIDGET(gtk_builder_get_object(appearance_gxml,
                                                                          "radio_singleimage"));
             g_signal_connect(G_OBJECT(panel->radio_singleimage), "toggled",
@@ -1477,16 +1593,18 @@ xfdesktop_settings_dialog_add_screens(GtkBuilder *main_gxml,
 #endif
     xfconf_g_property_bind(channel, DESKTOP_ICONS_STYLE_PROP, G_TYPE_INT,
                            G_OBJECT(w), "active");
-    xfconf_g_property_bind(channel, DESKTOP_ICONS_ICON_SIZE_PROP, G_TYPE_UINT,
-                           G_OBJECT(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(gtk_builder_get_object(main_gxml,
-                                                                                                          "spin_icon_size")))),
-                           "value");
     xfconf_g_property_bind(channel, DESKTOP_ICONS_FONT_SIZE_PROP, G_TYPE_DOUBLE,
                            G_OBJECT(gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(spin_font_size))),
                            "value");
     xfconf_g_property_bind(channel, DESKTOP_ICONS_CUSTOM_FONT_SIZE_PROP,
                            G_TYPE_BOOLEAN, G_OBJECT(chk_custom_font_size),
                            "active");
+    xfconf_g_property_bind(channel, DESKTOP_ICONS_SHOW_THUMBNAILS_PROP,
+                           G_TYPE_BOOLEAN, G_OBJECT(chk_show_thumbnails),
+                           "active");
+    xfconf_g_property_bind(channel, DESKTOP_ICONS_SINGLE_CLICK_PROP,
+                           G_TYPE_BOOLEAN, G_OBJECT(chk_single_click),
+                           "active");
 
     setup_special_icon_list(main_gxml, channel);
 }
diff --git a/settings/xfdesktop-settings-appearance-frame-ui.glade b/settings/xfdesktop-settings-appearance-frame-ui.glade
index 3a4fed6..a397d94 100644
--- a/settings/xfdesktop-settings-appearance-frame-ui.glade
+++ b/settings/xfdesktop-settings-appearance-frame-ui.glade
@@ -17,6 +17,14 @@
     <property name="page_size">0</property>
     <property name="value">1</property>
   </object>
+  <object class="GtkAdjustment" id="adjustment3">
+    <property name="upper">65535</property>
+    <property name="lower">1</property>
+    <property name="page_increment">10</property>
+    <property name="step_increment">1</property>
+    <property name="page_size">0</property>
+    <property name="value">10</property>
+  </object>
   <object class="GtkListStore" id="model1">
     <columns>
       <column type="gchararray"/>
@@ -528,6 +536,62 @@
             <property name="position">1</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkHBox" id="hbox9">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">4</property>
+            <child>
+              <object class="GtkCheckButton" id="chk_cycle_backdrop">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">_Change the background (in minutes):</property>
+                <property name="tooltip-text" translatable="yes">While in image list mode, select this option to automatically select a different background from the image list after a set number of minutes.</property>
+                <property name="use_underline">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+          <child>
+            <object class="GtkSpinButton" id="spin_backdrop_time_minutes">
+              <property name="visible">True</property>
+              <property name="sensitive">False</property>
+              <property name="can_focus">True</property>
+              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              <property name="adjustment">adjustment3</property>
+              <property name="tooltip-text" translatable="yes">Number of minutes before a different background is randomly selected from the list.</property>
+            </object>
+            <packing>
+              <property name="expand">False</property>
+              <property name="position">2</property>
+            </packing>
+          </child>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="position">2</property>
+        </packing>
+      </child>
+      <child>
+        <object class="GtkCheckButton" id="chk_xinerama_stretch">
+          <property name="visible">True</property>
+          <property name="sensitive">False</property>
+          <property name="can_focus">True</property>
+          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+          <property name="label" translatable="yes">St_retch this background across all monitors.</property>
+          <property name="tooltip-text" translatable="yes">When multiple monitors are present, select this option to stretch the current background over all of them.</property>
+          <property name="use_underline">True</property>
+          <property name="draw_indicator">True</property>
+        </object>
+        <packing>
+          <property name="expand">False</property>
+          <property name="position">3</property>
+        </packing>
+      </child>
       </object>
     </child>
   </object>
diff --git a/settings/xfdesktop-settings-ui.glade b/settings/xfdesktop-settings-ui.glade
index 0ae289c..eef177e 100644
--- a/settings/xfdesktop-settings-ui.glade
+++ b/settings/xfdesktop-settings-ui.glade
@@ -685,6 +685,27 @@
                                   </packing>
                                 </child>
                                 <child>
+                                      <object class="GtkCheckButton" id="chk_show_thumbnails">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                        <property name="label" translatable="yes">Show t_humbnails</property>
+                                        <property name="tooltip-text" translatable="yes">Select this option to display preview-able files on the desktop as automatically generated thumbnail icons.</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="draw_indicator">True</property>
+                                      </object>
+                                </child>
+                                <child>
+                                  <object class="GtkCheckButton" id="chk_single_click">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="label" translatable="yes">Single _click to activate items</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                </child>
+                                <child>
                                   <object class="GtkHBox" id="hbox9">
                                     <property name="visible">True</property>
                                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
diff --git a/src/Makefile.am b/src/Makefile.am
index 5d1fd4d..3adb3d2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,9 +4,7 @@ bin_PROGRAMS = xfdesktop
 
 xfdesktop_built_sources = \
 	xfce-desktop-enum-types.c \
-	xfce-desktop-enum-types.h \
-	xfdesktop-marshal.c \
-	xfdesktop-marshal.h
+	xfce-desktop-enum-types.h
 
 if HAVE_LIBNOTIFY
 xfdesktop_notify_sources = \
@@ -149,17 +147,8 @@ BUILT_SOURCES = \
 
 DISTCLEANFILES = \
 	$(xfdesktop_built_sources) \
-	stamp-xfdesktop-marshal.h \
 	stamp-xfce-desktop-enum-types.h
 
-xfdesktop-marshal.h: stamp-xfdesktop-marshal.h
-	@true
-stamp-xfdesktop-marshal.h: xfdesktop-marshal.list Makefile
-	$(AM_V_GEN) glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --header > xfdesktop-marshal.h && \
-	echo timestamp > $(@F)
-xfdesktop-marshal.c: xfdesktop-marshal.list Makefile
-	$(AM_V_GEN) echo '#include "xfdesktop-marshal.h"' > xfdesktop-marshal.c && \
-	glib-genmarshal --prefix=xfdesktop_marshal xfdesktop-marshal.list --body >> xfdesktop-marshal.c
 
 enum_headers = \
 	xfce-backdrop.h \
@@ -227,5 +216,4 @@ endif
 EXTRA_DIST = \
 	$(desktop_menu_sources) \
 	$(desktop_icon_sources) \
-	$(desktop_file_icon_sources) \
-	xfdesktop-marshal.list
+	$(desktop_file_icon_sources)
diff --git a/src/main.c b/src/main.c
index af11691..9de09db 100644
--- a/src/main.c
+++ b/src/main.c
@@ -189,6 +189,11 @@ client_message_received(GtkWidget *w, GdkEventClient *evt, gpointer user_data)
             xfce_desktop_popup_secondary_root_menu(XFCE_DESKTOP(w), 0,
                                                    GDK_CURRENT_TIME);
             return TRUE;
+#ifdef ENABLE_FILE_ICONS
+        } else if(!strcmp(ARRANGE_MESSAGE, evt->data.b)) {
+            xfce_desktop_arrange_icons(XFCE_DESKTOP(w));
+            return TRUE;
+#endif
         } else if(!strcmp(QUIT_MESSAGE, evt->data.b)) {
             xfce_sm_client_set_restart_style(sm_client,
                                              XFCE_SM_CLIENT_RESTART_NORMAL);
@@ -233,12 +238,15 @@ main(int argc, char **argv)
     GError *error = NULL;
     gboolean opt_version = FALSE, opt_reload = FALSE;
     gboolean opt_menu = FALSE, opt_windowlist = FALSE;
-    gboolean opt_quit = FALSE;
+    gboolean opt_arrange = FALSE, opt_quit = FALSE;
     const GOptionEntry main_entries[] = {
         { "version", 'V', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_version, N_("Display version information"), NULL },
         { "reload", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_reload, N_("Reload all settings, refresh image list"), NULL },
         { "menu", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_menu, N_("Pop up the menu (at the current mouse position)"), NULL },
         { "windowlist", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_windowlist, N_("Pop up the window list (at the current mouse position)"), NULL },
+#ifdef ENABLE_FILE_ICONS
+        { "arrange", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_arrange, N_("Automatically arrange all the icons on the desktop"), NULL },
+#endif
         { "quit", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_quit, N_("Cause xfdesktop to quit"), NULL },
         { NULL, 0, 0, 0, NULL, NULL, NULL }
     };
@@ -303,6 +311,8 @@ main(int argc, char **argv)
         message = MENU_MESSAGE;
     else if(opt_windowlist)
         message = WINDOWLIST_MESSAGE;
+    else if(opt_arrange)
+        message = ARRANGE_MESSAGE;
     else if(opt_quit)
         message = QUIT_MESSAGE;
     
diff --git a/src/xfce-backdrop.c b/src/xfce-backdrop.c
index 486a796..600d7fd 100644
--- a/src/xfce-backdrop.c
+++ b/src/xfce-backdrop.c
@@ -52,6 +52,7 @@ static void xfce_backdrop_get_property(GObject *object,
                                        guint property_id,
                                        GValue *value,
                                        GParamSpec *pspec);
+static void xfce_backdrop_timer(XfceBackdrop *backdrop);
 
 struct _XfceBackdropPriv
 {
@@ -65,14 +66,20 @@ struct _XfceBackdropPriv
     gboolean show_image;
     XfceBackdropImageStyle image_style;
     gchar *image_path;
+    gchar *backdrop_list;
     
     gint brightness;
     gdouble saturation;
+
+    gboolean cycle_backdrop;
+    guint cycle_timer;
+    guint cycle_timer_id;
 };
 
 enum
 {
     BACKDROP_CHANGED,
+    BACKDROP_CYCLE,
     LAST_SIGNAL,
 };
 
@@ -87,6 +94,8 @@ enum
     PROP_IMAGE_FILENAME,
     PROP_BRIGHTNESS,
     PROP_SATURATION,
+    PROP_BACKDROP_CYCLE_ENABLE,
+    PROP_BACKDROP_CYCLE_TIMER,
 };
 
 static guint backdrop_signals[LAST_SIGNAL] = { 0, };
@@ -240,6 +249,10 @@ xfce_backdrop_class_init(XfceBackdropClass *klass)
             G_OBJECT_CLASS_TYPE(gobject_class), G_SIGNAL_RUN_FIRST,
             G_STRUCT_OFFSET(XfceBackdropClass, changed), NULL, NULL,
             g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+    backdrop_signals[BACKDROP_CYCLE] = g_signal_new("cycle",
+            G_OBJECT_CLASS_TYPE(gobject_class), G_SIGNAL_RUN_FIRST,
+            G_STRUCT_OFFSET(XfceBackdropClass, cycle), NULL, NULL,
+            g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 
 #define XFDESKTOP_PARAM_FLAGS  (G_PARAM_READWRITE \
                                 | G_PARAM_CONSTRUCT \
@@ -305,6 +318,20 @@ xfce_backdrop_class_init(XfceBackdropClass *klass)
                                                         -10.0, 10.0, 1.0,
                                                         XFDESKTOP_PARAM_FLAGS));
 
+    g_object_class_install_property(gobject_class, PROP_BACKDROP_CYCLE_ENABLE,
+                                    g_param_spec_boolean("backdrop-cycle-enable",
+                                                         "backdrop-cycle-enable",
+                                                         "backdrop-cycle-enable",
+                                                         FALSE,
+                                                         XFDESKTOP_PARAM_FLAGS));
+
+    g_object_class_install_property(gobject_class, PROP_BACKDROP_CYCLE_TIMER,
+                                    g_param_spec_uint("backdrop-cycle-timer",
+                                                     "backdrop-cycle-timer",
+                                                     "backdrop-cycle-timer",
+                                                     0, G_MAXUSHORT, 10,
+                                                     XFDESKTOP_PARAM_FLAGS));
+
 #undef XFDESKTOP_PARAM_FLAGS
 }
 
@@ -314,6 +341,8 @@ xfce_backdrop_init(XfceBackdrop *backdrop)
     backdrop->priv = G_TYPE_INSTANCE_GET_PRIVATE(backdrop, XFCE_TYPE_BACKDROP,
                                                  XfceBackdropPriv);
     backdrop->priv->show_image = TRUE;
+    backdrop->priv->cycle_timer_id = 0;
+    backdrop->priv->backdrop_list = NULL;
 
     /* color defaults */
     backdrop->priv->color1.red = 0x1515;
@@ -333,7 +362,17 @@ xfce_backdrop_finalize(GObject *object)
     
     if(backdrop->priv->image_path)
         g_free(backdrop->priv->image_path);
-    
+
+    if(backdrop->priv->cycle_timer_id != 0) {
+        g_source_remove(backdrop->priv->cycle_timer_id);
+        backdrop->priv->cycle_timer_id = 0;
+    }
+
+    if(backdrop->priv->backdrop_list != NULL) {
+        g_free(backdrop->priv->backdrop_list);
+        backdrop->priv->backdrop_list = NULL;
+    }
+
     G_OBJECT_CLASS(xfce_backdrop_parent_class)->finalize(object);
 }
 
@@ -384,6 +423,14 @@ xfce_backdrop_set_property(GObject *object,
             xfce_backdrop_set_saturation(backdrop, g_value_get_double(value));
             break;
 
+        case PROP_BACKDROP_CYCLE_ENABLE:
+            xfce_backdrop_set_cycle_backdrop(backdrop, g_value_get_boolean(value));
+            break;
+
+        case PROP_BACKDROP_CYCLE_TIMER:
+            xfce_backdrop_set_cycle_timer(backdrop, g_value_get_uint(value));
+            break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
             break;
@@ -432,6 +479,14 @@ xfce_backdrop_get_property(GObject *object,
             g_value_set_double(value, xfce_backdrop_get_saturation(backdrop));
             break;
 
+        case PROP_BACKDROP_CYCLE_ENABLE:
+            g_value_set_boolean(value, xfce_backdrop_get_cycle_backdrop(backdrop));
+            break;
+
+        case PROP_BACKDROP_CYCLE_TIMER:
+            g_value_set_uint(value, xfce_backdrop_get_cycle_timer(backdrop));
+            break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
             break;
@@ -701,6 +756,37 @@ xfce_backdrop_get_image_filename(XfceBackdrop *backdrop)
 }
 
 /**
+ * xfce_backdrop_set_list:
+ * @backdrop: An #XfceBackdrop.
+ * @backdrop_list: A list of backdrop images.
+ *
+ * Sets the internal list of wallpaper images assigned to this backdrop.
+ * Frees any previous backdrop list before setting the new one.
+ * [Transfer full]
+ **/
+void
+xfce_backdrop_set_list(XfceBackdrop *backdrop,
+                       gchar *backdrop_list)
+{
+    g_return_if_fail(XFCE_IS_BACKDROP(backdrop));
+
+    if(backdrop->priv->backdrop_list != NULL) {
+        g_free(backdrop->priv->backdrop_list);
+        backdrop->priv->backdrop_list = NULL;
+    }
+
+    backdrop->priv->backdrop_list = backdrop_list;
+}
+
+G_CONST_RETURN gchar*
+xfce_backdrop_get_list(XfceBackdrop *backdrop)
+{
+    g_return_val_if_fail(XFCE_IS_BACKDROP(backdrop), NULL);
+
+    return backdrop->priv->backdrop_list;
+}
+
+/**
  * xfce_backdrop_set_brightness:
  * @backdrop: An #XfceBackdrop.
  * @brightness: A brightness value.
@@ -745,6 +831,76 @@ xfce_backdrop_get_saturation(XfceBackdrop *backdrop)
     return backdrop->priv->saturation;
 }
 
+static void
+xfce_backdrop_timer(XfceBackdrop *backdrop)
+{
+    g_return_if_fail(XFCE_IS_BACKDROP(backdrop));
+
+    g_signal_emit(G_OBJECT(backdrop), backdrop_signals[BACKDROP_CYCLE], 0);
+}
+
+/**
+ * xfce_backdrop_set_cycle_timer:
+ * @backdrop: An #XfceBackdrop.
+ * @cycle_timer: The amount of time, in minutes, to wait before changing the
+ *               background image.
+ *
+ * If cycle_backdrop is enabled then this function will change the backdrop
+ * image based on the cycle_timer, a value between 0 and G_MAXUSHORT.
+ * A value of 0 indicates that the backdrop should not be changed.
+ **/
+void
+xfce_backdrop_set_cycle_timer(XfceBackdrop *backdrop, guint cycle_timer)
+{
+    g_return_if_fail(XFCE_IS_BACKDROP(backdrop));
+
+    if(cycle_timer > G_MAXUSHORT)
+        cycle_timer = G_MAXUSHORT;
+
+    backdrop->priv->cycle_timer = cycle_timer;
+
+    if(backdrop->priv->cycle_timer_id != 0) {
+        g_source_remove(backdrop->priv->cycle_timer_id);
+        backdrop->priv->cycle_timer_id = 0;
+    }
+
+    if(backdrop->priv->cycle_timer != 0 &&
+       backdrop->priv->cycle_backdrop == TRUE) {
+        backdrop->priv->cycle_timer_id = g_timeout_add_seconds(backdrop->priv->cycle_timer * 60,
+                                                               (GSourceFunc)xfce_backdrop_timer,
+                                                               backdrop);
+    }
+}
+
+guint
+xfce_backdrop_get_cycle_timer(XfceBackdrop *backdrop)
+{
+    g_return_val_if_fail(XFCE_IS_BACKDROP(backdrop), 0);
+    return backdrop->priv->cycle_timer;
+}
+
+void
+xfce_backdrop_set_cycle_backdrop(XfceBackdrop *backdrop,
+                                 gboolean cycle_backdrop)
+{
+    g_return_if_fail(XFCE_IS_BACKDROP(backdrop));
+
+    if(backdrop->priv->cycle_backdrop != cycle_backdrop) {
+        backdrop->priv->cycle_backdrop = cycle_backdrop;
+        /* Start or stop the backdrop changing */
+        xfce_backdrop_set_cycle_timer(backdrop,
+                                      xfce_backdrop_get_cycle_timer(backdrop));
+    }
+}
+
+gboolean
+xfce_backdrop_get_cycle_backdrop(XfceBackdrop *backdrop)
+{
+    g_return_val_if_fail(XFCE_IS_BACKDROP(backdrop), 0);
+
+    return backdrop->priv->cycle_backdrop;
+}
+
 /**
  * xfce_backdrop_get_pixbuf:
  * @backdrop: An #XfceBackdrop.
diff --git a/src/xfce-backdrop.h b/src/xfce-backdrop.h
index d193644..78ba6b0 100644
--- a/src/xfce-backdrop.h
+++ b/src/xfce-backdrop.h
@@ -70,6 +70,7 @@ struct _XfceBackdropClass
     
     /*< signals >*/
     void (*changed)(XfceBackdrop *backdrop);
+    void (*cycle)(XfceBackdrop *backdrop);
 };
 
 GType xfce_backdrop_get_type             (void) G_GNUC_CONST;
@@ -113,6 +114,11 @@ void xfce_backdrop_set_image_filename    (XfceBackdrop *backdrop,
 G_CONST_RETURN gchar *xfce_backdrop_get_image_filename
                                          (XfceBackdrop *backdrop);
 
+void xfce_backdrop_set_list              (XfceBackdrop *backdrop,
+                                          gchar *backdrop_list);
+G_CONST_RETURN gchar *xfce_backdrop_get_list
+                                         (XfceBackdrop *backdrop);
+
 void xfce_backdrop_set_brightness        (XfceBackdrop *backdrop,
                                           gint brightness);
 gint xfce_backdrop_get_brightness        (XfceBackdrop *backdrop);
@@ -121,6 +127,14 @@ void xfce_backdrop_set_saturation        (XfceBackdrop *backdrop,
                                           gdouble saturation);
 gdouble xfce_backdrop_get_saturation     (XfceBackdrop *backdrop);
 
+void xfce_backdrop_set_cycle_backdrop    (XfceBackdrop *backdrop,
+                                          gboolean cycle_backdrop);
+gboolean xfce_backdrop_get_cycle_backdrop(XfceBackdrop *backdrop);
+
+void xfce_backdrop_set_cycle_timer       (XfceBackdrop *backdrop,
+                                          guint cycle_timer);
+guint xfce_backdrop_get_cycle_timer      (XfceBackdrop *backdrop);
+
 GdkPixbuf *xfce_backdrop_get_pixbuf      (XfceBackdrop *backdrop);
 
 G_END_DECLS
diff --git a/src/xfce-desktop.c b/src/xfce-desktop.c
index cd98ae7..b1ad65f 100644
--- a/src/xfce-desktop.c
+++ b/src/xfce-desktop.c
@@ -335,14 +335,29 @@ backdrop_changed_cb(XfceBackdrop *backdrop, gpointer user_data)
     pix = xfce_backdrop_get_pixbuf(backdrop);
     if(!pix)
         return;
-    
-    if(desktop->priv->nbackdrops == 1) {
-        /* single monitor */
-        rect.x = rect.y = 0;
+
+    if(desktop->priv->xinerama_stretch) {
+        GdkRectangle monitor_rect;
+
+        gdk_screen_get_monitor_geometry(gscreen, 0, &rect);
+
+        /* Get the lowest x and y value for all the monitors in
+         * case none of them start at 0,0 for whatever reason.
+         */
+        for(i = 1; i < (guint)gdk_screen_get_n_monitors(gscreen); i++) {
+            gdk_screen_get_monitor_geometry(gscreen, i, &monitor_rect);
+
+            if(monitor_rect.x < rect.x)
+                rect.x = monitor_rect.x;
+            if(monitor_rect.y < rect.y)
+                rect.y = monitor_rect.y;
+        }
+
         rect.width = gdk_screen_get_width(gscreen);
         rect.height = gdk_screen_get_height(gscreen);
-    } else
+    } else {
         gdk_screen_get_monitor_geometry(gscreen, monitor, &rect);
+    }
 
     gdk_draw_pixbuf(GDK_DRAWABLE(pmap), GTK_WIDGET(desktop)->style->black_gc,
                     pix, 0, 0, rect.x, rect.y,
@@ -363,6 +378,28 @@ backdrop_changed_cb(XfceBackdrop *backdrop, gpointer user_data)
 }
 
 static void
+backdrop_cycle_cb(XfceBackdrop *backdrop, gpointer user_data)
+{
+    const gchar* backdrop_list;
+
+    g_return_if_fail(XFCE_IS_BACKDROP(backdrop));
+
+    backdrop_list = xfce_backdrop_get_list(backdrop);
+
+    if(xfdesktop_backdrop_list_is_valid(backdrop_list)) {
+        gchar *backdrop_file;
+        GError *error = NULL;
+
+        backdrop_file = xfdesktop_backdrop_list_choose_random(backdrop_list,
+                                                              &error);
+
+        xfce_backdrop_set_image_filename(backdrop, backdrop_file);
+        g_free(backdrop_file);
+        backdrop_changed_cb(backdrop, user_data);
+    }
+}
+
+static void
 screen_size_changed_cb(GdkScreen *gscreen, gpointer user_data)
 {
     XfceDesktop *desktop = user_data;
@@ -434,6 +471,9 @@ xfce_desktop_monitors_changed(GdkScreen *gscreen,
                 g_signal_connect(G_OBJECT(desktop->priv->backdrops[0]),
                                  "changed",
                                  G_CALLBACK(backdrop_changed_cb), desktop);
+                g_signal_connect(G_OBJECT(desktop->priv->backdrops[0]),
+                                 "cycle",
+                                 G_CALLBACK(backdrop_cycle_cb), desktop);
             }
             desktop->priv->nbackdrops = 1;
         }
@@ -459,6 +499,10 @@ xfce_desktop_monitors_changed(GdkScreen *gscreen,
                                      "changed",
                                      G_CALLBACK(backdrop_changed_cb),
                                      desktop);
+                    g_signal_connect(G_OBJECT(desktop->priv->backdrops[i]),
+                                     "cycle",
+                                     G_CALLBACK(backdrop_cycle_cb),
+                                     desktop);
                 }
             }
             desktop->priv->nbackdrops = n_monitors;
@@ -626,7 +670,7 @@ xfce_desktop_finalize(GObject *object)
     
     g_object_unref(G_OBJECT(desktop->priv->channel));
     g_free(desktop->priv->property_prefix);
-    
+
     G_OBJECT_CLASS(xfce_desktop_parent_class)->finalize(object);
 }
 
@@ -853,18 +897,20 @@ xfce_desktop_button_press_event(GtkWidget *w,
 {
     guint button = evt->button;
     guint state = evt->state;
-    
+    g_return_val_if_fail(XFCE_IS_DESKTOP(w), FALSE);
+
     if(evt->type == GDK_BUTTON_PRESS) {
-        if(button == 2 || (button == 1 && (state & GDK_SHIFT_MASK)
-                           && (state & GDK_CONTROL_MASK)))
+        if(XFCE_DESKTOP(w)->priv->icons_style == XFCE_DESKTOP_ICON_STYLE_NONE
+           && (button == 3 || (button == 1 && (state & GDK_SHIFT_MASK)))) {
+            xfce_desktop_popup_root_menu(XFCE_DESKTOP(w),
+                                         button,
+                                         evt->time);
+        } else if(button == 2 || (button == 1 && (state & GDK_SHIFT_MASK)
+                                  && (state & GDK_CONTROL_MASK)))
         {
             xfce_desktop_popup_secondary_root_menu(XFCE_DESKTOP(w),
                                                    button, evt->time);
             return TRUE;
-        } else if(button == 3 || (button == 1 && (state & GDK_SHIFT_MASK))) {
-            xfce_desktop_popup_root_menu(XFCE_DESKTOP(w),
-                                         button, evt->time);
-            return TRUE;
         }
     }
     
@@ -1033,8 +1079,13 @@ xfce_desktop_image_filename_changed(XfconfChannel *channel,
 
             xfce_backdrop_set_image_filename(backdrop, backdrop_file);
             g_free(backdrop_file);
-        } else
+
+            xfce_backdrop_set_list(backdrop, g_strdup(filename));
+        } else {
             xfce_backdrop_set_image_filename(backdrop, filename);
+
+            xfce_backdrop_set_list(backdrop, NULL);
+        }
     }
 }
 
@@ -1086,6 +1137,16 @@ xfce_desktop_connect_backdrop_settings(XfceDesktop *desktop,
     xfconf_g_property_bind(channel, buf, G_TYPE_DOUBLE,
                            G_OBJECT(backdrop), "saturation");
 
+    buf[pp_len] = 0;
+    g_strlcat(buf, "backdrop-cycle-enable", sizeof(buf));
+    xfconf_g_property_bind(channel, buf, G_TYPE_BOOLEAN,
+                           G_OBJECT(backdrop), "backdrop-cycle-enable");
+
+    buf[pp_len] = 0;
+    g_strlcat(buf, "backdrop-cycle-timer", sizeof(buf));
+    xfconf_g_property_bind(channel, buf, G_TYPE_UINT,
+                           G_OBJECT(backdrop), "backdrop-cycle-timer");
+
     /* the image filename could be an image or a backdrop list, so we
      * can't just bind the property directly */
     buf[pp_len] = 0;
@@ -1340,29 +1401,29 @@ xfce_desktop_do_menu_popup(XfceDesktop *desktop,
         screen = gtk_widget_get_screen(GTK_WIDGET(desktop));
     else
         screen = gdk_display_get_default_screen(gdk_display_get_default());
-    
-    menu = gtk_menu_new();
-    gtk_menu_set_screen(GTK_MENU(menu), screen);
-    g_signal_connect_swapped(G_OBJECT(menu), "deactivate",
-                             G_CALLBACK(g_idle_add),
-                             (gpointer)xfce_desktop_menu_destroy_idled);
-    
-    g_signal_emit(G_OBJECT(desktop), populate_signal, 0, menu);
-    
-    /* if nobody populated the menu, don't do anything */
-    menu_children = gtk_container_get_children(GTK_CONTAINER(menu));
-    if(!menu_children) {
-        gtk_widget_destroy(menu);
-        return;
-    }
-    
-    g_list_free(menu_children);
-    
-    gtk_menu_attach_to_widget(GTK_MENU(menu), GTK_WIDGET(desktop), NULL);
-    
+
     if(xfdesktop_popup_grab_available(gdk_screen_get_root_window(screen),
                                       activate_time))
     {
+        menu = gtk_menu_new();
+        gtk_menu_set_screen(GTK_MENU(menu), screen);
+        g_signal_connect_swapped(G_OBJECT(menu), "deactivate",
+                                 G_CALLBACK(g_idle_add),
+                                 (gpointer)xfce_desktop_menu_destroy_idled);
+
+        g_signal_emit(G_OBJECT(desktop), populate_signal, 0, menu);
+
+        /* if nobody populated the menu, don't do anything */
+        menu_children = gtk_container_get_children(GTK_CONTAINER(menu));
+        if(!menu_children) {
+            gtk_widget_destroy(menu);
+            return;
+        }
+
+        g_list_free(menu_children);
+
+        gtk_menu_attach_to_widget(GTK_MENU(menu), GTK_WIDGET(desktop), NULL);
+
         /* bug #3652: for some reason passing the correct button here breaks
          * on some systems but not others.  always pass 0 for now. */
         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0,
@@ -1428,3 +1489,14 @@ xfce_desktop_refresh(XfceDesktop *desktop)
     xfce_desktop_setup_icon_view(desktop);
 #endif
 }
+
+void xfce_desktop_arrange_icons(XfceDesktop *desktop)
+{
+    g_return_if_fail(XFCE_IS_DESKTOP(desktop));
+
+#ifdef ENABLE_DESKTOP_ICONS
+    g_return_if_fail(XFDESKTOP_IS_ICON_VIEW(desktop->priv->icon_view));
+
+    xfdesktop_icon_view_sort_icons(XFDESKTOP_ICON_VIEW(desktop->priv->icon_view));
+#endif
+}
diff --git a/src/xfce-desktop.h b/src/xfce-desktop.h
index d3173ed..a9224af 100644
--- a/src/xfce-desktop.h
+++ b/src/xfce-desktop.h
@@ -116,6 +116,8 @@ void xfce_desktop_popup_secondary_root_menu(XfceDesktop *desktop,
 
 void xfce_desktop_refresh(XfceDesktop *desktop);
 
+void xfce_desktop_arrange_icons(XfceDesktop *desktop);
+
 G_END_DECLS
 
 #endif
diff --git a/src/xfdesktop-clipboard-manager.c b/src/xfdesktop-clipboard-manager.c
index 76b4bef..ed90aa0 100644
--- a/src/xfdesktop-clipboard-manager.c
+++ b/src/xfdesktop-clipboard-manager.c
@@ -307,7 +307,6 @@ xfdesktop_clipboard_manager_owner_changed (GtkClipboard           *clipboard,
 }
 
 
-#if 0
 static void
 xfdesktop_clipboard_manager_contents_received (GtkClipboard     *clipboard,
                                             GtkSelectionData *selection_data,
@@ -318,6 +317,8 @@ xfdesktop_clipboard_manager_contents_received (GtkClipboard     *clipboard,
   GtkWindow                      *parent = GTK_WINDOW(gtk_widget_get_toplevel(request->widget));
   gboolean                        path_copy = TRUE;
   GList                          *path_list = NULL;
+  GList                          *dest_file_list  = NULL;
+  GList                          *l               = NULL;
   gchar                          *data;
 
   /* check whether the retrieval worked */
@@ -340,19 +341,43 @@ xfdesktop_clipboard_manager_contents_received (GtkClipboard     *clipboard,
         }
 
       /* determine the path list stored with the selection */
-      path_list = thunar_vfs_path_list_from_string (data, NULL);
+      path_list = xfdesktop_file_utils_file_list_from_string (data);
     }
 
   /* perform the action if possible */
   if (G_LIKELY (path_list != NULL))
     {
+      for (l = path_list; l; l = l->next) {
+        gchar *dest_basename = g_file_get_basename(l->data);
+
+        if(dest_basename && *dest_basename != '\0') {
+          /* If we copy a file, we need to use the new absolute filename
+           * as the destination. If we move, we need to use the destination
+           * directory. */
+           if(path_copy) {
+             GFile *dest_file = g_file_get_child(request->target_file, dest_basename);
+             dest_file_list = g_list_prepend(dest_file_list, dest_file);
+           } else {
+             dest_file_list = g_list_prepend(dest_file_list, request->target_file);
+           }
+         }
+         g_free(dest_basename);
+      }
+
+      dest_file_list = g_list_reverse(dest_file_list);
+
       if (G_LIKELY (path_copy))
-        xfdesktop_file_utils_copy_into(parent, path_list, request->target_path);
-        //thunar_application_copy_into (application, request->widget, path_list, request->target_path, request->new_files_closure);
-      else
-        xfdesktop_file_utils_move_into(parent, path_list, request->target_path);
-        //thunar_application_move_into (application, request->widget, path_list, request->target_path, request->new_files_closure);
-      thunar_vfs_path_list_free (path_list);
+      {
+        xfdesktop_file_utils_transfer_files(GDK_ACTION_COPY,
+                                            path_list,
+                                            dest_file_list,
+                                            gtk_widget_get_screen(GTK_WIDGET(parent)));
+      } else {
+        xfdesktop_file_utils_transfer_files(GDK_ACTION_MOVE,
+                                            path_list,
+                                            dest_file_list,
+                                            gtk_widget_get_screen(GTK_WIDGET(parent)));
+      }
 
       /* clear the clipboard if it contained "cutted data"
        * (gtk_clipboard_clear takes care of not clearing
@@ -365,18 +390,11 @@ xfdesktop_clipboard_manager_contents_received (GtkClipboard     *clipboard,
        * if either the Xserver or our GTK+ version
        * doesn't support the XFixes extension.
        */
-#if GTK_CHECK_VERSION(2,6,0)
       if (!gdk_display_supports_selection_notification (gtk_clipboard_get_display (manager->clipboard)))
-#endif
         {
           xfdesktop_clipboard_manager_owner_changed (manager->clipboard, NULL, manager);
         }
     }
-  else
-    {
-      /* tell the user that we cannot paste */
-//      thunar_dialogs_show_error (request->widget, NULL, _("There is nothing on the clipboard to paste"));
-    }
 
   /* free the request */
   if (G_LIKELY (request->widget != NULL))
@@ -384,10 +402,11 @@ xfdesktop_clipboard_manager_contents_received (GtkClipboard     *clipboard,
   if (G_LIKELY (request->new_files_closure != NULL))
     g_closure_unref (request->new_files_closure);
   g_object_unref (G_OBJECT (request->manager));
-  thunar_vfs_path_unref (request->target_path);
-  g_free (request);
+
+  g_list_free(dest_file_list);
+  g_list_free(path_list);
 }
-#endif
+
 
 
 static void
@@ -654,6 +673,61 @@ xfdesktop_clipboard_manager_cut_files (XfdesktopClipboardManager *manager,
 gboolean
 xfdesktop_clipboard_manager_get_can_paste (XfdesktopClipboardManager *manager)
 {
-    /* FIXME: implement */
-    return FALSE;
+    g_return_val_if_fail (XFDESKTOP_IS_CLIPBOARD_MANAGER (manager), FALSE);
+    return manager->can_paste;
+}
+
+
+/**
+ * thunar_clipboard_manager_paste_files:
+ * @manager           : a #XfdesktopClipboardManager.
+ * @target_file       : the #GFile of the folder to which the contents on the clipboard
+ *                      should be pasted.
+ * @widget            : a #GtkWidget, on which to perform the paste or %NULL if no widget is
+ *                      known.
+ * @new_files_closure : a #GClosure to connect to the job's "new-files" signal,
+ *                      which will be emitted when the job finishes with the
+ *                      list of #GFile<!---->s created by the job, or
+ *                      %NULL if you're not interested in the signal.
+ *
+ * Pastes the contents from the clipboard associated with @manager to the directory
+ * referenced by @target_file.
+ * Code copied and adapted from thunar-clipboard-manager.c
+ * Copyright (c) 2005-2006 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at xfce.org>
+ **/
+void
+xfdesktop_clipboard_manager_paste_files (XfdesktopClipboardManager *manager,
+                                      GFile                  *target_file,
+                                      GtkWidget              *widget,
+                                      GClosure               *new_files_closure)
+{
+  XfdesktopClipboardPasteRequest *request;
+
+  g_return_if_fail (XFDESKTOP_IS_CLIPBOARD_MANAGER (manager));
+  g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
+
+  /* prepare the paste request */
+  request = g_slice_new0 (XfdesktopClipboardPasteRequest);
+  request->manager = g_object_ref (G_OBJECT (manager));
+  request->target_file = g_object_ref (target_file);
+  request->widget = widget;
+
+  /* take a reference on the closure (if any) */
+  if (G_LIKELY (new_files_closure != NULL))
+    {
+      request->new_files_closure = new_files_closure;
+      g_closure_ref (new_files_closure);
+      g_closure_sink (new_files_closure);
+    }
+
+  /* get notified when the widget is destroyed prior to
+   * completing the clipboard contents retrieval
+   */
+  if (G_LIKELY (request->widget != NULL))
+    g_object_add_weak_pointer (G_OBJECT (request->widget), (gpointer) &request->widget);
+
+  /* schedule the request */
+  gtk_clipboard_request_contents (manager->clipboard, manager->x_special_gnome_copied_files,
+                                  xfdesktop_clipboard_manager_contents_received, request);
 }
diff --git a/src/xfdesktop-file-icon-manager.c b/src/xfdesktop-file-icon-manager.c
index d3ca2eb..0c6b244 100644
--- a/src/xfdesktop-file-icon-manager.c
+++ b/src/xfdesktop-file-icon-manager.c
@@ -71,6 +71,7 @@
 #include "xfdesktop-special-file-icon.h"
 #include "xfdesktop-trash-proxy.h"
 #include "xfdesktop-volume-icon.h"
+#include "xfdesktop-thumbnailer.h"
 
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
@@ -82,6 +83,7 @@
 #define SETTING_SHOW_HOME        "/desktop-icons/file-icons/show-home"
 #define SETTING_SHOW_TRASH       "/desktop-icons/file-icons/show-trash"
 #define SETTING_SHOW_REMOVABLE   "/desktop-icons/file-icons/show-removable"
+#define SETTING_SHOW_THUMBNAILS  "/desktop-icons/show-thumbnails"
 
 enum
 {
@@ -91,6 +93,7 @@ enum
     PROP_SHOW_HOME,
     PROP_SHOW_TRASH,
     PROP_SHOW_REMOVABLE,
+    PROP_SHOW_THUMBNAILS
 };
 
 struct _XfdesktopFileIconManagerPrivate
@@ -117,6 +120,7 @@ struct _XfdesktopFileIconManagerPrivate
     
     gboolean show_removable_media;
     gboolean show_special[XFDESKTOP_SPECIAL_FILE_ICON_TRASH+1];
+    gboolean show_thumbnails;
     
     guint save_icons_id;
     
@@ -129,6 +133,8 @@ struct _XfdesktopFileIconManagerPrivate
     GList *thunarx_menu_providers;
     GList *thunarx_properties_providers;
 #endif
+
+    XfdesktopThumbnailer *thumbnailer;
 };
 
 static void xfdesktop_file_icon_manager_set_property(GObject *object,
@@ -175,6 +181,10 @@ static void xfdesktop_file_icon_manager_remove_removable_media(XfdesktopFileIcon
 static void xfdesktop_file_icon_position_changed(XfdesktopFileIcon *icon,
                                                  gpointer user_data);
 
+static void xfdesktop_file_icon_manager_update_image(GtkWidget *widget,
+                                                     gchar *srcfile,
+                                                     gchar *thumbfile,
+                                                     XfdesktopFileIconManager *fmanager);
 
 G_DEFINE_TYPE_EXTENDED(XfdesktopFileIconManager,
                        xfdesktop_file_icon_manager,
@@ -264,6 +274,12 @@ xfdesktop_file_icon_manager_class_init(XfdesktopFileIconManagerClass *klass)
                                                          "show removable",
                                                          TRUE,
                                                          XFDESKTOP_PARAM_FLAGS));
+    g_object_class_install_property(gobject_class, PROP_SHOW_THUMBNAILS,
+                                    g_param_spec_boolean("show-thumbnails",
+                                                         "show-thumbnails",
+                                                         "show-thumbnails",
+                                                         TRUE,
+                                                         XFDESKTOP_PARAM_FLAGS));
 #undef XFDESKTOP_PARAM_FLAGS
 
     xfdesktop_app_info_quark = g_quark_from_static_string("xfdesktop-app-info-quark");
@@ -282,6 +298,10 @@ xfdesktop_file_icon_manager_init(XfdesktopFileIconManager *fmanager)
                                                        n_drag_targets);
     fmanager->priv->drop_targets = gtk_target_list_new(drop_targets,
                                                        n_drop_targets);
+
+    fmanager->priv->thumbnailer = xfdesktop_thumbnailer_new();
+
+    g_signal_connect(G_OBJECT(fmanager->priv->thumbnailer), "thumbnail-ready", G_CALLBACK(xfdesktop_file_icon_manager_update_image), fmanager);
 }
 
 static void
@@ -321,6 +341,11 @@ xfdesktop_file_icon_manager_set_property(GObject *object,
                                                                  g_value_get_boolean(value));
             break;
 
+        case PROP_SHOW_THUMBNAILS:
+            xfdesktop_file_icon_manager_set_show_thumbnails(fmanager,
+                                                            g_value_get_boolean(value));
+            break;
+
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
     }
@@ -357,6 +382,10 @@ xfdesktop_file_icon_manager_get_property(GObject *object,
         case PROP_SHOW_REMOVABLE:
             g_value_set_boolean(value, fmanager->priv->show_removable_media);
             break;
+
+        case PROP_SHOW_THUMBNAILS:
+            g_value_set_boolean(value, fmanager->priv->show_thumbnails);
+            break;
         
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
@@ -377,6 +406,7 @@ xfdesktop_file_icon_manager_finalize(GObject *obj)
     gtk_target_list_unref(fmanager->priv->drop_targets);
     
     g_object_unref(fmanager->priv->folder);
+    g_object_unref(fmanager->priv->thumbnailer);
     
     G_OBJECT_CLASS(xfdesktop_file_icon_manager_parent_class)->finalize(obj);
 }
@@ -400,8 +430,10 @@ __migrate_old_icon_positions(XfdesktopFileIconManager *fmanager)
 {
     gchar relpath[PATH_MAX], *old_file;
     
-    g_snprintf(relpath, PATH_MAX, "xfce4/desktop/icons.screen%d.rc",
-               gdk_screen_get_number(fmanager->priv->gscreen));
+    g_snprintf(relpath, PATH_MAX, "xfce4/desktop/icons.screen%d-%dx%d.rc",
+               gdk_screen_get_number(fmanager->priv->gscreen),
+               gdk_screen_get_width(fmanager->priv->gscreen),
+               gdk_screen_get_height(fmanager->priv->gscreen));
     
     old_file = xfce_resource_save_location(XFCE_RESOURCE_CACHE, relpath, FALSE);
     
@@ -858,6 +890,23 @@ xfdesktop_file_icon_menu_delete(GtkWidget *widget,
 }
 
 static void
+xfdesktop_file_icon_menu_paste(GtkWidget *widget,
+                               gpointer user_data)
+{
+    XfdesktopFileIconManager *fmanager = XFDESKTOP_FILE_ICON_MANAGER(user_data);
+    if(widget && fmanager)
+        xfdesktop_clipboard_manager_paste_files(clipboard_manager, fmanager->priv->folder, widget, NULL);
+}
+
+static void
+xfdesktop_file_icon_menu_arrange_icons(GtkWidget *widget,
+                                       gpointer user_data)
+{
+    XfdesktopFileIconManager *fmanager = XFDESKTOP_FILE_ICON_MANAGER(user_data);
+    xfdesktop_icon_view_sort_icons(fmanager->priv->icon_view);
+}
+
+static void
 xfdesktop_file_icon_menu_properties(GtkWidget *widget,
                                     gpointer user_data)
 {
@@ -1616,7 +1665,11 @@ xfdesktop_file_icon_manager_populate_context_menu(XfceDesktop *desktop,
             mi = gtk_image_menu_item_new_from_stock(GTK_STOCK_PASTE, NULL);
             gtk_widget_show(mi);
             gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
-            /* FIXME: implement */
+            if(xfdesktop_clipboard_manager_get_can_paste(clipboard_manager)) {
+                g_signal_connect(G_OBJECT(mi), "activate",
+                                 G_CALLBACK(xfdesktop_file_icon_menu_paste),
+                                 fmanager);
+            } else
             gtk_widget_set_sensitive(mi, FALSE);
         } else {
             mi = gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY, NULL);
@@ -1666,6 +1719,16 @@ xfdesktop_file_icon_manager_populate_context_menu(XfceDesktop *desktop,
         gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
         
         if(file_icon == fmanager->priv->desktop_icon) {
+            img = gtk_image_new_from_stock(GTK_STOCK_SORT_ASCENDING, GTK_ICON_SIZE_MENU);
+            gtk_widget_show(img);
+            mi = gtk_image_menu_item_new_with_mnemonic(_("_Arrange Desktop Icons"));
+            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
+            gtk_widget_show(mi);
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
+            g_signal_connect(G_OBJECT(mi), "activate",
+                             G_CALLBACK(xfdesktop_file_icon_menu_arrange_icons),
+                             fmanager);
+
             img = gtk_image_new_from_stock(GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU);
             gtk_widget_show(img);
             mi = gtk_image_menu_item_new_with_mnemonic(_("Desktop _Settings..."));
@@ -1718,11 +1781,22 @@ xfdesktop_file_icon_manager_save_icons(gpointer user_data)
     XfdesktopFileIconManager *fmanager = XFDESKTOP_FILE_ICON_MANAGER(user_data);
     gchar relpath[PATH_MAX], *tmppath, *path;
     XfceRc *rcfile;
+    gint x = 0, y = 0, width = 0, height = 0;
     
     fmanager->priv->save_icons_id = 0;
-    
-    g_snprintf(relpath, PATH_MAX, "xfce4/desktop/icons.screen%d.rc",
-               gdk_screen_get_number(fmanager->priv->gscreen));
+
+    xfdesktop_get_workarea_single(fmanager->priv->icon_view,
+                                  0,
+                                  &x,
+                                  &y,
+                                  &width,
+                                  &height);
+
+    g_snprintf(relpath, PATH_MAX, "xfce4/desktop/icons.screen%d-%dx%d.rc",
+               gdk_screen_get_number(fmanager->priv->gscreen),
+               width,
+               height);
+
     path = xfce_resource_save_location(XFCE_RESOURCE_CONFIG, relpath, TRUE);
     if(!path)
         return FALSE;
@@ -1779,20 +1853,42 @@ xfdesktop_file_icon_position_changed(XfdesktopFileIcon *icon,
 
 /*   *****   */
 
-static gboolean
+gboolean
 xfdesktop_file_icon_manager_get_cached_icon_position(XfdesktopFileIconManager *fmanager,
                                                      const gchar *name,
                                                      gint16 *row,
                                                      gint16 *col)
 {
     gchar relpath[PATH_MAX];
-    XfceRc *rcfile;
+    gchar *filename = NULL;
     gboolean ret = FALSE;
-    
-    g_snprintf(relpath, PATH_MAX, "xfce4/desktop/icons.screen%d.rc",
-               gdk_screen_get_number(fmanager->priv->gscreen));
-    rcfile = xfce_rc_config_open(XFCE_RESOURCE_CONFIG, relpath, TRUE);
-    if(rcfile) {
+    gint x = 0, y = 0, width = 0, height = 0;
+
+    xfdesktop_get_workarea_single(fmanager->priv->icon_view,
+                                  0,
+                                  &x,
+                                  &y,
+                                  &width,
+                                  &height);
+    
+    g_snprintf(relpath, PATH_MAX, "xfce4/desktop/icons.screen%d-%dx%d.rc",
+               gdk_screen_get_number(fmanager->priv->gscreen),
+               width,
+               height);
+
+    filename = xfce_resource_lookup(XFCE_RESOURCE_CONFIG, relpath);
+
+    /* Check if we have to migrate from the old file format */
+    if(filename == NULL) {
+        g_snprintf(relpath, PATH_MAX, "xfce4/desktop/icons.screen%d.rc",
+        gdk_screen_get_number(fmanager->priv->gscreen));
+        filename = xfce_resource_lookup(XFCE_RESOURCE_CONFIG, relpath);
+    }
+
+    if(filename != NULL) {
+        XfceRc *rcfile;
+        rcfile = xfce_rc_simple_open(filename, TRUE);
+
         if(xfce_rc_has_group(rcfile, name)) {
             xfce_rc_set_group(rcfile, name);
             *row = xfce_rc_read_int_entry(rcfile, "row", -1);
@@ -1801,6 +1897,7 @@ xfdesktop_file_icon_manager_get_cached_icon_position(XfdesktopFileIconManager *f
                 ret = TRUE;
         }
         xfce_rc_close(rcfile);
+        g_free(filename);
     }
     
     return ret;
@@ -1829,6 +1926,15 @@ xfdesktop_file_icon_manager_add_icon(XfdesktopFileIconManager *fmanager,
     gint16 row = -1, col = -1;
     gboolean do_add = FALSE;
     const gchar *name;
+    GFile *file;
+
+    file = xfdesktop_file_icon_peek_file(icon);
+
+    if(fmanager->priv->show_thumbnails && g_file_get_path(file) != NULL) {
+        xfdesktop_thumbnailer_queue_thumbnail(fmanager->priv->thumbnailer,
+                                              g_file_get_path(file));
+    }
+
     
     name = xfdesktop_icon_peek_label(XFDESKTOP_ICON(icon));
     if(xfdesktop_file_icon_manager_get_cached_icon_position(fmanager, name,
@@ -1839,7 +1945,6 @@ xfdesktop_file_icon_manager_add_icon(XfdesktopFileIconManager *fmanager,
         do_add = TRUE;
     } else {
         if(defer_if_missing) {
-            GFile *file = xfdesktop_file_icon_peek_file(icon);
             fmanager->priv->deferred_icons = g_list_prepend(fmanager->priv->deferred_icons,
                                                             g_object_ref(file));
         } else
@@ -2098,6 +2203,18 @@ xfdesktop_file_icon_manager_key_press(GtkWidget *widget,
             }
             return TRUE;
         
+        case GDK_v:
+        case GDK_V:
+            if(!(evt->state & GDK_CONTROL_MASK)
+               || (evt->state & (GDK_SHIFT_MASK|GDK_MOD1_MASK|GDK_MOD4_MASK)))
+            {
+                return FALSE;
+            }
+            if(xfdesktop_clipboard_manager_get_can_paste(clipboard_manager)) {
+                xfdesktop_clipboard_manager_paste_files(clipboard_manager, fmanager->priv->folder, widget, NULL);
+            }
+            return TRUE;
+
         case GDK_r:
         case GDK_R:
             if(!(evt->state & GDK_CONTROL_MASK)
@@ -2195,6 +2312,13 @@ xfdesktop_file_icon_manager_file_changed(GFileMonitor     *monitor,
 
             icon = g_hash_table_lookup(fmanager->priv->icons, file);
             if(icon) {
+                /* Always try to remove thumbnail so it doesn't take up
+                 * space on the user's disk.
+                 */
+                xfdesktop_thumbnailer_delete_thumbnail(fmanager->priv->thumbnailer,
+                                                       g_file_get_path(file));
+                xfdesktop_icon_delete_thumbnail(XFDESKTOP_ICON(icon));
+
                 xfdesktop_icon_view_remove_item(fmanager->priv->icon_view,
                                                 XFDESKTOP_ICON(icon));
                 g_hash_table_remove(fmanager->priv->icons, file);
@@ -2778,6 +2902,92 @@ xfdesktop_file_icon_manager_drag_drop(XfdesktopIconViewManager *manager,
     return TRUE;
 }
 
+static void xfdesktop_dnd_item(GtkWidget *item, GdkDragAction *action)
+{
+    *action = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(item), "action"));
+}
+
+static void xfdesktop_dnd_item_cancel(GtkWidget *item, GdkDragAction *action)
+{
+    *action = 0;
+}
+
+/**
+ * xfdesktop_dnd_menu:
+ * @manager     : the #XfdesktopIconViewManager instance
+ * @drop_icon   : the #XfdesktopIcon to which is being dropped.
+ * @context     : the #GdkDragContext of the icons being dropped.
+ * @row         : the row on the desktop to drop to.
+ * @col         : the col on the desktop to drop to.
+ * @ time_      : the starting time of the drag event.
+ * Pops up a menu that asks the user to choose one of the
+ * actions or to cancel the drop. Sets context->action to
+ * the new action the user selected or 0 on cancel.
+ * Portions of this code was copied from thunar-dnd.c
+ * Copyright (c) 2005-2006 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at xfce.org>
+ **/
+static void xfdesktop_dnd_menu (XfdesktopIconViewManager *manager,
+                                XfdesktopIcon *drop_icon,
+                                GdkDragContext *context,
+                                guint16 row,
+                                guint16 col,
+                                guint time_)
+{
+    static GdkDragAction    actions[] = { GDK_ACTION_COPY, GDK_ACTION_MOVE, GDK_ACTION_LINK };
+    static const gchar      *action_names[] = { N_ ("Copy _Here") , N_ ("_Move Here") , N_ ("_Link Here") };
+    static const gchar      *action_icons[] = { "stock_folder-copy", "stock_folder-move", NULL };
+    GtkWidget *menu;
+    GtkWidget *item;
+    GtkWidget  *image;
+    guint menu_item, signal_id;
+    GMainLoop *loop;
+    gint response;
+    menu = gtk_menu_new();
+
+    /* This adds the Copy, Move, & Link options */
+    for(menu_item = 0; menu_item < G_N_ELEMENTS(actions); menu_item++) {
+        item = gtk_image_menu_item_new_with_mnemonic(_(action_names[menu_item]));
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+        g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(xfdesktop_dnd_item), &response);
+        g_object_set_data(G_OBJECT(item), "action", GUINT_TO_POINTER(actions[menu_item]));
+        /* add image to the menu item */
+        if(G_LIKELY(action_icons[menu_item] != NULL)) {
+            image = gtk_image_new_from_icon_name(action_icons[menu_item], GTK_ICON_SIZE_MENU);
+            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
+            gtk_widget_show(image);
+        }
+
+        gtk_widget_show(item);
+    }
+
+    /* Add a seperator */
+    item = gtk_separator_menu_item_new();
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+    gtk_widget_show(item);
+
+    /* Cancel option */
+    item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CANCEL, NULL);
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+    g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(xfdesktop_dnd_item_cancel), &response);
+    gtk_widget_show(item);
+
+    gtk_widget_show(menu);
+    g_object_ref_sink(G_OBJECT(menu));
+
+    /* Loop until we get a user response */
+    loop = g_main_loop_new(NULL, FALSE);
+    signal_id = g_signal_connect_swapped(G_OBJECT(menu), "deactivate", G_CALLBACK(g_main_loop_quit), loop);
+    gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, time_);
+    g_main_loop_run(loop);
+    g_signal_handler_disconnect(G_OBJECT(menu), signal_id);
+    g_main_loop_unref(loop);
+
+    context->action = response;
+
+    g_object_unref(G_OBJECT(menu));
+}
+
 static void
 xfdesktop_file_icon_manager_drag_data_received(XfdesktopIconViewManager *manager,
                                                XfdesktopIcon *drop_icon,
@@ -2794,6 +3004,20 @@ xfdesktop_file_icon_manager_drag_data_received(XfdesktopIconViewManager *manager
     GFile *tfile = NULL;
     gboolean copy_only = TRUE, drop_ok = FALSE;
     GList *file_list;
+    gboolean user_selected_action = FALSE;
+
+    TRACE("entering");
+
+    if(context->action == GDK_ACTION_ASK) {
+        xfdesktop_dnd_menu(manager, drop_icon, context, row, col, time_);
+
+        if(context->action == 0) {
+            gtk_drag_finish(context, FALSE, FALSE, time_);
+            return;
+        }
+        /* The user picked whether to move or copy the files */
+        user_selected_action = TRUE;
+    }
 
     if(info == TARGET_XDND_DIRECT_SAVE0) {
         /* we don't suppose XdndDirectSave stage 3, result F, i.e., the app
@@ -2866,7 +3090,7 @@ xfdesktop_file_icon_manager_drag_data_received(XfdesktopIconViewManager *manager
             tinfo = xfdesktop_file_icon_peek_file_info(file_icon);
         }
         
-        copy_only = (context->action != GDK_ACTION_MOVE);
+        copy_only = (context->action == GDK_ACTION_COPY);
         
         if(tfile && g_file_has_uri_scheme(tfile, "trash") && copy_only) {
             gtk_drag_finish(context, FALSE, FALSE, time_);
@@ -2907,12 +3131,53 @@ xfdesktop_file_icon_manager_drag_data_received(XfdesktopIconViewManager *manager
                     base_dest_file = g_object_ref(fmanager->priv->folder);
                 }
 
+                /* If the user didn't pick whether to copy or move via
+                 * a GDK_ACTION_ASK then determine if we should move/copy
+                 * by checking if the files are on the same filesystem
+                 * and are writable by the user.
+                 */
+                if(user_selected_action == FALSE) {
+                    GFileInfo *src_info, *dest_info;
+                    const gchar *src_name, *dest_name;
+
+                    dest_info = g_file_query_info(base_dest_file,
+                                                  XFDESKTOP_FILE_INFO_NAMESPACE,
+                                                  G_FILE_QUERY_INFO_NONE,
+                                                  NULL,
+                                                  NULL);
+                    src_info = g_file_query_info(file_list->data,
+                                                 XFDESKTOP_FILE_INFO_NAMESPACE,
+                                                 G_FILE_QUERY_INFO_NONE,
+                                                 NULL,
+                                                 NULL);
+
+                    if(dest_info != NULL && src_info != NULL) {
+                        dest_name = g_file_info_get_attribute_string(dest_info,
+                                                G_FILE_ATTRIBUTE_ID_FILESYSTEM);
+                        src_name = g_file_info_get_attribute_string(src_info,
+                                                G_FILE_ATTRIBUTE_ID_FILESYSTEM);
+
+                        if((g_strcmp0(src_name, dest_name) == 0)
+                           && g_file_info_get_attribute_boolean(src_info,
+                                            G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
+                        {
+                            copy_only = FALSE;
+                            context->action = GDK_ACTION_MOVE;
+                        }
+                    }
+
+                    if(dest_info != NULL)
+                        g_object_unref(dest_info);
+                    if(src_info != NULL)
+                        g_object_unref(src_info);
+                }
+
                 for (l = file_list; l; l = l->next) {
                     gchar *dest_basename = g_file_get_basename(l->data);
 
                     if(dest_basename && *dest_basename != '\0') {
                         /* If we copy a file, we need to use the new absolute filename
-                         * as the destination. If we move, we need to use the destination
+                         * as the destination. If we move or link, we need to use the destination
                          * directory. */
                         if(copy_only) {
                             GFile *dest_file = g_file_get_child(base_dest_file, dest_basename);
@@ -2936,7 +3201,11 @@ xfdesktop_file_icon_manager_drag_data_received(XfdesktopIconViewManager *manager
                                                                   fmanager->priv->gscreen);
                 }
 
-                xfdesktop_file_utils_file_list_free(dest_file_list);
+                if(copy_only) {
+                    xfdesktop_file_utils_file_list_free(dest_file_list);
+                } else {
+                    g_list_free(dest_file_list);
+                }
             }
         }
     }
@@ -2996,6 +3265,8 @@ xfdesktop_file_icon_manager_new(GFile *folder,
                            G_OBJECT(fmanager), "show-trash");
     xfconf_g_property_bind(channel, SETTING_SHOW_REMOVABLE, G_TYPE_BOOLEAN,
                            G_OBJECT(fmanager), "show-removable");
+    xfconf_g_property_bind(channel, SETTING_SHOW_THUMBNAILS, G_TYPE_BOOLEAN,
+                           G_OBJECT(fmanager), "show-thumbnails");
 
     return XFDESKTOP_ICON_VIEW_MANAGER(fmanager);
 }
@@ -3027,6 +3298,64 @@ xfdesktop_file_icon_manager_get_show_removable_media(XfdesktopFileIconManager *m
     return manager->priv->show_removable_media;
 }
 
+static void
+xfdesktop_file_icon_manager_requeue_thumbnails(gpointer key,
+                                               gpointer value,
+                                               gpointer data)
+{
+    GFile *file = key;
+    XfdesktopFileIconManager *fmanager = XFDESKTOP_FILE_ICON_MANAGER(data);
+
+    xfdesktop_thumbnailer_queue_thumbnail(fmanager->priv->thumbnailer,
+                                          g_file_get_path(file));
+}
+
+static void
+xfdesktop_file_icon_manager_remove_thumbnails(gpointer key,
+                                              gpointer value,
+                                              gpointer data)
+{
+    XfdesktopRegularFileIcon *icon = XFDESKTOP_REGULAR_FILE_ICON(value);
+
+    xfdesktop_icon_delete_thumbnail(XFDESKTOP_ICON(icon));
+}
+
+void
+xfdesktop_file_icon_manager_set_show_thumbnails(XfdesktopFileIconManager *manager,
+                                                gboolean show_thumbnails)
+{
+    g_return_if_fail(XFDESKTOP_IS_FILE_ICON_MANAGER(manager));
+
+    if(show_thumbnails == manager->priv->show_thumbnails)
+        return;
+
+    manager->priv->show_thumbnails = show_thumbnails;
+
+    if(!manager->priv->inited)
+        return;
+
+    if(show_thumbnails) {
+        /* We have to request to create the thumbnails everytime. */
+         g_hash_table_foreach(manager->priv->icons,
+                         xfdesktop_file_icon_manager_requeue_thumbnails,
+                         manager);
+    } else {
+        /* We have to remove the thumbnails because the regular file
+         * icons can't easily check if thumbnails are allowed.
+         */
+         g_hash_table_foreach(manager->priv->icons,
+                         xfdesktop_file_icon_manager_remove_thumbnails,
+                         manager);
+    }
+}
+
+gboolean
+xfdesktop_file_icon_manager_get_show_thumbnails(XfdesktopFileIconManager *manager)
+{
+    g_return_val_if_fail(XFDESKTOP_IS_FILE_ICON_MANAGER(manager), FALSE);
+    return manager->priv->show_thumbnails;
+}
+
 void
 xfdesktop_file_icon_manager_set_show_special_file(XfdesktopFileIconManager *manager,
                                                   XfdesktopSpecialFileIconType type,
@@ -3068,3 +3397,26 @@ xfdesktop_file_icon_manager_get_show_special_file(XfdesktopFileIconManager *mana
     
     return manager->priv->show_special[type];
 }
+
+static void
+xfdesktop_file_icon_manager_update_image(GtkWidget *widget,
+                                         gchar *srcfile,
+                                         gchar *thumbfile,
+                                         XfdesktopFileIconManager *manager)
+{
+    GFile *file;
+    XfdesktopIcon *icon;
+
+    g_return_if_fail(srcfile && thumbfile);
+    g_return_if_fail(XFDESKTOP_FILE_ICON_MANAGER(manager));
+
+    file = g_file_new_for_path(srcfile);
+
+    icon = g_hash_table_lookup(manager->priv->icons, file);
+    if(icon)
+    {
+        g_object_unref(file);
+        file = g_file_new_for_path(thumbfile);
+        xfdesktop_icon_set_thumbnail_file(icon, file);
+    }
+}
diff --git a/src/xfdesktop-file-icon-manager.h b/src/xfdesktop-file-icon-manager.h
index 703a6f4..decdb74 100644
--- a/src/xfdesktop-file-icon-manager.h
+++ b/src/xfdesktop-file-icon-manager.h
@@ -64,6 +64,15 @@ void xfdesktop_file_icon_manager_set_show_special_file(XfdesktopFileIconManager
                                                        gboolean show_special_file);
 gboolean xfdesktop_file_icon_manager_get_show_special_file(XfdesktopFileIconManager *manager,
                                                            XfdesktopSpecialFileIconType type);
+void xfdesktop_file_icon_manager_set_show_thumbnails(XfdesktopFileIconManager *manager,
+                                                     gboolean show_thumbnails);
+gboolean xfdesktop_file_icon_manager_get_show_thumbnails(XfdesktopFileIconManager *manager);
+
+gboolean xfdesktop_file_icon_manager_get_cached_icon_position(
+                                                    XfdesktopFileIconManager *fmanager,
+                                                    const gchar *name,
+                                                    gint16 *row,
+                                                    gint16 *col);
 
 G_END_DECLS
 
diff --git a/src/xfdesktop-file-utils.c b/src/xfdesktop-file-utils.c
index 75bf0ce..5b015fd 100644
--- a/src/xfdesktop-file-utils.c
+++ b/src/xfdesktop-file-utils.c
@@ -570,13 +570,11 @@ xfdesktop_file_utils_get_icon(const gchar *custom_icon_name,
         }
     }
 
-#ifdef HAVE_LIBEXO
     if(opacity != 100) {
         GdkPixbuf *tmp = exo_gdk_pixbuf_lucent(pix, opacity);
         g_object_unref(G_OBJECT(pix));
         pix = tmp;
     }
-#endif
 
     return pix;
 }
diff --git a/src/xfdesktop-icon-view.c b/src/xfdesktop-icon-view.c
index 0736006..cf2e977 100644
--- a/src/xfdesktop-icon-view.c
+++ b/src/xfdesktop-icon-view.c
@@ -39,18 +39,18 @@
 #include <gdk/gdkx.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
-
-#ifdef HAVE_LIBEXO
 #include <exo/exo.h>
-#else
-#define I_(str)  g_intern_static_string(str)
-#endif
 
 #include "xfdesktop-icon-view.h"
+#include "xfdesktop-file-icon-manager.h"
 #include "xfdesktop-marshal.h"
+#include "xfce-desktop.h"
+#include "xfdesktop-volume-icon.h"
+#include "xfdesktop-common.h"
 
 #include <libwnck/libwnck.h>
 #include <libxfce4ui/libxfce4ui.h>
+#include <xfconf/xfconf.h>
 
 #define DEFAULT_FONT_SIZE  12
 #define DEFAULT_ICON_SIZE  32
@@ -135,6 +135,8 @@ struct _XfdesktopIconViewPrivate
     gint press_start_y;
     GdkRectangle band_rect;
 
+    XfconfChannel *channel;
+
     GdkColor *selection_box_color;
     guchar selection_box_alpha;
     
@@ -168,8 +170,20 @@ struct _XfdesktopIconViewPrivate
     gdouble cell_text_width_proportion;
 
     gboolean ellipsize_icon_labels;
+    guint    tooltip_size;
+
+    gboolean single_click;
 };
 
+static void xfce_icon_view_set_property(GObject *object,
+                                        guint property_id,
+                                        const GValue *value,
+                                        GParamSpec *pspec);
+static void xfce_icon_view_get_property(GObject *object,
+                                        guint property_id,
+                                        GValue *value,
+                                        GParamSpec *pspec);
+
 static gboolean xfdesktop_icon_view_button_press(GtkWidget *widget,
                                                  GdkEventButton *evt,
                                                  gpointer user_data);
@@ -243,10 +257,10 @@ static void xfdesktop_icon_view_invalidate_icon(XfdesktopIconView *icon_view,
                                                 gboolean recalc_extents);
 static void xfdesktop_icon_view_icon_changed(XfdesktopIcon *icon,
                                              gpointer user_data);
-#ifdef HAVE_LIBEXO
+
 static void xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView *icon_view,
                                                        XfdesktopIcon *icon);
-#endif
+
 static void xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
                                            XfdesktopIcon *icon,
                                            GdkRectangle *area);
@@ -290,12 +304,6 @@ static void xfdesktop_screen_size_changed_cb(GdkScreen *gscreen,
 static GdkFilterReturn xfdesktop_rootwin_watch_workarea(GdkXEvent *gxevent,
                                                         GdkEvent *event,
                                                         gpointer user_data);
-static gboolean xfdesktop_get_workarea_single(XfdesktopIconView *icon_view,
-                                              guint ws_num,
-                                              gint *xorigin,
-                                              gint *yorigin,
-                                              gint *width,
-                                              gint *height);
 static void xfdesktop_grid_do_resize(XfdesktopIconView *icon_view);
 static inline gboolean xfdesktop_rectangle_contains_point(GdkRectangle *rect,
                                                           gint x,
@@ -337,6 +345,13 @@ enum
     TARGET_XFDESKTOP_ICON = 9999,
 };
 
+enum
+{
+    PROP_0 = 0,
+    PROP_SINGLE_CLICK,
+};
+
+
 static const GtkTargetEntry icon_view_targets[] = {
     { "XFDESKTOP_ICON", GTK_TARGET_SAME_APP, TARGET_XFDESKTOP_ICON }
 };
@@ -362,6 +377,8 @@ xfdesktop_icon_view_class_init(XfdesktopIconViewClass *klass)
     g_type_class_add_private(klass, sizeof(XfdesktopIconViewPrivate));
     
     gobject_class->finalize = xfdesktop_icon_view_finalize;
+    gobject_class->set_property = xfce_icon_view_set_property;
+    gobject_class->get_property = xfce_icon_view_get_property;
     
     widget_class->style_set = xfdesktop_icon_view_style_set;
     widget_class->realize = xfdesktop_icon_view_realize;
@@ -545,6 +562,28 @@ xfdesktop_icon_view_class_init(XfdesktopIconViewClass *klass)
                                                                 0.0, 50.0, 4.0,
                                                                 G_PARAM_READABLE));
 
+    gtk_widget_class_install_style_property(widget_class,
+                                            g_param_spec_uint("tooltip-size",
+                                                              "Tooltip Image Size",
+                                                              "The size of the tooltip image preview",
+                                                              0, 512, 128,
+                                                              G_PARAM_READABLE));
+
+#define XFDESKTOP_PARAM_FLAGS  (G_PARAM_READWRITE \
+                                | G_PARAM_CONSTRUCT \
+                                | G_PARAM_STATIC_NAME \
+                                | G_PARAM_STATIC_NICK \
+                                | G_PARAM_STATIC_BLURB)
+
+    g_object_class_install_property(gobject_class, PROP_SINGLE_CLICK,
+                                    g_param_spec_boolean("single-click",
+                                                         "single-click",
+                                                         "single-click",
+                                                         FALSE,
+                                                         XFDESKTOP_PARAM_FLAGS));
+
+#undef XFDESKTOP_PARAM_FLAGS
+
     /* same binding entries as GtkIconView */
     gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK,
                                  "select-all", 0);
@@ -633,6 +672,14 @@ xfdesktop_icon_view_init(XfdesktopIconView *icon_view)
     g_object_set(G_OBJECT(icon_view), "has-tooltip", TRUE, NULL);
     g_signal_connect(G_OBJECT(icon_view), "query-tooltip",
                      G_CALLBACK(xfdesktop_icon_view_show_tooltip), NULL);
+
+    icon_view->priv->channel = xfconf_channel_new (XFDESKTOP_CHANNEL);
+
+    xfconf_g_property_bind(icon_view->priv->channel,
+                           "/desktop-icons/single-click",
+                           G_TYPE_BOOLEAN,
+                           G_OBJECT(icon_view),
+                           "single_click");
     
     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(icon_view), GTK_NO_WINDOW);
 }
@@ -654,11 +701,54 @@ xfdesktop_icon_view_finalize(GObject *obj)
     g_list_foreach(icon_view->priv->pending_icons, (GFunc)g_object_unref, NULL);
     g_list_free(icon_view->priv->pending_icons);
     /* icon_view->priv->icons should be cleared in _unrealize() */
+
+    if (icon_view->priv->channel) {
+        g_object_unref (icon_view->priv->channel);
+        icon_view->priv->channel = NULL;
+    }
     
     G_OBJECT_CLASS(xfdesktop_icon_view_parent_class)->finalize(obj);
 }
 
 static void
+xfce_icon_view_set_property(GObject *object,
+                            guint property_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+    XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(object);
+
+    switch(property_id) {
+        case PROP_SINGLE_CLICK:
+            icon_view->priv->single_click = g_value_get_boolean (value);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+xfce_icon_view_get_property(GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+    XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(object);
+
+    switch(property_id) {
+        case PROP_SINGLE_CLICK:
+            g_value_set_boolean(value, icon_view->priv->single_click);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void
 xfdesktop_icon_view_add_move_binding(GtkBindingSet *binding_set,
                                      guint keyval,
                                      guint modmask,
@@ -744,7 +834,7 @@ xfdesktop_icon_view_button_press(GtkWidget *widget,
                     xfdesktop_icon_view_select_item(icon_view, icon);
             }
             
-            if(evt->button == 1) {
+            if(evt->button == 1 || evt->button == 3) {
                 /* we might be the start of a drag */
                 DBG("setting stuff");
                 icon_view->priv->maybe_begin_drag = TRUE;
@@ -752,10 +842,6 @@ xfdesktop_icon_view_button_press(GtkWidget *widget,
                 icon_view->priv->definitely_rubber_banding = FALSE;
                 icon_view->priv->press_start_x = evt->x;
                 icon_view->priv->press_start_y = evt->y;
-            } else if(evt->button == 3) {
-                /* XfceDesktop will handle signalling the icon view manager
-                 * to show the context menu */
-                return FALSE;
             }
             
             return TRUE;
@@ -802,6 +888,14 @@ xfdesktop_icon_view_button_press(GtkWidget *widget,
 }
 
 static gboolean
+xfdesktop_icon_view_get_single_click(XfdesktopIconView *icon_view)
+{
+    g_return_val_if_fail(XFDESKTOP_IS_ICON_VIEW(icon_view), FALSE);
+
+    return icon_view->priv->single_click;
+}
+
+static gboolean
 xfdesktop_icon_view_button_release(GtkWidget *widget,
                                    GdkEventButton *evt,
                                    gpointer user_data)
@@ -809,8 +903,35 @@ xfdesktop_icon_view_button_release(GtkWidget *widget,
     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
     
     TRACE("entering btn=%d", evt->button);
-    
-    if(evt->button == 1) {
+
+    /* single-click */
+    if(xfdesktop_icon_view_get_single_click(icon_view)
+       && evt->button == 1
+       && !(evt->state & GDK_SHIFT_MASK)
+       && !(evt->state & GDK_CONTROL_MASK)
+       && !icon_view->priv->definitely_dragging
+       && !icon_view->priv->definitely_rubber_banding) {
+        XfdesktopIcon *icon;
+        GList *icon_l = g_list_find_custom(icon_view->priv->icons, evt,
+                                           (GCompareFunc)xfdesktop_check_icon_clicked);
+        if(icon_l && (icon = icon_l->data)) {
+            icon_view->priv->cursor = icon;
+            g_signal_emit(G_OBJECT(icon_view), __signals[SIG_ICON_ACTIVATED],
+                          0, NULL);
+            xfdesktop_icon_activated(icon);
+        }
+    }
+
+    if((evt->button == 3 || (evt->button == 1 && (evt->state & GDK_SHIFT_MASK))) &&
+       icon_view->priv->definitely_dragging == FALSE &&
+       icon_view->priv->definitely_rubber_banding == FALSE)
+    {
+        xfce_desktop_popup_root_menu(XFCE_DESKTOP(widget),
+                                     evt->button,
+                                     evt->time);
+    }
+
+    if(evt->button == 1 || evt->button == 3) {
         DBG("unsetting stuff");
         icon_view->priv->definitely_dragging = FALSE;
         icon_view->priv->maybe_begin_drag = FALSE;
@@ -874,6 +995,12 @@ xfdesktop_icon_view_focus_out(GtkWidget *widget,
         xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
     }
 
+    if(G_UNLIKELY(icon_view->priv->single_click)) {
+        if(G_LIKELY(icon_view->priv->parent_window->window != NULL)) {
+            gdk_window_set_cursor(icon_view->priv->parent_window->window, NULL);
+        }
+    }
+
     return FALSE;
 }
 
@@ -897,9 +1024,15 @@ xfdesktop_icon_view_maybe_begin_drag(XfdesktopIconView *icon_view,
     actions = GDK_ACTION_MOVE | (icon_view->priv->drag_source_set ?
                                  icon_view->priv->foreign_source_actions : 0);
     
+    if(evt->state != GDK_BUTTON3_MASK) {
     gtk_drag_begin(GTK_WIDGET(icon_view),
                    icon_view->priv->source_targets,
                    actions, 1, (GdkEvent *)evt);
+    } else {
+        gtk_drag_begin(GTK_WIDGET(icon_view),
+                   icon_view->priv->source_targets,
+                   actions | GDK_ACTION_ASK, 3, (GdkEvent *)evt);
+    }
     
     DBG("DRAG BEGIN!");
     
@@ -926,7 +1059,13 @@ xfdesktop_icon_view_show_tooltip(GtkWidget *widget,
     tip_text = xfdesktop_icon_peek_tooltip(icon_view->priv->item_under_pointer);
     if(!tip_text)
         return FALSE;
-    
+
+    if(icon_view->priv->tooltip_size > 0) {
+        gtk_tooltip_set_icon(tooltip,
+                xfdesktop_icon_peek_pixbuf(icon_view->priv->item_under_pointer,
+                                           icon_view->priv->tooltip_size));
+    }
+
     gtk_tooltip_set_text(tooltip, tip_text);
 
     return TRUE;
@@ -1049,17 +1188,24 @@ xfdesktop_icon_view_motion_notify(GtkWidget *widget,
         /* normal movement; highlight icons as they go under the pointer */
         
         if(icon_view->priv->item_under_pointer) {
+            if(G_UNLIKELY(icon_view->priv->single_click)) {
+                GdkCursor *cursor = gdk_cursor_new(GDK_HAND2);
+                gdk_window_set_cursor(evt->window, cursor);
+                gdk_cursor_unref(cursor);
+            }
             if(!xfdesktop_icon_get_extents(icon_view->priv->item_under_pointer,
                                            NULL, NULL, &extents)
                || !xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
             {
                 icon = icon_view->priv->item_under_pointer;
                 icon_view->priv->item_under_pointer = NULL;
-#ifdef HAVE_LIBEXO
+
                 xfdesktop_icon_view_invalidate_icon_pixbuf(icon_view, icon);
-#endif
             }
         } else {
+            if(G_UNLIKELY(icon_view->priv->single_click)) {
+                gdk_window_set_cursor(evt->window, NULL);
+            }
             icon = xfdesktop_icon_view_widget_coords_to_item(icon_view,
                                                              evt->x,
                                                              evt->y);
@@ -1067,13 +1213,14 @@ xfdesktop_icon_view_motion_notify(GtkWidget *widget,
                && xfdesktop_rectangle_contains_point(&extents, evt->x, evt->y))
             {
                 icon_view->priv->item_under_pointer = icon;
-#ifdef HAVE_LIBEXO
+
                 xfdesktop_icon_view_invalidate_icon_pixbuf(icon_view, icon);
-#endif
             }
         }
     }
     
+    gdk_event_request_motions(evt);
+
     return ret;
 }
 
@@ -1085,13 +1232,16 @@ xfdesktop_icon_view_leave_notify(GtkWidget *widget,
     XfdesktopIconView *icon_view = XFDESKTOP_ICON_VIEW(user_data);
     
     if(icon_view->priv->item_under_pointer) {
-#ifdef HAVE_LIBEXO
         XfdesktopIcon *icon = icon_view->priv->item_under_pointer;
-#endif
         icon_view->priv->item_under_pointer = NULL;
-#ifdef HAVE_LIBEXO
+
         xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
-#endif
+    }
+
+    if(G_UNLIKELY(icon_view->priv->single_click)) {
+        if(GTK_WIDGET_REALIZED(widget)) {
+            gdk_window_set_cursor(widget->window, NULL);
+        }
     }
     
     return FALSE;
@@ -1327,6 +1477,7 @@ xfdesktop_icon_view_drag_drop(GtkWidget *widget,
     GdkAtom target = GDK_NONE;
     XfdesktopIcon *icon;
     guint16 old_row, old_col, row, col;
+    GList *l;
     XfdesktopIcon *icon_on_dest = NULL;
     
     TRACE("entering: (%d,%d)", x, y);
@@ -1346,7 +1497,6 @@ xfdesktop_icon_view_drag_drop(GtkWidget *widget,
     
     if(target == gdk_atom_intern("XFDESKTOP_ICON", FALSE)) {
         if(icon_on_dest) {
-            GList *l;
             gboolean ret = FALSE;
             
             for(l = icon_view->priv->selected_icons; l; l = l->next) {
@@ -1366,18 +1516,52 @@ xfdesktop_icon_view_drag_drop(GtkWidget *widget,
         icon = icon_view->priv->cursor;
         g_return_val_if_fail(icon, FALSE);
         
-        /* clear out old position */
-        xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
-        if(xfdesktop_icon_get_position(icon, &old_row, &old_col))
-            xfdesktop_grid_set_position_free(icon_view, old_row, old_col);
+        /* 1: Remove all the icons that are going to be moved from
+         *    the desktop. That's in case the icons being moved
+         *    want to rearrange themselves there.
+         * 2: We need to move the icon that's being dragged since the
+         *    user explicitly wants to drop it in that spot.
+         * 3: We just append all the other icons in any spot that's
+         *    open. */
+        for(l = icon_view->priv->selected_icons; l; l = l->next) {
+            /* clear out old position */
+            xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
+            if(xfdesktop_icon_get_position(l->data, &old_row, &old_col))
+                xfdesktop_grid_set_position_free(icon_view, old_row, old_col);
+        }
+
         /* set new position */
         xfdesktop_icon_set_position(icon, row, col);
         xfdesktop_grid_unset_position_free(icon_view, icon);
         
         /* clear out old extents, if any */
         /* FIXME: is this right? */
-        //xfdesktop_icon_mark_extents_dirty(icon);
         xfdesktop_icon_view_invalidate_icon(icon_view, icon, TRUE);
+
+        /* Now that we have moved the icon the user selected,
+         * append all the other selected icons after it. */
+        for(l = icon_view->priv->selected_icons; l; l = l->next) {
+            if(l->data == icon)
+                continue;
+
+            /* Find the next available spot for an icon */
+            do {
+                if(row + 1 >= icon_view->priv->nrows) {
+                    ++col;
+                    row = 0;
+                } else {
+                    ++row;
+                }
+            } while(!xfdesktop_grid_is_free_position(icon_view, row, col));
+
+            /* set new position */
+            xfdesktop_icon_set_position(l->data, row, col);
+            xfdesktop_grid_unset_position_free(icon_view, l->data);
+
+            /* clear out old extents, if any */
+            /* FIXME: is this right? */
+            xfdesktop_icon_view_invalidate_icon(icon_view, l->data, TRUE);
+        }
         
         DBG("drag succeeded");
         
@@ -1440,6 +1624,106 @@ xfdesktop_icon_view_drag_data_received(GtkWidget *widget,
                                                    info, time_);
 }
 
+static gint
+xfdesktop_icon_view_compare_icons(gconstpointer *a,
+                                  gconstpointer *b)
+{
+    XfdesktopIcon *a_icon, *b_icon;
+    const gchar *a_str, *b_str;
+
+    a_icon = XFDESKTOP_ICON(a);
+    b_icon = XFDESKTOP_ICON(b);
+
+    a_str = xfdesktop_icon_peek_label(a_icon);
+    b_str = xfdesktop_icon_peek_label(b_icon);
+
+    if(a_str == NULL)
+        a_str = "";
+    if(b_str == NULL)
+        b_str = "";
+
+    return g_utf8_collate(a_str, b_str);
+}
+
+static void
+xfdesktop_icon_view_append_icons(XfdesktopIconView *icon_view,
+                                 GList *icon_list,
+                                 guint16 *row,
+                                 guint16 *col)
+{
+    GList *l = NULL;
+    for(l = icon_list; l; l = l->next) {
+
+        /* Find the next available spot for an icon */
+        do {
+            if(*row + 1 >= icon_view->priv->nrows) {
+                ++*col;
+                *row = 0;
+            } else {
+                ++*row;
+            }
+        } while(!xfdesktop_grid_is_free_position(icon_view, *row, *col));
+
+        /* set new position */
+        xfdesktop_icon_set_position(l->data, *row, *col);
+        xfdesktop_grid_unset_position_free(icon_view, l->data);
+
+        xfdesktop_icon_view_invalidate_icon(icon_view, l->data, TRUE);
+    }
+}
+
+void
+xfdesktop_icon_view_sort_icons(XfdesktopIconView *icon_view)
+{
+#ifdef ENABLE_FILE_ICONS
+    GList *l = NULL;
+    GList *special_icons = NULL;
+    GList *folder_icons = NULL;
+    GList *regular_icons = NULL;
+    guint16 row = 0;
+    guint16 col = -1; /* start at -1 because we'll increment it */
+
+    for(l = icon_view->priv->icons; l; l = l->next) {
+        guint16 old_row, old_col;
+
+        /* clear out old position */
+        xfdesktop_icon_view_invalidate_icon(icon_view, l->data, FALSE);
+
+        if(xfdesktop_icon_get_position(l->data, &old_row, &old_col))
+            xfdesktop_grid_set_position_free(icon_view, old_row, old_col);
+
+        /* Add it to the correct list */
+        if(XFDESKTOP_IS_SPECIAL_FILE_ICON(l->data) ||
+           XFDESKTOP_IS_VOLUME_ICON(l->data)) {
+            special_icons = g_list_insert_sorted(special_icons,
+                                                 l->data,
+                                                 (GCompareFunc)xfdesktop_icon_view_compare_icons);
+        } else if(XFDESKTOP_IS_FILE_ICON(l->data) &&
+                  g_file_query_file_type(xfdesktop_file_icon_peek_file(l->data),
+                                         G_FILE_QUERY_INFO_NONE,
+                                         NULL) == G_FILE_TYPE_DIRECTORY) {
+            folder_icons = g_list_insert_sorted(folder_icons,
+                                                 l->data,
+                                                 (GCompareFunc)xfdesktop_icon_view_compare_icons);
+        } else {
+            regular_icons = g_list_insert_sorted(regular_icons,
+                                                 l->data,
+                                                 (GCompareFunc)xfdesktop_icon_view_compare_icons);
+        }
+    }
+
+    /* Append the icons: special, folder, then regular */
+    xfdesktop_icon_view_append_icons(icon_view, special_icons, &row, &col);
+    xfdesktop_icon_view_append_icons(icon_view, folder_icons, &row, &col);
+    xfdesktop_icon_view_append_icons(icon_view, regular_icons, &row, &col);
+
+
+    g_list_free(special_icons);
+    g_list_free(folder_icons);
+    g_list_free(regular_icons);
+#endif
+}
+
 static void
 xfdesktop_icon_view_icon_theme_changed(GtkIconTheme *icon_theme,
                                        gpointer user_data)
@@ -1514,12 +1798,14 @@ xfdesktop_icon_view_style_set(GtkWidget *widget,
                          "cell-padding", &icon_view->priv->cell_padding,
                          "cell-text-width-proportion", &icon_view->priv->cell_text_width_proportion,
                          "ellipsize-icon-labels", &icon_view->priv->ellipsize_icon_labels,
+                         "tooltip-size", &icon_view->priv->tooltip_size,
                          NULL);
 
     DBG("cell spacing is %d", icon_view->priv->cell_spacing);
     DBG("cell padding is %d", icon_view->priv->cell_padding);
     DBG("cell text width proportion is %f", icon_view->priv->cell_text_width_proportion);
     DBG("ellipsize icon label is %s", icon_view->priv->ellipsize_icon_labels?"true":"false");
+    DBG("tooltip size is %d", icon_view->priv->tooltip_size);
 
     if(icon_view->priv->selection_box_color) {
         gdk_color_free(icon_view->priv->selection_box_color);
@@ -1586,7 +1872,7 @@ xfdesktop_icon_view_realize(GtkWidget *widget)
     /* unfortunately GTK_NO_WINDOW widgets don't receive events, with the
      * exception of expose events. */
     gtk_widget_add_events(icon_view->priv->parent_window,
-                          GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK
+                          GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK
                           | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
                           | GDK_FOCUS_CHANGE_MASK | GDK_EXPOSURE_MASK
                           | GDK_LEAVE_NOTIFY_MASK);
@@ -1855,7 +2141,7 @@ xfdesktop_icon_view_select_between(XfdesktopIconView *icon_view,
     {
         if(start_row > end_row || (start_row == end_row && start_col > end_col)) {
             /* flip start and end */
-            guint16 tmpr = start_row, tmpc = end_row;
+            guint16 tmpr = start_row, tmpc = start_col;
 
             start_row = end_row;
             start_col = end_col;
@@ -2357,7 +2643,6 @@ xfdesktop_icon_view_invalidate_icon(XfdesktopIconView *icon_view,
     }
 }
 
-#ifdef HAVE_LIBEXO
 static void
 xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView *icon_view,
                                            XfdesktopIcon *icon)
@@ -2383,7 +2668,6 @@ xfdesktop_icon_view_invalidate_icon_pixbuf(XfdesktopIconView *icon_view,
         }
     }
 }
-#endif
 
 static void
 xfdesktop_paint_rounded_box(XfdesktopIconView *icon_view,
@@ -2622,29 +2906,17 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
 
     playout = icon_view->priv->playout;
     
-    if(xfdesktop_icon_get_extents(icon, &pixbuf_extents,
-                                   &text_extents, &total_extents))
+    xfdesktop_icon_get_extents(icon, &pixbuf_extents,
+                               &text_extents, &total_extents);
+    xfdesktop_icon_view_setup_pango_layout(icon_view, icon, playout);
+
+    if(!xfdesktop_icon_view_update_icon_extents(icon_view, icon,
+                                                &pixbuf_extents,
+                                                &text_extents,
+                                                &total_extents))
     {
-        xfdesktop_icon_view_setup_pango_layout(icon_view, icon, playout);
-    } else {
-        /* if we get here, it's likely that the expose area doesn't
-         * include everything we *actually* need to repaint.  the
-         * extents should be recalculated before invalidating rects
-         * in the first place.  for now just fix it up and re-expose
-         * the correct area. */
-        if(!xfdesktop_icon_view_update_icon_extents(icon_view, icon,
-                                                    &pixbuf_extents,
-                                                    &text_extents,
-                                                    &total_extents))
-        {
-            g_warning("Can't update extents for icon '%s'",
-                      xfdesktop_icon_peek_label(icon));
-        } else {
-            gtk_widget_queue_draw_area(GTK_WIDGET(icon_view),
-                                       total_extents.x, total_extents.y,
-                                       total_extents.width, total_extents.height);
-        }
-        return;
+        g_warning("Can't update extents for icon '%s'",
+                  xfdesktop_icon_peek_label(icon));
     }
 
     if(g_list_find(icon_view->priv->selected_icons, icon)) {
@@ -2659,7 +2931,6 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
         GdkPixbuf *pix = xfdesktop_icon_peek_pixbuf(icon, ICON_SIZE);
         GdkPixbuf *pix_free = NULL;
 
-#ifdef HAVE_LIBEXO
         if(state != GTK_STATE_NORMAL) {
             pix_free = exo_gdk_pixbuf_colorize(pix, &widget->style->base[state]);
             pix = pix_free;
@@ -2672,7 +2943,6 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
             pix = tmp;
             pix_free = tmp;
         }
-#endif
 
         TRACE("painting pixbuf at %dx%d+%d+%d",
               intersection.width, intersection.height,
@@ -2780,11 +3050,16 @@ xfdesktop_icon_view_paint_icon(XfdesktopIconView *icon_view,
 static void
 xfdesktop_grid_do_resize(XfdesktopIconView *icon_view)
 {
+    XfdesktopFileIconManager *fmanager;
     GList *l, *leftovers = NULL;
     
-    /* move all icons into the pending_icons list */
+    //* move all icons into the pending_icons list and remove from the desktop */
     for(l = icon_view->priv->icons; l; l = l->next) {
-        xfdesktop_icon_mark_extents_dirty(XFDESKTOP_ICON(l->data));
+        guint16 old_row, old_col;
+
+        if(xfdesktop_icon_get_position(XFDESKTOP_ICON(l->data), &old_row, &old_col))
+            xfdesktop_grid_set_position_free(icon_view, old_row, old_col);
+
         g_signal_handlers_disconnect_by_func(G_OBJECT(l->data),
                                              G_CALLBACK(xfdesktop_icon_view_icon_changed),
                                              icon_view);
@@ -2802,10 +3077,28 @@ xfdesktop_grid_do_resize(XfdesktopIconView *icon_view)
     xfdesktop_setup_grids(icon_view);
     
     DUMP_GRID_LAYOUT(icon_view);
-    
+
+#ifdef ENABLE_FILE_ICONS    
+    fmanager = XFDESKTOP_FILE_ICON_MANAGER(icon_view->priv->manager);
+#endif
+
     /* add all icons back */
     for(l = icon_view->priv->pending_icons; l; l = l->next) {
+        gint16 row, col;
         XfdesktopIcon *icon = XFDESKTOP_ICON(l->data);
+
+#ifdef ENABLE_FILE_ICONS
+        /* Try to get the cached position for the new resolution */
+        if(xfdesktop_file_icon_manager_get_cached_icon_position(
+                                                            fmanager,
+                                                            xfdesktop_icon_peek_label(icon),
+                                                            &row,
+                                                            &col))
+        {
+            xfdesktop_icon_set_position(icon, row, col);
+        }
+#endif
+
         if(xfdesktop_icon_view_icon_find_position(icon_view, icon))
             xfdesktop_icon_view_add_item_internal(icon_view, icon);
         else
@@ -2829,7 +3122,7 @@ xfdesktop_grid_resize_timeout(gpointer user_data)
 }
 
 
-static gboolean
+gboolean
 xfdesktop_get_workarea_single(XfdesktopIconView *icon_view,
                               guint ws_num,
                               gint *xorigin,
@@ -3204,7 +3497,6 @@ xfdesktop_icon_view_remove_item(XfdesktopIconView *icon_view,
         
         if(xfdesktop_icon_get_position(icon, &row, &col)) {
             xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
-            xfdesktop_icon_mark_extents_dirty(icon);
             xfdesktop_grid_set_position_free(icon_view, row, col);
         }
         icon_view->priv->icons = g_list_delete_link(icon_view->priv->icons, l);
@@ -3252,7 +3544,6 @@ xfdesktop_icon_view_remove_all(XfdesktopIconView *icon_view)
         if(xfdesktop_icon_get_position(icon, &row, &col)) {
             xfdesktop_icon_view_invalidate_icon(icon_view, icon, FALSE);
             xfdesktop_grid_set_position_free(icon_view, row, col);
-            xfdesktop_icon_mark_extents_dirty(icon);
         }
         
         g_signal_handlers_disconnect_by_func(G_OBJECT(l->data),
diff --git a/src/xfdesktop-icon-view.h b/src/xfdesktop-icon-view.h
index 4961044..f9f5cbf 100644
--- a/src/xfdesktop-icon-view.h
+++ b/src/xfdesktop-icon-view.h
@@ -118,6 +118,16 @@ gdouble xfdesktop_icon_view_get_font_size(XfdesktopIconView *icon_view);
 
 GtkWidget *xfdesktop_icon_view_get_window_widget(XfdesktopIconView *icon_view);
 
+gboolean
+xfdesktop_get_workarea_single(XfdesktopIconView *icon_view,
+                              guint ws_num,
+                              gint *xorigin,
+                              gint *yorigin,
+                              gint *width,
+                              gint *height);
+
+void xfdesktop_icon_view_sort_icons(XfdesktopIconView *icon_view);
+
 #if defined(DEBUG) && DEBUG > 0
 guint _xfdesktop_icon_view_n_items(XfdesktopIconView *icon_view);
 #endif
diff --git a/src/xfdesktop-icon.c b/src/xfdesktop-icon.c
index 431ba79..38c1538 100644
--- a/src/xfdesktop-icon.c
+++ b/src/xfdesktop-icon.c
@@ -37,7 +37,6 @@ struct _XfdesktopIconPrivate
     gint16 row;
     gint16 col;
 
-    gboolean extents_dirty;
     GdkRectangle pixbuf_extents;
     GdkRectangle text_extents;
     GdkRectangle total_extents;
@@ -116,7 +115,6 @@ xfdesktop_icon_init(XfdesktopIcon *icon)
 {
     icon->priv = G_TYPE_INSTANCE_GET_PRIVATE(icon, XFDESKTOP_TYPE_ICON,
                                              XfdesktopIconPrivate);
-    icon->priv->extents_dirty = TRUE;
 }
 
 
@@ -158,7 +156,6 @@ xfdesktop_icon_set_extents(XfdesktopIcon *icon,
     icon->priv->pixbuf_extents = *pixbuf_extents;
     icon->priv->text_extents = *text_extents;
     icon->priv->total_extents = *total_extents;
-    icon->priv->extents_dirty = FALSE;
 }
 
 gboolean
@@ -169,9 +166,6 @@ xfdesktop_icon_get_extents(XfdesktopIcon *icon,
 {
     g_return_val_if_fail(XFDESKTOP_IS_ICON(icon), FALSE);
 
-    if(icon->priv->extents_dirty)
-        return FALSE;
-
     if(pixbuf_extents)
         *pixbuf_extents = icon->priv->pixbuf_extents;
     if(text_extents)
@@ -182,16 +176,6 @@ xfdesktop_icon_get_extents(XfdesktopIcon *icon,
     return TRUE;
 }
 
-void
-xfdesktop_icon_mark_extents_dirty(XfdesktopIcon *icon)
-{
-    g_return_if_fail(XFDESKTOP_IS_ICON(icon));
-
-    icon->priv->extents_dirty = TRUE;
-}
-
-
-
 /*< required >*/
 GdkPixbuf *
 xfdesktop_icon_peek_pixbuf(XfdesktopIcon *icon,
@@ -283,6 +267,37 @@ xfdesktop_icon_peek_tooltip(XfdesktopIcon *icon)
 }
 
 /*< optional >*/
+void xfdesktop_icon_delete_thumbnail(XfdesktopIcon *icon)
+{
+    XfdesktopIconClass *klass;
+
+    g_return_if_fail(XFDESKTOP_IS_ICON(icon));
+
+    klass = XFDESKTOP_ICON_GET_CLASS(icon);
+
+    if(!klass->delete_thumbnail_file)
+        return;
+
+    klass->delete_thumbnail_file(icon);
+}
+
+/*< optional >*/
+void
+xfdesktop_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file)
+{
+    XfdesktopIconClass *klass;
+
+    g_return_if_fail(XFDESKTOP_IS_ICON(icon));
+
+    klass = XFDESKTOP_ICON_GET_CLASS(icon);
+
+    if(!klass->set_thumbnail_file)
+        return;
+
+    klass->set_thumbnail_file(icon, file);
+}
+
+/*< optional >*/
 gboolean
 xfdesktop_icon_populate_context_menu(XfdesktopIcon *icon,
                                      GtkWidget *menu)
@@ -312,7 +327,6 @@ void
 xfdesktop_icon_pixbuf_changed(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
-    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(icon, __signals[SIG_PIXBUF_CHANGED], 0);
 }
 
@@ -320,7 +334,6 @@ void
 xfdesktop_icon_label_changed(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
-    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(icon, __signals[SIG_LABEL_CHANGED], 0);
 }
 
@@ -328,7 +341,6 @@ void
 xfdesktop_icon_position_changed(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
-    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(icon, __signals[SIG_POS_CHANGED], 0);
 }
 
@@ -337,7 +349,6 @@ void
 xfdesktop_icon_selected(XfdesktopIcon *icon)
 {
     g_return_if_fail(XFDESKTOP_IS_ICON(icon));
-    xfdesktop_icon_mark_extents_dirty(icon);
     g_signal_emit(G_OBJECT(icon), __signals[SIG_SELECTED], 0, NULL);
 }
 
diff --git a/src/xfdesktop-icon.h b/src/xfdesktop-icon.h
index b838ed5..e42261e 100644
--- a/src/xfdesktop-icon.h
+++ b/src/xfdesktop-icon.h
@@ -73,6 +73,9 @@ struct _XfdesktopIconClass
     
     G_CONST_RETURN gchar *(*peek_tooltip)(XfdesktopIcon *icon);
     
+    void (*set_thumbnail_file)(XfdesktopIcon *icon, GFile *file);
+    void (*delete_thumbnail_file)(XfdesktopIcon *icon);
+
     gboolean (*populate_context_menu)(XfdesktopIcon *icon,
                                       GtkWidget *menu);
 };
@@ -105,6 +108,9 @@ gboolean xfdesktop_icon_populate_context_menu(XfdesktopIcon *icon,
 
 GtkWidget *xfdesktop_icon_peek_icon_view(XfdesktopIcon *icon);
 
+void xfdesktop_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file);
+void xfdesktop_icon_delete_thumbnail(XfdesktopIcon *icon);
+
 /*< signal triggers >*/
 
 void xfdesktop_icon_pixbuf_changed(XfdesktopIcon *icon);
@@ -123,7 +129,6 @@ gboolean xfdesktop_icon_get_extents(XfdesktopIcon *icon,
                                     GdkRectangle *pixbuf_extents,
                                     GdkRectangle *text_extents,
                                     GdkRectangle *total_extents);
-void xfdesktop_icon_mark_extents_dirty(XfdesktopIcon *icon);
 
 G_END_DECLS
 
diff --git a/src/xfdesktop-marshal.list b/src/xfdesktop-marshal.list
deleted file mode 100644
index 819c32e..0000000
--- a/src/xfdesktop-marshal.list
+++ /dev/null
@@ -1,2 +0,0 @@
-BOOLEAN:VOID
-BOOLEAN:ENUM,INT
diff --git a/src/xfdesktop-regular-file-icon.c b/src/xfdesktop-regular-file-icon.c
index e14256a..f42f6d6 100644
--- a/src/xfdesktop-regular-file-icon.c
+++ b/src/xfdesktop-regular-file-icon.c
@@ -36,9 +36,7 @@
 #include <time.h>
 #endif
 
-#ifdef HAVE_LIBEXO
 #include <exo/exo.h>
-#endif
 
 #ifndef PATH_MAX
 #define PATH_MAX 4096
@@ -68,11 +66,15 @@ struct _XfdesktopRegularFileIconPrivate
     GFileInfo *file_info;
     GFileInfo *filesystem_info;
     GFile *file;
+    GFile *thumbnail_file;
     GdkScreen *gscreen;
 };
 
 static void xfdesktop_regular_file_icon_finalize(GObject *obj);
 
+static void xfdesktop_regular_file_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file);
+static void xfdesktop_regular_file_icon_delete_thumbnail_file(XfdesktopIcon *icon);
+
 static GdkPixbuf *xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon,
                                                           gint size);
 static G_CONST_RETURN gchar *xfdesktop_regular_file_icon_peek_label(XfdesktopIcon *icon);
@@ -127,6 +129,8 @@ xfdesktop_regular_file_icon_class_init(XfdesktopRegularFileIconClass *klass)
     icon_class->get_allowed_drag_actions = xfdesktop_regular_file_icon_get_allowed_drag_actions;
     icon_class->get_allowed_drop_actions = xfdesktop_regular_file_icon_get_allowed_drop_actions;
     icon_class->do_drop_dest = xfdesktop_regular_file_icon_do_drop_dest;
+    icon_class->set_thumbnail_file = xfdesktop_regular_file_icon_set_thumbnail_file;
+    icon_class->delete_thumbnail_file = xfdesktop_regular_file_icon_delete_thumbnail_file;
     
     file_icon_class->peek_file_info = xfdesktop_regular_file_icon_peek_file_info;
     file_icon_class->peek_filesystem_info = xfdesktop_regular_file_icon_peek_filesystem_info;
@@ -171,6 +175,9 @@ xfdesktop_regular_file_icon_finalize(GObject *obj)
     
     if(icon->priv->tooltip)
         g_free(icon->priv->tooltip);
+
+    if(icon->priv->thumbnail_file)
+        g_object_unref(icon->priv->thumbnail_file);
     
     G_OBJECT_CLASS(xfdesktop_regular_file_icon_parent_class)->finalize(obj);
 }
@@ -201,6 +208,43 @@ xfdesktop_regular_file_icon_invalidate_pixbuf(XfdesktopRegularFileIcon *icon)
     }
 }
 
+static void
+xfdesktop_regular_file_icon_delete_thumbnail_file(XfdesktopIcon *icon)
+{
+    XfdesktopRegularFileIcon *file_icon;
+
+    if(!XFDESKTOP_IS_REGULAR_FILE_ICON(icon))
+        return;
+
+    file_icon = XFDESKTOP_REGULAR_FILE_ICON(icon);
+
+    if(file_icon->priv->thumbnail_file) {
+        g_object_unref(file_icon->priv->thumbnail_file);
+        file_icon->priv->thumbnail_file = NULL;
+    }
+
+    xfdesktop_regular_file_icon_invalidate_pixbuf(file_icon);
+    xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(icon));
+}
+
+static void
+xfdesktop_regular_file_icon_set_thumbnail_file(XfdesktopIcon *icon, GFile *file)
+{
+    XfdesktopRegularFileIcon *file_icon;
+
+    if(!XFDESKTOP_IS_REGULAR_FILE_ICON(icon))
+        return;
+
+    file_icon = XFDESKTOP_REGULAR_FILE_ICON(icon);
+
+    if(file_icon->priv->thumbnail_file)
+        g_object_unref(file_icon->priv->thumbnail_file);
+
+    file_icon->priv->thumbnail_file = file;
+
+    xfdesktop_regular_file_icon_invalidate_pixbuf(file_icon);
+    xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(icon));
+}
 
 static GdkPixbuf *
 xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon,
@@ -224,6 +268,10 @@ xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon,
         if(g_file_has_prefix(file_icon->priv->file, thumbnail_dir)) {
             /* use the filename as custom icon name for thumbnails */
             icon_name = g_file_get_path(file_icon->priv->file);
+
+            /* release thumbnail path */
+            g_object_unref(thumbnail_dir);
+            g_free(thumbnail_dir_path);
         } else if(xfdesktop_file_utils_is_desktop_file(file_icon->priv->file_info)) {
             gchar *contents;
             gsize length;
@@ -248,12 +296,16 @@ xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon,
                 g_key_file_free(key_file);
                 g_free(contents);
             }
+        } else {
+            /* If we have a thumbnail then they are enabled, use it. */
+            if(file_icon->priv->thumbnail_file)
+            {
+                file_icon->priv->pix = gdk_pixbuf_new_from_file_at_size(g_file_get_path(file_icon->priv->thumbnail_file),
+                                                                        size, size,
+                                                                        NULL);
+            }
         }
 
-        /* release thumbnail path */
-        g_object_unref(thumbnail_dir);
-        g_free(thumbnail_dir_path);
-
         /* load the symlink emblem if necessary */
         if(g_file_info_get_attribute_boolean(file_icon->priv->file_info, 
                                              G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK)) 
@@ -280,10 +332,24 @@ xfdesktop_regular_file_icon_peek_pixbuf(XfdesktopIcon *icon,
 
         if(file_icon->priv->file_info)
             gicon = g_file_info_get_icon(file_icon->priv->file_info);
-        
-        file_icon->priv->pix = xfdesktop_file_utils_get_icon(icon_name, gicon, 
-                                                             size, emblem_pix,
-                                                             file_icon->priv->pix_opacity);
+
+        if(file_icon->priv->pix) {
+            if(emblem_pix) {
+                gint emblem_pix_size = gdk_pixbuf_get_width(emblem_pix);
+                gint dest_size = size - emblem_pix_size;
+
+                /* We have to add the emblem */
+                gdk_pixbuf_composite(emblem_pix, file_icon->priv->pix,
+                                     dest_size, dest_size,
+                                     emblem_pix_size, emblem_pix_size,
+                                     dest_size, dest_size,
+                                     1.0, 1.0, GDK_INTERP_BILINEAR, 255);
+            }
+        } else {
+            file_icon->priv->pix = xfdesktop_file_utils_get_icon(icon_name, gicon,
+                                                                 size, emblem_pix,
+                                                                 file_icon->priv->pix_opacity);
+        }
         
         file_icon->priv->cur_pix_size = size;
 
@@ -450,13 +516,27 @@ xfdesktop_regular_file_icon_peek_tooltip(XfdesktopIcon *icon)
     
     if(!regular_file_icon->priv->tooltip) {
         GFileInfo *info = xfdesktop_file_icon_peek_file_info(XFDESKTOP_FILE_ICON(icon));
-        const gchar *content_type;
+        const gchar *content_type, *comment = NULL;
         gchar *description, *size_string, *time_string;
         guint64 size, mtime;
+        gboolean is_desktop_file = FALSE;
 
         if(!info)
             return NULL;
 
+        if(g_content_type_equals(g_file_info_get_content_type(info),
+                                 "application/x-desktop"))
+        {
+            is_desktop_file = TRUE;
+        }
+        else
+        {
+          gchar *uri = g_file_get_uri(regular_file_icon->priv->file);
+          if(g_str_has_suffix(uri, ".desktop"))
+              is_desktop_file = TRUE;
+          g_free(uri);
+        }
+
         content_type = g_file_info_get_content_type(info);
         description = g_content_type_get_description(content_type);
 
@@ -468,10 +548,34 @@ xfdesktop_regular_file_icon_peek_tooltip(XfdesktopIcon *icon)
                                                  G_FILE_ATTRIBUTE_TIME_MODIFIED);
         time_string = xfdesktop_file_utils_format_time_for_display(mtime);
 
+        /* Extract the Comment entry from the .desktop file */
+        if(is_desktop_file)
+        {
+            gchar *path = g_file_get_path(regular_file_icon->priv->file);
+            XfceRc *rcfile = xfce_rc_simple_open(path, TRUE);
+            g_free(path);
+
+            if(rcfile) {
+                xfce_rc_set_group(rcfile, "Desktop Entry");
+                comment = xfce_rc_read_entry(rcfile, "Comment", NULL);
+            }
+
+            xfce_rc_close(rcfile);
+        }
+
         regular_file_icon->priv->tooltip =
             g_strdup_printf(_("Type: %s\nSize: %s\nLast modified: %s"),
                             description, size_string, time_string);
 
+        /* Prepend the comment to the tooltip */
+        if(is_desktop_file && comment != NULL) {
+            gchar *tooltip = regular_file_icon->priv->tooltip;
+            regular_file_icon->priv->tooltip = g_strdup_printf("%s\n%s",
+                                                               comment,
+                                                               tooltip);
+            g_free(tooltip);
+        }
+
         g_free(time_string);
         g_free(size_string);
         g_free(description);
diff --git a/src/xfdesktop-special-file-icon.c b/src/xfdesktop-special-file-icon.c
index 1226adf..fa0bc0b 100644
--- a/src/xfdesktop-special-file-icon.c
+++ b/src/xfdesktop-special-file-icon.c
@@ -65,7 +65,7 @@ struct _XfdesktopSpecialFileIconPrivate
     GdkScreen *gscreen;
     
     /* only needed for trash */
-    gboolean trash_item_count;
+    guint trash_item_count;
 };
 
 static void xfdesktop_special_file_icon_finalize(GObject *obj);
@@ -90,6 +90,7 @@ static void xfdesktop_special_file_icon_changed(GFileMonitor *monitor,
                                                 GFile *other_file,
                                                 GFileMonitorEvent event,
                                                 XfdesktopSpecialFileIcon *special_file_icon);
+static void xfdesktop_special_file_icon_update_trash_count(XfdesktopSpecialFileIcon *special_file_icon);
 
 #ifdef HAVE_THUNARX
 static void xfdesktop_special_file_icon_tfi_init(ThunarxFileInfoIface *iface);
@@ -219,29 +220,43 @@ xfdesktop_special_file_icon_peek_pixbuf(XfdesktopIcon *icon,
                                         gint size)
 {
     XfdesktopSpecialFileIcon *file_icon = XFDESKTOP_SPECIAL_FILE_ICON(icon);
-    
+    GIcon *gicon = NULL;
+    const gchar *custom_icon_name = NULL;
+    GFile *parent = NULL;
+
     if(size != file_icon->priv->cur_pix_size)
         xfdesktop_special_file_icon_invalidate_pixbuf(file_icon);
-    
-    if(!file_icon->priv->pix) {
-        GIcon *gicon = NULL;
-        const gchar *custom_icon_name = NULL;
-
-        /* use a custom icon name for the local filesystem root */
-        GFile *parent = g_file_get_parent(file_icon->priv->file);
-        if(!parent && g_file_has_uri_scheme(file_icon->priv->file, "file"))
-            custom_icon_name = "drive-harddisk";
-        if(parent)
-            g_object_unref(parent);
-
-        if(file_icon->priv->file_info)
-            gicon = g_file_info_get_icon(file_icon->priv->file_info);
-        
-        file_icon->priv->pix = xfdesktop_file_utils_get_icon(custom_icon_name, gicon,
-                                                             size, NULL, 100);
-        
-        file_icon->priv->cur_pix_size = size;
+
+    /* Already have a good icon */
+    if(file_icon->priv->pix != NULL)
+        return file_icon->priv->pix;
+
+    /* use a custom icon name for the local filesystem root */
+    parent = g_file_get_parent(file_icon->priv->file);
+    if(!parent && g_file_has_uri_scheme(file_icon->priv->file, "file"))
+        custom_icon_name = "drive-harddisk";
+    if(parent)
+        g_object_unref(parent);
+
+    /* use a custom icon for the trash, based on it having files
+     * the user can delete */
+    if(file_icon->priv->type == XFDESKTOP_SPECIAL_FILE_ICON_TRASH) {
+        if(file_icon->priv->trash_item_count == 0)
+            custom_icon_name = "user-trash";
+        else
+            custom_icon_name = "user-trash-full";
     }
+
+    if(file_icon->priv->file_info)
+        gicon = g_file_info_get_icon(file_icon->priv->file_info);
+
+    file_icon->priv->pix = xfdesktop_file_utils_get_icon(custom_icon_name,
+                                                         gicon,
+                                                         size,
+                                                         NULL,
+                                                         100);
+
+    file_icon->priv->cur_pix_size = size;
     
     return file_icon->priv->pix;
 }
@@ -477,13 +492,10 @@ xfdesktop_special_file_icon_populate_context_menu(XfdesktopIcon *icon,
 {
     XfdesktopSpecialFileIcon *special_file_icon = XFDESKTOP_SPECIAL_FILE_ICON(icon);
     GtkWidget *mi, *img;
-    GtkIconTheme *icon_theme;
     
     if(XFDESKTOP_SPECIAL_FILE_ICON_TRASH != special_file_icon->priv->type)
         return FALSE;
     
-    icon_theme = gtk_icon_theme_get_default();
-    
     img = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
     gtk_widget_show(img);
     mi = gtk_image_menu_item_new_with_mnemonic(_("_Open"));
@@ -496,13 +508,12 @@ xfdesktop_special_file_icon_populate_context_menu(XfdesktopIcon *icon,
     mi = gtk_separator_menu_item_new();
     gtk_widget_show(mi);
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
-    
-    if(gtk_icon_theme_has_icon(icon_theme, "user-trash"))
+
+    if(special_file_icon->priv->trash_item_count == 0) {
         img = gtk_image_new_from_icon_name("user-trash", GTK_ICON_SIZE_MENU);
-    else if(gtk_icon_theme_has_icon(icon_theme, "gnome-fs-trash-empty"))
-        img = gtk_image_new_from_icon_name("gnome-fs-trash-empty", GTK_ICON_SIZE_MENU);
-    else
-        img = NULL;
+    } else {
+        img = gtk_image_new_from_icon_name("user-trash-full", GTK_ICON_SIZE_MENU);
+    }
     
     mi = gtk_image_menu_item_new_with_mnemonic(_("_Empty Trash"));
     if(img)
@@ -575,12 +586,8 @@ xfdesktop_special_file_icon_changed(GFileMonitor *monitor,
                                                                             NULL, NULL);
 
     /* update the trash full state */
-    if(special_file_icon->priv->file_info 
-       && special_file_icon->priv->type == XFDESKTOP_SPECIAL_FILE_ICON_TRASH) 
-    {
-        special_file_icon->priv->trash_item_count = g_file_info_get_attribute_uint32(special_file_icon->priv->file_info, 
-                                                                                     G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT);
-    }
+    if(special_file_icon->priv->type == XFDESKTOP_SPECIAL_FILE_ICON_TRASH)
+        xfdesktop_special_file_icon_update_trash_count(special_file_icon);
 
     /* invalidate the tooltip */
     g_free(special_file_icon->priv->tooltip);
@@ -591,6 +598,54 @@ xfdesktop_special_file_icon_changed(GFileMonitor *monitor,
     xfdesktop_icon_pixbuf_changed(XFDESKTOP_ICON(special_file_icon));
 }
 
+static void
+xfdesktop_special_file_icon_update_trash_count(XfdesktopSpecialFileIcon *special_file_icon)
+{
+    GFileEnumerator *enumerator;
+    GFileInfo *f_info;
+    gint n = 0;
+
+    g_return_if_fail(XFDESKTOP_IS_SPECIAL_FILE_ICON(special_file_icon));
+
+    if(special_file_icon->priv->file_info == NULL
+       || special_file_icon->priv->type != XFDESKTOP_SPECIAL_FILE_ICON_TRASH)
+    {
+        return;
+    }
+
+    special_file_icon->priv->trash_item_count = g_file_info_get_attribute_uint32(
+                                                    special_file_icon->priv->file_info,
+                                                    G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT);
+
+    if(special_file_icon->priv->trash_item_count == 0)
+        return;
+
+    /* The trash count may return a number of files the user can't
+     * currently delete, for example if the file is in a removable
+     * drive that isn't mounted.
+     */
+    enumerator = g_file_enumerate_children(special_file_icon->priv->file,
+                                           G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE,
+                                           G_FILE_QUERY_INFO_NONE,
+                                           NULL,
+                                           NULL);
+    if(enumerator == NULL)
+        return;
+
+    for(f_info = g_file_enumerator_next_file(enumerator, NULL, NULL);
+        f_info != NULL;
+        f_info = g_file_enumerator_next_file(enumerator, NULL, NULL))
+    {
+          n++;
+          g_object_unref(f_info);
+    }
+
+    g_file_enumerator_close(enumerator, NULL, NULL);
+    g_object_unref(enumerator);
+
+    special_file_icon->priv->trash_item_count = n;
+}
+
 /* public API */
 
 XfdesktopSpecialFileIcon *
@@ -636,11 +691,9 @@ xfdesktop_special_file_icon_new(XfdesktopSpecialFileIconType type,
     special_file_icon->priv->filesystem_info = g_file_query_filesystem_info(special_file_icon->priv->file,
                                                                             XFDESKTOP_FILESYSTEM_INFO_NAMESPACE,
                                                                             NULL, NULL);
-
-    if(type == XFDESKTOP_SPECIAL_FILE_ICON_TRASH) {
-        special_file_icon->priv->trash_item_count = g_file_info_get_attribute_uint32(special_file_icon->priv->file_info, 
-                                                                                     G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT);
-    }
+    /* update the trash full state */
+    if(type == XFDESKTOP_SPECIAL_FILE_ICON_TRASH)
+        xfdesktop_special_file_icon_update_trash_count(special_file_icon);
 
     g_signal_connect_swapped(G_OBJECT(gtk_icon_theme_get_for_screen(screen)),
                              "changed",
diff --git a/src/xfdesktop-volume-icon.c b/src/xfdesktop-volume-icon.c
index 01a5570..c0cae93 100644
--- a/src/xfdesktop-volume-icon.c
+++ b/src/xfdesktop-volume-icon.c
@@ -52,6 +52,8 @@
 #include "xfdesktop-notify.h"
 #endif
 
+#include <exo/exo.h>
+
 #include "xfdesktop-common.h"
 #include "xfdesktop-file-utils.h"
 #include "xfdesktop-volume-icon.h"
@@ -224,6 +226,30 @@ xfdesktop_volume_icon_invalidate_pixbuf(XfdesktopVolumeIcon *icon)
     }
 }
 
+static gboolean
+xfdesktop_volume_icon_is_mounted(XfdesktopIcon *icon)
+{
+    GVolume *volume = NULL;
+    GMount *mount = NULL;
+    gboolean ret = FALSE;
+    XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon);
+
+    g_return_val_if_fail(XFDESKTOP_IS_VOLUME_ICON(icon), FALSE);
+
+    volume = xfdesktop_volume_icon_peek_volume(volume_icon);
+
+    if(volume != NULL)
+        mount = g_volume_get_mount(volume);
+
+    if(mount != NULL) {
+        ret = TRUE;
+        g_object_unref(mount);
+    } else {
+        ret = FALSE;
+    }
+
+    return ret;
+}
 
 static GdkPixbuf *
 xfdesktop_volume_icon_peek_pixbuf(XfdesktopIcon *icon,
@@ -244,6 +270,17 @@ xfdesktop_volume_icon_peek_pixbuf(XfdesktopIcon *icon,
 
         file_icon->priv->pix = xfdesktop_file_utils_get_icon(NULL, gicon, size, 
                                                              NULL, 100);
+
+        /* If the volume isn't mounted show it as semi-transparent */
+        if(!xfdesktop_volume_icon_is_mounted(icon)) {
+            GdkPixbuf *temp;
+            temp = exo_gdk_pixbuf_lucent(file_icon->priv->pix, 50);
+
+            if(temp != NULL) {
+                g_object_unref(G_OBJECT(file_icon->priv->pix));
+                file_icon->priv->pix = temp;
+            }
+        }
         
         file_icon->priv->cur_pix_size = size;
     }
@@ -268,10 +305,6 @@ xfdesktop_volume_icon_peek_label(XfdesktopIcon *icon)
 static GdkDragAction
 xfdesktop_volume_icon_get_allowed_drag_actions(XfdesktopIcon *icon)
 {
-    XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon);
-    GVolume *volume;
-    GMount *mount;
-    
     /* volume icons more or less represent the volume's mount point, usually
      * (hopefully) a local path.  so when it's mounted, we certainly can't move
      * the mount point, but copying and linking should be OK.  when not mounted,
@@ -281,10 +314,7 @@ xfdesktop_volume_icon_get_allowed_drag_actions(XfdesktopIcon *icon)
     /* FIXME: should i allow all actions if not mounted as well, and try to
      * mount and resolve on drop? */
     
-    volume = xfdesktop_volume_icon_peek_volume(volume_icon);
-
-    mount = g_volume_get_mount(volume);
-    if(mount) {
+    if(xfdesktop_volume_icon_is_mounted(icon)) {
         GFileInfo *info = xfdesktop_file_icon_peek_file_info(XFDESKTOP_FILE_ICON(icon));
         if(info) {
             if(g_file_info_get_attribute_boolean(info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
@@ -292,8 +322,6 @@ xfdesktop_volume_icon_get_allowed_drag_actions(XfdesktopIcon *icon)
             else
                 return GDK_ACTION_LINK;
         }
-
-        g_object_unref(mount);
     }
     
     return 0;
@@ -302,26 +330,18 @@ xfdesktop_volume_icon_get_allowed_drag_actions(XfdesktopIcon *icon)
 static GdkDragAction
 xfdesktop_volume_icon_get_allowed_drop_actions(XfdesktopIcon *icon)
 {
-    XfdesktopVolumeIcon *volume_icon = XFDESKTOP_VOLUME_ICON(icon);
-    GVolume *volume;
-    GMount *mount;
-    
     /* if not mounted, it doesn't really make sense to allow any operations
      * here.  if mounted, we should allow everything if it's writable. */
     
     /* FIXME: should i allow all actions if not mounted as well, and try to
      * mount and resolve on drop? */
 
-    volume = xfdesktop_volume_icon_peek_volume(volume_icon);
-
-    mount = g_volume_get_mount(volume);
-    if(mount) {
+    if(xfdesktop_volume_icon_is_mounted(icon)) {
         GFileInfo *info = xfdesktop_file_icon_peek_file_info(XFDESKTOP_FILE_ICON(icon));
         if(info) {
             if(g_file_info_get_attribute_boolean(info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
                 return GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK;
         }
-        g_object_unref(mount);
     }
     
     return 0;


More information about the Xfce4-commits mailing list