From e24ebc3dd35e1a5b1d16db4469b346722d683fb6 Mon Sep 17 00:00:00 2001
From: Benedikt Meurer <benny@xfce.org>
Date: Sun, 24 Jul 2005 17:12:27 +0000
Subject: [PATCH] 2005-07-24	Benedikt Meurer <benny@xfce.org>

	* thunar/thunar-file.c(thunar_file_load_icon): Actually cache the result
	  of an icon lookup.
	* thunarx/, thunarx/Makefile.am, configure.in.in: Add "thunarx"
	  namespace, which contains extensions to existing frameworks and
	  various helper functions that don't fit anywhere else.
	* thunarx/thunarx-gdk-pixbuf-extensions.{c,h}: Add a method to colorize
	  a GdkPixbuf to a given GdkColor.
	* thunar/main.c, thunar/thunar-desktop-model.{c,h}, thunar/Makefile.am,
	  thunar/thunar-desktop-window.{c,h}, thunar/thunar-desktop-view.{c,h}:
	  Add proof-of-concept for the desktop support.




(Old svn revision: 16409)
---
 ChangeLog                               |  13 +
 Makefile.am                             |   1 +
 configure.in.in                         |   1 +
 thunar/Makefile.am                      |  10 +-
 thunar/main.c                           |   9 +
 thunar/thunar-desktop-model.c           | 471 +++++++++++++++
 thunar/thunar-desktop-model.h           |  67 ++
 thunar/thunar-desktop-view.c            | 771 +++++++++++++++++++++---
 thunar/thunar-desktop-view.h            |  33 +-
 thunar/thunar-desktop-window.c          | 216 +++++++
 thunar/thunar-desktop-window.h          |  44 ++
 thunar/thunar-file.c                    |  21 +-
 thunarx/Makefile.am                     |  25 +
 thunarx/thunarx-gdk-pixbuf-extensions.c |  90 +++
 thunarx/thunarx-gdk-pixbuf-extensions.h |  32 +
 15 files changed, 1692 insertions(+), 112 deletions(-)
 create mode 100644 thunar/thunar-desktop-model.c
 create mode 100644 thunar/thunar-desktop-model.h
 create mode 100644 thunar/thunar-desktop-window.c
 create mode 100644 thunar/thunar-desktop-window.h
 create mode 100644 thunarx/Makefile.am
 create mode 100644 thunarx/thunarx-gdk-pixbuf-extensions.c
 create mode 100644 thunarx/thunarx-gdk-pixbuf-extensions.h

diff --git a/ChangeLog b/ChangeLog
index ca1965c62..d9edb358a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2005-07-24	Benedikt Meurer <benny@xfce.org>
+
+	* thunar/thunar-file.c(thunar_file_load_icon): Actually cache the result
+	  of an icon lookup.
+	* thunarx/, thunarx/Makefile.am, configure.in.in: Add "thunarx"
+	  namespace, which contains extensions to existing frameworks and
+	  various helper functions that don't fit anywhere else.
+	* thunarx/thunarx-gdk-pixbuf-extensions.{c,h}: Add a method to colorize
+	  a GdkPixbuf to a given GdkColor.
+	* thunar/main.c, thunar/thunar-desktop-model.{c,h}, thunar/Makefile.am,
+	  thunar/thunar-desktop-window.{c,h}, thunar/thunar-desktop-view.{c,h}:
+	  Add proof-of-concept for the desktop support.
+
 2005-07-23	Benedikt Meurer <benny@xfce.org>
 
 	* thunar/thunar-list-model.c: Fix incorrect ThunarVfsMimeInfo -> GObject
diff --git a/Makefile.am b/Makefile.am
index 8d98f9fd0..bdef6e54d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,6 +3,7 @@
 SUBDIRS =								\
 	docs								\
 	thunar-vfs							\
+	thunarx								\
 	thunar								\
 	tests
 
diff --git a/configure.in.in b/configure.in.in
index 7d350ee2c..5702d6bbe 100644
--- a/configure.in.in
+++ b/configure.in.in
@@ -108,4 +108,5 @@ tests/data/Makefile
 thunar/Makefile
 thunar-vfs/Makefile
 thunar-vfs/xdgmime/Makefile
+thunarx/Makefile
 ])
diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 582e85cac..3dd53e549 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -17,8 +17,12 @@ Thunar_SOURCES =							\
 	thunar-clipboard-manager.h					\
 	thunar-computer-folder.c					\
 	thunar-computer-folder.h					\
+	thunar-desktop-model.c						\
+	thunar-desktop-model.h						\
 	thunar-desktop-view.c						\
 	thunar-desktop-view.h						\
+	thunar-desktop-window.c						\
+	thunar-desktop-window.h						\
 	thunar-details-view.c						\
 	thunar-details-view.h						\
 	thunar-details-view-icon-renderer.c				\
@@ -90,10 +94,12 @@ Thunar_LDFLAGS =							\
 	$(GTHREAD_LIBS)
 
 Thunar_LDADD =								\
-	$(top_builddir)/thunar-vfs/libthunar-vfs.la
+	$(top_builddir)/thunar-vfs/libthunar-vfs.la			\
+	$(top_builddir)/thunarx/libthunarx.la
 
 Thunar_DEPENDENCIES =							\
-	$(top_builddir)/thunar-vfs/libthunar-vfs.la
+	$(top_builddir)/thunar-vfs/libthunar-vfs.la			\
+	$(top_builddir)/thunarx/libthunarx.la
 
 # install symlink to 'thunar'
 install-data-local:
diff --git a/thunar/main.c b/thunar/main.c
index c847fe983..f375be9be 100644
--- a/thunar/main.c
+++ b/thunar/main.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #endif
 
+#include <thunar/thunar-desktop-window.h>
 #include <thunar/thunar-window.h>
 
 
@@ -58,6 +59,14 @@ main (int argc, char **argv)
   /* initialize the ThunarVFS library */
   thunar_vfs_init ();
 
+  if (argc >= 2 && exo_str_is_equal (argv[1], "--desktop"))
+    {
+      window = thunar_desktop_window_new ();
+      gtk_widget_show (window);
+      gtk_main ();
+      return 0;
+    }
+
   path = (argc > 1) ? argv[1] : xfce_get_homedir ();
 
   uri = thunar_vfs_uri_new (path, &error);
diff --git a/thunar/thunar-desktop-model.c b/thunar/thunar-desktop-model.c
new file mode 100644
index 000000000..059325e8f
--- /dev/null
+++ b/thunar/thunar-desktop-model.c
@@ -0,0 +1,471 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <thunar/thunar-desktop-model.h>
+
+
+
+GType
+thunar_desktop_position_get_type (void)
+{
+  static GType type = G_TYPE_INVALID;
+
+  if (G_UNLIKELY (type == G_TYPE_INVALID))
+    {
+      type = g_boxed_type_register_static ("ThunarDesktopPosition",
+                                           (GBoxedCopyFunc) thunar_desktop_position_dup,
+                                           (GBoxedFreeFunc) thunar_desktop_position_free);
+    }
+
+  return type;
+}
+
+
+
+/**
+ * thunar_desktop_position_dup:
+ * @position : a #ThunarDesktopPosition.
+ *
+ * Returns a duplicate of @position. The caller
+ * is responsible to call #thunar_desktop_position_free()
+ * on the returned object.
+ *
+ * Return value: a duplicate of @position.
+ **/
+ThunarDesktopPosition*
+thunar_desktop_position_dup (const ThunarDesktopPosition *position)
+{
+  g_return_val_if_fail (position != NULL, NULL);
+  return g_memdup (position, sizeof (*position));
+}
+
+
+
+/**
+ * thunar_desktop_position_free:
+ * @position : a #ThunarDesktopPosition.
+ *
+ * Frees the resources allocated for @position.
+ **/
+void
+thunar_desktop_position_free (ThunarDesktopPosition *position)
+{
+  g_return_if_fail (position != NULL);
+
+#ifndef G_DISABLE_CHECKS
+  memset (position, 0xaa, sizeof (*position));
+#endif
+
+  g_free (position);
+}
+
+
+
+
+typedef struct _ThunarDesktopModelItem ThunarDesktopModelItem;
+
+
+
+static void               thunar_desktop_model_class_init       (ThunarDesktopModelClass  *klass);
+static void               thunar_desktop_model_tree_model_init  (GtkTreeModelIface        *iface);
+static void               thunar_desktop_model_init             (ThunarDesktopModel       *model);
+static void               thunar_desktop_model_finalize         (GObject                  *object);
+static GtkTreeModelFlags  thunar_desktop_model_get_flags        (GtkTreeModel             *tree_model);
+static gint               thunar_desktop_model_get_n_columns    (GtkTreeModel             *tree_model);
+static GType              thunar_desktop_model_get_column_type  (GtkTreeModel             *tree_model,
+                                                                 gint                      index);
+static gboolean           thunar_desktop_model_get_iter         (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter,
+                                                                 GtkTreePath              *path);
+static GtkTreePath       *thunar_desktop_model_get_path         (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter);
+static void               thunar_desktop_model_get_value        (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter,
+                                                                 gint                      column,
+                                                                 GValue                   *value);
+static gboolean           thunar_desktop_model_iter_next        (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter);
+static gboolean           thunar_desktop_model_iter_children    (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter,
+                                                                 GtkTreeIter              *parent);
+static gboolean           thunar_desktop_model_iter_has_child   (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter);
+static gint               thunar_desktop_model_iter_n_children  (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter);
+static gboolean           thunar_desktop_model_iter_nth_child   (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter,
+                                                                 GtkTreeIter              *parent,
+                                                                 gint                      n);
+static gboolean           thunar_desktop_model_iter_parent      (GtkTreeModel             *tree_model,
+                                                                 GtkTreeIter              *iter,
+                                                                 GtkTreeIter              *child);
+static void               thunar_desktop_model_item_free        (ThunarDesktopModelItem   *item);
+
+
+
+struct _ThunarDesktopModelClass
+{
+  GObjectClass __parent__;
+};
+
+struct _ThunarDesktopModel
+{
+  GObject __parent__;
+
+  guint   stamp;
+  GList  *items;
+  gint    n_items;
+};
+
+struct _ThunarDesktopModelItem
+{
+  ThunarFile           *file;
+  ThunarDesktopPosition position;
+};
+
+
+
+G_DEFINE_TYPE_WITH_CODE (ThunarDesktopModel,
+                         thunar_desktop_model,
+                         G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+                                                thunar_desktop_model_tree_model_init));
+
+
+
+static void
+thunar_desktop_model_class_init (ThunarDesktopModelClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = thunar_desktop_model_finalize;
+}
+
+
+
+static void
+thunar_desktop_model_tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags = thunar_desktop_model_get_flags;
+  iface->get_n_columns = thunar_desktop_model_get_n_columns;
+  iface->get_column_type = thunar_desktop_model_get_column_type;
+  iface->get_iter = thunar_desktop_model_get_iter;
+  iface->get_path = thunar_desktop_model_get_path;
+  iface->get_value = thunar_desktop_model_get_value;
+  iface->iter_next = thunar_desktop_model_iter_next;
+  iface->iter_children = thunar_desktop_model_iter_children;
+  iface->iter_has_child = thunar_desktop_model_iter_has_child;
+  iface->iter_n_children = thunar_desktop_model_iter_n_children;
+  iface->iter_nth_child = thunar_desktop_model_iter_nth_child;
+  iface->iter_parent = thunar_desktop_model_iter_parent;
+}
+
+
+
+static void
+thunar_desktop_model_init (ThunarDesktopModel *model)
+{
+  ThunarDesktopModelItem *item;
+  ThunarVfsURI           *uri;
+
+  model->stamp = g_random_int ();
+
+  uri = thunar_vfs_uri_new_for_path (xfce_get_homedir ());
+  item = g_new (ThunarDesktopModelItem, 1);
+  item->file = thunar_file_get_for_uri (uri, NULL);
+  item->position.row = 0;
+  item->position.column = 0;
+  item->position.screen_number = 0;
+  model->items = g_list_append (model->items, item);
+  ++model->n_items;
+  thunar_vfs_uri_unref (uri);
+
+  uri = thunar_vfs_uri_new ("trash:", NULL);
+  item = g_new (ThunarDesktopModelItem, 1);
+  item->file = thunar_file_get_for_uri (uri, NULL);
+  item->position.row = 4;
+  item->position.column = 1;
+  item->position.screen_number = 0;
+  model->items = g_list_append (model->items, item);
+  ++model->n_items;
+  thunar_vfs_uri_unref (uri);
+}
+
+
+
+static void
+thunar_desktop_model_finalize (GObject *object)
+{
+  ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (object);
+
+  /* free the desktop items */
+  g_list_foreach (model->items, (GFunc) thunar_desktop_model_item_free, NULL);
+  g_list_free (model->items);
+
+  G_OBJECT_CLASS (thunar_desktop_model_parent_class)->finalize (object);
+}
+
+
+
+static GtkTreeModelFlags
+thunar_desktop_model_get_flags (GtkTreeModel *tree_model)
+{
+  return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+}
+
+
+
+static gint
+thunar_desktop_model_get_n_columns (GtkTreeModel *tree_model)
+{
+  return THUNAR_DESKTOP_MODEL_N_COLUMNS;
+}
+
+
+
+static GType
+thunar_desktop_model_get_column_type (GtkTreeModel *tree_model,
+                                      gint          index)
+{
+  switch (index)
+    {
+    case THUNAR_DESKTOP_MODEL_COLUMN_FILE:
+      return THUNAR_TYPE_FILE;
+
+    case THUNAR_DESKTOP_MODEL_COLUMN_POSITION:
+      return THUNAR_TYPE_DESKTOP_POSITION;
+    }
+
+  g_assert_not_reached ();
+  return G_TYPE_INVALID;
+}
+
+
+
+static gboolean
+thunar_desktop_model_get_iter (GtkTreeModel *tree_model,
+                               GtkTreeIter  *iter,
+                               GtkTreePath  *path)
+{
+  ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model);
+  gint                index;
+
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), FALSE);
+  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+  index = gtk_tree_path_get_indices (path)[0];
+  if (G_UNLIKELY (index >= model->n_items))
+    return FALSE;
+
+  iter->stamp = model->stamp;
+  iter->user_data = g_list_nth (model->items, index);
+
+  return TRUE;
+}
+
+
+
+static GtkTreePath*
+thunar_desktop_model_get_path (GtkTreeModel *tree_model,
+                               GtkTreeIter  *iter)
+{
+  ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model);
+
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), NULL);
+  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
+
+  return gtk_tree_path_new_from_indices (g_list_position (model->items, iter->user_data), -1);
+}
+
+
+
+static void
+thunar_desktop_model_get_value (GtkTreeModel *tree_model,
+                                GtkTreeIter  *iter,
+                                gint          column,
+                                GValue       *value)
+{
+  ThunarDesktopModelItem *item = ((GList *) iter->user_data)->data;
+  ThunarDesktopModel     *model = THUNAR_DESKTOP_MODEL (tree_model);
+
+  g_return_if_fail (THUNAR_IS_DESKTOP_MODEL (model));
+  g_return_if_fail (model->stamp == iter->stamp);
+
+  switch (column)
+    {
+    case THUNAR_DESKTOP_MODEL_COLUMN_FILE:
+      g_value_init (value, THUNAR_TYPE_FILE);
+      g_value_set_object (value, item->file);
+      break;
+
+    case THUNAR_DESKTOP_MODEL_COLUMN_POSITION:
+      g_value_init (value, THUNAR_TYPE_DESKTOP_POSITION);
+      g_value_set_boxed (value, &item->position);
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+
+
+static gboolean
+thunar_desktop_model_iter_next (GtkTreeModel *tree_model,
+                                GtkTreeIter  *iter)
+{
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (tree_model), FALSE);
+  g_return_val_if_fail (iter->stamp == THUNAR_DESKTOP_MODEL (tree_model)->stamp, FALSE);
+
+  iter->user_data = ((GList *) iter->user_data)->next;
+  return (iter->user_data != NULL);
+}
+
+
+
+static gboolean
+thunar_desktop_model_iter_children (GtkTreeModel *tree_model,
+                                    GtkTreeIter  *iter,
+                                    GtkTreeIter  *parent)
+{
+  ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model);
+
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), FALSE);
+  g_return_val_if_fail (parent == NULL || parent->stamp == model->stamp, FALSE);
+
+  if (G_LIKELY (parent == NULL && model->items != NULL))
+    {
+      iter->stamp = model->stamp;
+      iter->user_data = model->items;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_desktop_model_iter_has_child (GtkTreeModel *tree_model,
+                                     GtkTreeIter  *iter)
+{
+  return FALSE;
+}
+
+
+
+static gint
+thunar_desktop_model_iter_n_children (GtkTreeModel *tree_model,
+                                      GtkTreeIter  *iter)
+{
+  ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model);
+
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), 0);
+  g_return_val_if_fail (iter == NULL || iter->stamp == model->stamp, 0);
+
+  return (iter == NULL) ? model->n_items : 0;
+}
+
+
+
+static gboolean
+thunar_desktop_model_iter_nth_child (GtkTreeModel *tree_model,
+                                     GtkTreeIter  *iter,
+                                     GtkTreeIter  *parent,
+                                     gint          n)
+{
+  ThunarDesktopModel *model = THUNAR_DESKTOP_MODEL (tree_model);
+
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_MODEL (model), FALSE);
+  g_return_val_if_fail (parent == NULL || parent->stamp == model->stamp, FALSE);
+
+  if (G_LIKELY (parent == NULL && n < model->n_items))
+    {
+      iter->stamp = model->stamp;
+      iter->user_data = g_list_nth (model->items, n);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_desktop_model_iter_parent (GtkTreeModel *tree_model,
+                                  GtkTreeIter  *iter,
+                                  GtkTreeIter  *child)
+{
+  return FALSE;
+}
+
+
+
+static void
+thunar_desktop_model_item_free (ThunarDesktopModelItem *item)
+{
+  g_object_unref (G_OBJECT (item->file));
+  g_free (item);
+}
+
+
+
+/**
+ * thunar_desktop_model_get_default:
+ *
+ * Returns the default #ThunarDesktopModel instance,
+ * which is shared by all #ThunarDesktopView<!---->s.
+ *
+ * The caller is responsible to free the returned
+ * object using #g_object_unref().
+ *
+ * Return value: the default #ThunarDesktopModel.
+ **/
+ThunarDesktopModel*
+thunar_desktop_model_get_default (void)
+{
+  static ThunarDesktopModel *model = NULL;
+
+  if (G_LIKELY (model == NULL))
+    {
+      model = g_object_new (THUNAR_TYPE_DESKTOP_MODEL, NULL);
+      g_object_add_weak_pointer (G_OBJECT (model), (gpointer) &model);
+    }
+  else
+    {
+      g_object_ref (G_OBJECT (model));
+    }
+
+  return model;
+}
+
+
+
diff --git a/thunar/thunar-desktop-model.h b/thunar/thunar-desktop-model.h
new file mode 100644
index 000000000..7a1e9a42a
--- /dev/null
+++ b/thunar/thunar-desktop-model.h
@@ -0,0 +1,67 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __THUNAR_DESKTOP_MODEL_H__
+#define __THUNAR_DESKTOP_MODEL_H__
+
+#include <thunar/thunar-file.h>
+
+G_BEGIN_DECLS;
+
+typedef struct _ThunarDesktopPosition ThunarDesktopPosition;
+
+#define THUNAR_TYPE_DESKTOP_POSITION (thunar_desktop_position_get_type ())
+
+struct _ThunarDesktopPosition
+{
+  gint row;
+  gint column;
+  gint screen_number;
+};
+
+GType                  thunar_desktop_position_get_type (void) G_GNUC_CONST;
+
+ThunarDesktopPosition *thunar_desktop_position_dup      (const ThunarDesktopPosition *position) G_GNUC_MALLOC;
+void                   thunar_desktop_position_free     (ThunarDesktopPosition       *position);
+
+
+typedef struct _ThunarDesktopModelClass ThunarDesktopModelClass;
+typedef struct _ThunarDesktopModel      ThunarDesktopModel;
+
+#define THUNAR_TYPE_DESKTOP_MODEL             (thunar_desktop_model_get_type ())
+#define THUNAR_DESKTOP_MODEL(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DESKTOP_MODEL, ThunarDesktopModel))
+#define THUNAR_DESKTOP_MODEL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DESKTOP_MODEL, ThunarDesktopModelClass))
+#define THUNAR_IS_DESKTOP_MODEL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DESKTOP_MODEL))
+#define THUNAR_IS_DESKTOP_MODEL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_DESKTOP_MODEL))
+#define THUNAR_DESKTOP_MODEL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_MODEL, ThunarDesktopModelClass))
+
+enum
+{
+  THUNAR_DESKTOP_MODEL_COLUMN_FILE,
+  THUNAR_DESKTOP_MODEL_COLUMN_POSITION,
+  THUNAR_DESKTOP_MODEL_N_COLUMNS,
+};
+
+GType               thunar_desktop_model_get_type     (void) G_GNUC_CONST;
+
+ThunarDesktopModel *thunar_desktop_model_get_default  (void);
+
+G_END_DECLS;
+
+#endif /* !__THUNAR_DESKTOP_MODEL_H__ */
diff --git a/thunar/thunar-desktop-view.c b/thunar/thunar-desktop-view.c
index 157bedc50..d1eecfd9d 100644
--- a/thunar/thunar-desktop-view.c
+++ b/thunar/thunar-desktop-view.c
@@ -21,33 +21,81 @@
 #include <config.h>
 #endif
 
-#include <exo/exo.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
 
+#include <thunar/thunar-desktop-model.h>
 #include <thunar/thunar-desktop-view.h>
+#include <thunar/thunar-file.h>
+
+#include <thunarx/thunarx-gdk-pixbuf-extensions.h>
+
+
+
+#define TILE_WIDTH  (48)
+#define TILE_HEIGHT (32)
+
 
 
+typedef struct _ThunarDesktopViewItem ThunarDesktopViewItem;
 
 enum
 {
   PROP_0,
-  PROP_DISPLAY,
+  PROP_ICON_SIZE,
+  PROP_MODEL,
+  PROP_FILE_COLUMN,
+  PROP_POSITION_COLUMN,
 };
 
 
 
-static void thunar_desktop_view_class_init    (ThunarDesktopViewClass *klass);
-static void thunar_desktop_view_init          (ThunarDesktopView      *view);
-static void thunar_desktop_view_finalize      (GObject                *object);
-static void thunar_desktop_view_get_property  (GObject                *object,
-                                               guint                   prop_id,
-                                               GValue                 *value,
-                                               GParamSpec             *pspec);
-static void thunar_desktop_view_set_property  (GObject                *object,
-                                               guint                   prop_id,
-                                               const GValue           *value,
-                                               GParamSpec             *pspec);
-static void thunar_desktop_view_realize       (GtkWidget              *widget);
-static void thunar_desktop_view_unrealize     (GtkWidget              *widget);
+static void                   thunar_desktop_view_class_init          (ThunarDesktopViewClass *klass);
+static void                   thunar_desktop_view_init                (ThunarDesktopView      *view);
+static void                   thunar_desktop_view_finalize            (GObject                *object);
+static void                   thunar_desktop_view_get_property        (GObject                *object,
+                                                                       guint                   prop_id,
+                                                                       GValue                 *value,
+                                                                       GParamSpec             *pspec);
+static void                   thunar_desktop_view_set_property        (GObject                *object,
+                                                                       guint                   prop_id,
+                                                                       const GValue           *value,
+                                                                       GParamSpec             *pspec);
+static void                   thunar_desktop_view_destroy             (GtkObject              *object);
+static void                   thunar_desktop_view_size_request        (GtkWidget              *widget,
+                                                                       GtkRequisition         *requisition);
+static gboolean               thunar_desktop_view_button_press_event  (GtkWidget              *widget,
+                                                                       GdkEventButton         *event);
+static gboolean               thunar_desktop_view_expose_event        (GtkWidget              *widget,
+                                                                       GdkEventExpose         *event);
+static void                   thunar_desktop_view_build_items         (ThunarDesktopView      *view);
+static ThunarDesktopViewItem *thunar_desktop_view_get_item_at_pos     (ThunarDesktopView      *view,
+                                                                       gint                    x,
+                                                                       gint                    y);
+static void                   thunar_desktop_view_get_item_area       (ThunarDesktopView      *view,
+                                                                       ThunarDesktopViewItem  *item,
+                                                                       GdkRectangle           *area);
+static void                   thunar_desktop_view_render_item         (ThunarDesktopView      *view,
+                                                                       ThunarDesktopViewItem  *item,
+                                                                       GdkRectangle           *item_area,
+                                                                       GdkRectangle           *expose_area);
+static void                   thunar_desktop_view_queue_render_item   (ThunarDesktopView      *view,
+                                                                       ThunarDesktopViewItem  *item);
+static void                   thunar_desktop_view_row_changed         (GtkTreeModel           *model,
+                                                                       GtkTreePath            *path,
+                                                                       GtkTreeIter            *iter,
+                                                                       ThunarDesktopView      *view);
+static void                   thunar_desktop_view_row_inserted        (GtkTreeModel           *model,
+                                                                       GtkTreePath            *path,
+                                                                       GtkTreeIter            *iter,
+                                                                       ThunarDesktopView      *view);
+static void                   thunar_desktop_view_row_deleted         (GtkTreeModel           *model,
+                                                                       GtkTreePath            *path,
+                                                                       ThunarDesktopView      *view);
 
 
 
@@ -60,7 +108,23 @@ struct _ThunarDesktopView
 {
   GtkWidget __parent__;
 
-  GdkDisplay *display;
+  PangoLayout  *layout;
+
+  GList        *items;
+
+  GtkTreeModel *model;
+
+  gint          icon_size;
+
+  gint          file_column;
+  gint          position_column;
+};
+
+struct _ThunarDesktopViewItem
+{
+  ThunarDesktopPosition position;
+  GtkTreeIter           iter;
+  gboolean              selected : 1;
 };
 
 
@@ -72,6 +136,7 @@ G_DEFINE_TYPE (ThunarDesktopView, thunar_desktop_view, GTK_TYPE_WIDGET);
 static void
 thunar_desktop_view_class_init (ThunarDesktopViewClass *klass)
 {
+  GtkObjectClass *gtkobject_class;
   GtkWidgetClass *gtkwidget_class;
   GObjectClass   *gobject_class;
 
@@ -80,24 +145,65 @@ thunar_desktop_view_class_init (ThunarDesktopViewClass *klass)
   gobject_class->get_property = thunar_desktop_view_get_property;
   gobject_class->set_property = thunar_desktop_view_set_property;
 
+  gtkobject_class = GTK_OBJECT_CLASS (klass);
+  gtkobject_class->destroy = thunar_desktop_view_destroy;
+
   gtkwidget_class = GTK_WIDGET_CLASS (klass);
-  gtkwidget_class->realize = thunar_desktop_view_realize;
-  gtkwidget_class->unrealize = thunar_desktop_view_unrealize;
+  gtkwidget_class->size_request = thunar_desktop_view_size_request;
+  gtkwidget_class->button_press_event = thunar_desktop_view_button_press_event;
+  gtkwidget_class->expose_event = thunar_desktop_view_expose_event;
+
+  /**
+   * ThunarDesktopView:icon-size:
+   *
+   * The icon size in pixels.
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_ICON_SIZE,
+                                   g_param_spec_int ("icon-size",
+                                                     _("Icon size"),
+                                                     _("The icon size in pixels"),
+                                                     1, G_MAXINT, 48,
+                                                     EXO_PARAM_READWRITE));
+
+  /**
+   * ThunarDesktopView:model:
+   *
+   * The model which is displayed by this #ThunarDesktopView.
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_MODEL,
+                                   g_param_spec_object ("model",
+                                                        _("Model"),
+                                                        _("The model to display"),
+                                                        GTK_TYPE_TREE_MODEL,
+                                                        EXO_PARAM_READWRITE));
+
+  /**
+   * ThunarDesktopView:file-column:
+   *
+   * The column in the model which contains the #ThunarFile.
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_FILE_COLUMN,
+                                   g_param_spec_int ("file-column",
+                                                     _("File column"), 
+                                                     _("The column which contains the file"),
+                                                     -1, G_MAXINT, -1,
+                                                     EXO_PARAM_READWRITE));
 
   /**
-   * ThunarDesktopView:display:
+   * ThunarDesktopView:position-column:
    *
-   * The #GdkDisplay covered by this desktop view or %NULL if
-   * the desktop view is not currently connected to any
-   * display.
+   * The column in the model which contains the location (as #ThunarDesktopPosition).
    **/
   g_object_class_install_property (gobject_class,
-                                   PROP_DISPLAY,
-                                   g_param_spec_object ("display",
-                                                        _("Display"),
-                                                        _("The display currently associated with"),
-                                                        GDK_TYPE_DISPLAY,
-                                                        G_PARAM_READWRITE));
+                                   PROP_POSITION_COLUMN,
+                                   g_param_spec_int ("position-column",
+                                                     _("Position column"),
+                                                     _("The column which contains the position"),
+                                                     -1, G_MAXINT, -1,
+                                                     EXO_PARAM_READWRITE));
 }
 
 
@@ -105,6 +211,17 @@ thunar_desktop_view_class_init (ThunarDesktopViewClass *klass)
 static void
 thunar_desktop_view_init (ThunarDesktopView *view)
 {
+  GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS);
+  GTK_WIDGET_SET_FLAGS (view, GTK_NO_WINDOW);
+
+  view->layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL);
+  pango_layout_set_alignment (view->layout, PANGO_ALIGN_CENTER);
+  pango_layout_set_wrap (view->layout, PANGO_WRAP_WORD_CHAR);
+
+  view->file_column = -1;
+  view->position_column = -1;
+
+  thunar_desktop_view_set_icon_size (view, 48);
 }
 
 
@@ -114,9 +231,9 @@ thunar_desktop_view_finalize (GObject *object)
 {
   ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (object);
 
-  g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view));
+  g_object_unref (G_OBJECT (view->layout));
 
-  G_OBJECT_CLASS (thunar_desktop_view_parent_class)->finalize (object);
+  (*G_OBJECT_CLASS (thunar_desktop_view_parent_class)->finalize) (object);
 }
 
 
@@ -131,8 +248,20 @@ thunar_desktop_view_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_DISPLAY:
-      g_value_set_object (value, thunar_desktop_view_get_display (view));
+    case PROP_ICON_SIZE:
+      g_value_set_int (value, thunar_desktop_view_get_icon_size (view));
+      break;
+
+    case PROP_MODEL:
+      g_value_set_object (value, thunar_desktop_view_get_model (view));
+      break;
+
+    case PROP_FILE_COLUMN:
+      g_value_set_int (value, thunar_desktop_view_get_file_column (view));
+      break;
+
+    case PROP_POSITION_COLUMN:
+      g_value_set_int (value, thunar_desktop_view_get_position_column (view));
       break;
 
     default:
@@ -144,17 +273,29 @@ thunar_desktop_view_get_property (GObject    *object,
 
 
 static void
-thunar_desktop_view_set_property  (GObject      *object,
-                                   guint         prop_id,
-                                   const GValue *value,
-                                   GParamSpec   *pspec)
+thunar_desktop_view_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
 {
   ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (object);
 
   switch (prop_id)
     {
-    case PROP_DISPLAY:
-      thunar_desktop_view_set_display (view, g_value_get_object (value));
+    case PROP_ICON_SIZE:
+      thunar_desktop_view_set_icon_size (view, g_value_get_int (value));
+      break;
+
+    case PROP_MODEL:
+      thunar_desktop_view_set_model (view, g_value_get_object (value));
+      break;
+
+    case PROP_FILE_COLUMN:
+      thunar_desktop_view_set_file_column (view, g_value_get_int (value));
+      break;
+
+    case PROP_POSITION_COLUMN:
+      thunar_desktop_view_set_position_column (view, g_value_get_int (value));
       break;
 
     default:
@@ -166,24 +307,293 @@ thunar_desktop_view_set_property  (GObject      *object,
 
 
 static void
-thunar_desktop_view_realize (GtkWidget *widget)
+thunar_desktop_view_destroy (GtkObject *object)
 {
-  ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (widget);
+  ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (object);
+
+  thunar_desktop_view_set_model (view, NULL);
 
-  // TODO: Create one GdkWindow per screen (each spanning
-  // all monitors connected to the given screen)
-  (void)&view;
+  (*GTK_OBJECT_CLASS (thunar_desktop_view_parent_class)->destroy) (object);
 }
 
 
 
 static void
-thunar_desktop_view_unrealize (GtkWidget *widget)
+thunar_desktop_view_size_request (GtkWidget      *widget,
+                                  GtkRequisition *requisition)
 {
   ThunarDesktopView *view = THUNAR_DESKTOP_VIEW (widget);
 
-  // TODO: Destroy all previously created GdkWindow's
-  (void)&view;
+  requisition->width = view->icon_size;
+  requisition->height = view->icon_size;
+}
+
+
+
+static gboolean
+thunar_desktop_view_button_press_event (GtkWidget      *widget,
+                                        GdkEventButton *event)
+{
+  ThunarDesktopViewItem *item;
+  ThunarDesktopView     *view = THUNAR_DESKTOP_VIEW (widget);
+
+  if (!GTK_WIDGET_HAS_FOCUS (widget))
+    gtk_widget_grab_focus (widget);
+
+  if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
+    {
+      item = thunar_desktop_view_get_item_at_pos (view, event->x, event->y);
+      if (item != NULL)
+        {
+          item->selected = TRUE;
+          thunar_desktop_view_queue_render_item (view, item);
+        }
+      else
+        {
+          thunar_desktop_view_unselect_all (view);
+        }
+    }
+
+  return (event->button == 1);
+}
+
+
+
+static gboolean
+thunar_desktop_view_expose_event (GtkWidget      *widget,
+                                  GdkEventExpose *event)
+{
+  ThunarDesktopViewItem *item;
+  ThunarDesktopView     *view = THUNAR_DESKTOP_VIEW (widget);
+  GdkRectangle           item_area;
+  GList                 *lp;
+  gint                   screen_number;
+
+  /* check if all necessary attributes are set */
+  if (view->model == NULL || view->file_column < 0 || view->position_column < 0)
+    return FALSE;
+
+  screen_number = gdk_screen_get_number (gtk_widget_get_screen (widget));
+
+  for (lp = view->items; lp != NULL; lp = lp->next)
+    {
+      item = lp->data;
+
+      /* check if the item should be display on this screen */
+      if (G_UNLIKELY (item->position.screen_number != screen_number))
+        continue;
+
+      thunar_desktop_view_get_item_area (view, item, &item_area);
+
+      if (gdk_region_rect_in (event->region, &item_area) != GDK_OVERLAP_RECTANGLE_OUT)
+        thunar_desktop_view_render_item (view, item, &item_area, &event->area);
+    }
+
+  return TRUE;
+}
+
+
+
+static void
+thunar_desktop_view_build_items (ThunarDesktopView *view)
+{
+  ThunarDesktopViewItem *item;
+  GtkTreeIter            iter;
+  GValue                 value = { 0, };
+
+  if (gtk_tree_model_get_iter_first (view->model, &iter))
+    {
+      do
+        {
+          item = g_new (ThunarDesktopViewItem, 1);
+          item->iter = iter;
+
+          if (G_LIKELY (view->position_column >= 0))
+            {
+              gtk_tree_model_get_value (view->model, &item->iter, view->position_column, &value);
+              item->position = *((ThunarDesktopPosition *) g_value_get_boxed (&value));
+              g_value_unset (&value);
+            }
+          else
+            memset (&item->position, 0, sizeof (item->position));
+
+          view->items = g_list_prepend (view->items, item);
+        }
+      while (gtk_tree_model_iter_next (view->model, &iter));
+    }
+}
+
+
+
+static ThunarDesktopViewItem*
+thunar_desktop_view_get_item_at_pos (ThunarDesktopView *view,
+                                     gint               x,
+                                     gint               y)
+{
+  ThunarDesktopViewItem *item;
+  GdkRectangle           item_area;
+  GdkRectangle           icon_area;
+  GdkRectangle           text_area;
+  ThunarFile            *file;
+  GdkRegion             *region;
+  GdkPixbuf             *icon;
+  GList                 *lp;
+
+  region = gdk_region_new ();
+
+  for (lp = view->items; lp != NULL; lp = lp->next)
+    {
+      item = lp->data;
+      thunar_desktop_view_get_item_area (view, item, &item_area);
+
+      gtk_tree_model_get (view->model, &item->iter, view->file_column, &file, -1);
+
+      /* add the icon area */
+      icon = thunar_file_load_icon (file, view->icon_size);
+      icon_area.width = gdk_pixbuf_get_width (icon);
+      icon_area.height = gdk_pixbuf_get_height (icon);
+      icon_area.x = item_area.x + (TILE_WIDTH * 2 - icon_area.width) / 2;
+      icon_area.y = item_area.y + (TILE_HEIGHT * 2 - icon_area.height) / 2;
+      gdk_region_union_with_rect (region, &icon_area);
+      g_object_unref (G_OBJECT (icon));
+
+      /* add the text area */
+      pango_layout_set_text (view->layout, thunar_file_get_special_name (file), -1);
+      pango_layout_set_width (view->layout, item_area.width * PANGO_SCALE);
+      pango_layout_get_pixel_size (view->layout, &text_area.width, &text_area.height);
+      text_area.x = item_area.x + (item_area.width - text_area.width) / 2;
+      text_area.y = item_area.y + TILE_HEIGHT * 2;
+      gdk_region_union_with_rect (region, &text_area);
+
+      g_object_unref (G_OBJECT (file));
+
+      if (gdk_region_point_in (region, x, y))
+        return item;
+    }
+
+  return NULL;
+}
+
+
+
+static void
+thunar_desktop_view_get_item_area (ThunarDesktopView     *view,
+                                   ThunarDesktopViewItem *item,
+                                   GdkRectangle          *area)
+{
+  area->x = item->position.column * TILE_WIDTH + GTK_WIDGET (view)->allocation.x;
+  area->y = item->position.row * TILE_HEIGHT + GTK_WIDGET (view)->allocation.y;
+  area->width = TILE_WIDTH * 2;
+  area->height = TILE_HEIGHT * 3;
+}
+
+
+
+static void
+thunar_desktop_view_render_item (ThunarDesktopView     *view,
+                                 ThunarDesktopViewItem *item,
+                                 GdkRectangle          *item_area,
+                                 GdkRectangle          *expose_area)
+{
+  GdkRectangle draw_area;
+  GdkRectangle icon_area;
+  GdkRectangle text_area;
+  ThunarFile *file;
+  GdkPixbuf  *colorized_icon;
+  GdkPixbuf  *icon;
+
+  gtk_tree_model_get (view->model, &item->iter, view->file_column, &file, -1);
+
+  icon = thunar_file_load_icon (file, view->icon_size);
+
+  icon_area.width = gdk_pixbuf_get_width (icon);
+  icon_area.height = gdk_pixbuf_get_height (icon);
+  icon_area.x = item_area->x + (TILE_WIDTH * 2 - icon_area.width) / 2;
+  icon_area.y = item_area->y + (TILE_HEIGHT * 2 - icon_area.height) / 2;
+
+  if (gdk_rectangle_intersect (expose_area, &icon_area, &draw_area))
+    {
+      if (G_UNLIKELY (item->selected))
+        {
+          colorized_icon = thunarx_gdk_pixbuf_colorize (icon, &GTK_WIDGET (view)->style->base[GTK_STATE_SELECTED]);
+          g_object_unref (G_OBJECT (icon));
+          icon = colorized_icon;
+        }
+
+      gdk_draw_pixbuf (GTK_WIDGET (view)->window, GTK_WIDGET (view)->style->black_gc, icon,
+                       draw_area.x - icon_area.x, draw_area.y - icon_area.y,
+                       draw_area.x, draw_area.y, draw_area.width, draw_area.height,
+                       GDK_RGB_DITHER_NORMAL, 0, 0);
+    }
+
+  text_area.x = item_area->x;
+  text_area.y = item_area->y + TILE_HEIGHT * 2;
+  text_area.width = 2 * TILE_WIDTH;
+  text_area.height = TILE_HEIGHT;
+
+  if (gdk_rectangle_intersect (expose_area, &text_area, &draw_area))
+    {
+      pango_layout_set_text (view->layout, thunar_file_get_special_name (file), -1);
+      pango_layout_set_width (view->layout, text_area.width * PANGO_SCALE);
+
+      gtk_paint_layout (GTK_WIDGET (view)->style, GTK_WIDGET (view)->window,
+                        item->selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL,
+                        TRUE, expose_area, GTK_WIDGET (view), "icon_view",
+                        text_area.x, text_area.y, view->layout);
+    }
+
+  g_object_unref (G_OBJECT (file));
+  g_object_unref (G_OBJECT (icon));
+}
+
+
+
+static void
+thunar_desktop_view_queue_render_item (ThunarDesktopView     *view,
+                                       ThunarDesktopViewItem *item)
+{
+  GdkRectangle item_area;
+
+  if (G_LIKELY (GTK_WIDGET_REALIZED (view)))
+    {
+      thunar_desktop_view_get_item_area (view, item, &item_area);
+      gdk_window_invalidate_rect (GTK_WIDGET (view)->window, &item_area, FALSE);
+    }
+}
+
+
+
+static void
+thunar_desktop_view_row_changed (GtkTreeModel      *model,
+                                 GtkTreePath       *path,
+                                 GtkTreeIter       *iter,
+                                 ThunarDesktopView *view)
+{
+  // FIXME: Implement this
+  g_error ("Not implemented!");
+}
+
+
+
+static void
+thunar_desktop_view_row_inserted (GtkTreeModel      *model,
+                                  GtkTreePath       *path,
+                                  GtkTreeIter       *iter,
+                                  ThunarDesktopView *view)
+{
+  // FIXME: Implement this
+  g_error ("Not implemented!");
+}
+
+
+
+static void
+thunar_desktop_view_row_deleted (GtkTreeModel      *model,
+                                 GtkTreePath       *path,
+                                 ThunarDesktopView *view)
+{
+  // FIXME: Implement this
+  g_error ("Not implemented!");
 }
 
 
@@ -191,12 +601,9 @@ thunar_desktop_view_unrealize (GtkWidget *widget)
 /**
  * thunar_desktop_view_new:
  *
- * Creates a new #ThunarDesktopView, which is associated with
- * no #GdkDisplay. You'll need to set a display using
- * #thunar_desktop_view_set_display() before realizing the
- * view.
+ * Allocates a new #ThunarDesktopView instance.
  *
- * Return value: the newly allocated #ThunarDesktopView instance.
+ * Return value: the newly allocated #ThunarDesktopView.
  **/
 GtkWidget*
 thunar_desktop_view_new (void)
@@ -207,80 +614,262 @@ thunar_desktop_view_new (void)
 
 
 /**
- * thunar_desktop_view_new_with_display:
- * @display : a valid #GdkDisplay.
+ * thunar_desktop_view_get_icon_size:
+ * @view : a #ThunarDesktopView.
  *
- * Creates a new #ThunarDesktop and associates it with the given
- * @display. You can instantly show (and thereby realize) the
- * returned object.
+ * Returns the icon size set for @view.
  *
- * Return value: the newly allocated #ThunarDesktopView instance.
+ * Return value: the icon size for @view.
  **/
-GtkWidget*
-thunar_desktop_view_new_with_display (GdkDisplay *display)
+gint
+thunar_desktop_view_get_icon_size (ThunarDesktopView *view)
+{
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), -1);
+  return view->icon_size;
+}
+
+
+
+/**
+ * thunar_desktop_view_set_icon_size:
+ * @view      : a #ThunarDesktopView.
+ * @icon_size : the new icon size for @view.
+ *
+ * Sets the icon size for @view to @icon_size.
+ **/
+void
+thunar_desktop_view_set_icon_size (ThunarDesktopView *view,
+                                   gint               icon_size)
 {
-  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view));
+  g_return_if_fail (icon_size > 0);
 
-  return g_object_new (THUNAR_TYPE_DESKTOP_VIEW,
-                       "display", display,
-                       NULL);
+  if (G_LIKELY (view->icon_size != icon_size))
+    {
+      view->icon_size = icon_size;
+      gtk_widget_queue_resize (GTK_WIDGET (view));
+      g_object_notify (G_OBJECT (view), "icon-size");
+    }
 }
 
 
 
 /**
- * thunar_desktop_view_get_display:
+ * thunar_desktop_view_get_model:
  * @view : a #ThunarDesktopView.
  *
- * Queries the #GdkDisplay currently used by the @view. May return
- * %NULL if no display has been set yet.
+ * Returns the #GtkTreeModel set for @view.
  *
- * Return value: the #GdkDisplay @view is associated with or %NULL.
+ * Return value: the model of @view.
  **/
-GdkDisplay*
-thunar_desktop_view_get_display (ThunarDesktopView *view)
+GtkTreeModel*
+thunar_desktop_view_get_model (ThunarDesktopView *view)
 {
   g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), NULL);
-  return view->display;
+  return view->model;
 }
 
 
 
 /**
- * thunar_desktop_view_set_display:
- * @view    : a #ThunarDesktopView.
- * @display : a #GdkDisplay or %NULL.
+ * thunar_desktop_view_set_model:
+ * @view  : a #ThunarDesktopView.
+ * @model : a #GtkTreeModel or %NULL.
  *
- * Sets the display to use for @view to @display. If @view was
- * previously connected to another #GdkDisplay, it'll first
- * disconnect from the old display, then connect to the new
- * display.
+ * Sets the model to use for @view to @model.
  **/
 void
-thunar_desktop_view_set_display (ThunarDesktopView *view,
-                                 GdkDisplay        *display)
+thunar_desktop_view_set_model (ThunarDesktopView *view,
+                               GtkTreeModel      *model)
 {
+  GType type;
+
   g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view));
-  g_return_if_fail (display == NULL || GDK_IS_DISPLAY (display));
+  g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
 
-  /* don't do anything if we already use that display */
-  if (G_UNLIKELY (display == view->display))
+  if (G_UNLIKELY (view->model == model))
     return;
 
-  if (view->display != NULL)
+  /* verify the new model (if any) */
+  if (G_LIKELY (model != NULL))
+    {
+      g_return_if_fail ((gtk_tree_model_get_flags (model) & (GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY)) != 0);
+
+      if (view->file_column >= 0)
+        {
+          type = gtk_tree_model_get_column_type (model, view->file_column);
+          g_return_if_fail (type == THUNAR_TYPE_FILE);
+        }
+
+      if (view->position_column >= 0)
+        {
+          type = gtk_tree_model_get_column_type (model, view->position_column);
+          g_return_if_fail (type == THUNAR_TYPE_DESKTOP_POSITION);
+        }
+    }
+
+  /* disconnect from the previous model */
+  if (G_LIKELY (view->model != NULL))
+    {
+      /* disconnect signals */
+      g_signal_handlers_disconnect_by_func (G_OBJECT (view->model), thunar_desktop_view_row_changed, view);
+      g_signal_handlers_disconnect_by_func (G_OBJECT (view->model), thunar_desktop_view_row_inserted, view);
+      g_signal_handlers_disconnect_by_func (G_OBJECT (view->model), thunar_desktop_view_row_deleted, view);
+
+      /* drop items */
+      g_list_foreach (view->items, (GFunc) g_free, NULL);
+      g_list_free (view->items);
+      view->items = NULL;
+
+      /* drop the model */
+      g_object_unref (G_OBJECT (view->model));
+    }
+
+  /* activate the new model */
+  view->model = model;
+
+  /* connect to the new model */
+  if (G_LIKELY (model != NULL))
+    {
+      /* connect signals */
+      g_signal_connect (G_OBJECT (model), "row-changed", G_CALLBACK (thunar_desktop_view_row_changed), view);
+      g_signal_connect (G_OBJECT (model), "row-inserted", G_CALLBACK (thunar_desktop_view_row_inserted), view);
+      g_signal_connect (G_OBJECT (model), "row-deleted", G_CALLBACK (thunar_desktop_view_row_deleted), view);
+
+      /* generate the items */
+      thunar_desktop_view_build_items (view);
+
+      /* take a reference on the model */
+      g_object_ref (G_OBJECT (model));
+    }
+
+  gtk_widget_queue_draw (GTK_WIDGET (view));
+  g_object_notify (G_OBJECT (view), "model");
+}
+
+
+
+/**
+ * thunar_desktop_view_get_file_column:
+ * @view : a #ThunarDesktopView.
+ *
+ * Return value: the file column or -1.
+ **/
+gint
+thunar_desktop_view_get_file_column (ThunarDesktopView *view)
+{
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), -1);
+  return view->file_column;
+}
+
+
+
+/**
+ * thunar_desktop_view_set_file_column:
+ * @view        : a #ThunarDesktopView.
+ * @file_column : the new file column or -1.
+ **/
+void
+thunar_desktop_view_set_file_column (ThunarDesktopView *view,
+                                     gint               file_column)
+{
+  g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view));
+  g_return_if_fail (file_column == -1 || file_column >= 0);
+
+  if (G_LIKELY (view->file_column != file_column))
     {
-      // TODO: Disconnect from the old display (take into account the
-      // REALIZED state)
+      view->file_column = file_column;
+      gtk_widget_queue_draw (GTK_WIDGET (view));
+      g_object_notify (G_OBJECT (view), "file-column");
     }
+}
+
 
-  view->display = display;
 
-  if (view->display != NULL)
+/**
+ * thunar_desktop_view_get_position_column:
+ * @view : a #ThunarDesktopView.
+ *
+ * Returns the position column.
+ *
+ * Return value: the position column or -1.
+ **/
+gint
+thunar_desktop_view_get_position_column (ThunarDesktopView *view)
+{
+  g_return_val_if_fail (THUNAR_IS_DESKTOP_VIEW (view), -1);
+  return view->position_column;
+}
+
+
+
+/**
+ * thunar_desktop_view_set_position_column:
+ * @view            : a #ThunarDesktopView.
+ * @position_column : the new position column or -1.
+ **/
+void
+thunar_desktop_view_set_position_column (ThunarDesktopView *view,
+                                         gint               position_column)
+{
+  ThunarDesktopViewItem *item;
+  GValue                 value = { 0, };
+  GList                 *lp;
+
+  g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view));
+  g_return_if_fail (position_column == -1 || position_column >= 0);
+  
+  if (G_LIKELY (view->position_column != position_column))
     {
-      // TODO: Connect to the new display (take into account the
-      // REALIZED state)
+      /* update all item positions */
+      if (G_LIKELY (view->model != NULL))
+        {
+          for (lp = view->items; lp != NULL; lp = lp->next)
+            {
+              item = lp->data;
+              if (G_LIKELY (position_column >= 0))
+                {
+                  gtk_tree_model_get_value (view->model, &item->iter, position_column, &value);
+                  item->position = *((ThunarDesktopPosition *) g_value_get_boxed (&value));
+                  g_value_unset (&value);
+                }
+              else
+                memset (&item->position, 0, sizeof (item->position));
+            }
+         }
+
+      /* apply the new column */
+      view->position_column = position_column;
+      gtk_widget_queue_draw (GTK_WIDGET (view));
+      g_object_notify (G_OBJECT (view), "position-column");
     }
+}
+
+
 
-  /* notify listeners */
-  g_object_notify (G_OBJECT (view), "display");
+/**
+ * thunar_desktop_view_unselect_all:
+ * @view : a #ThunarDesktopView.
+ *
+ * Unselects all selected items in @view.
+ **/
+void
+thunar_desktop_view_unselect_all (ThunarDesktopView *view)
+{
+  ThunarDesktopViewItem *item;
+  GList                 *lp;
+
+  g_return_if_fail (THUNAR_IS_DESKTOP_VIEW (view));
+
+  for (lp = view->items; lp != NULL; lp = lp->next)
+    {
+      item = lp->data;
+      if (G_UNLIKELY (item->selected))
+        {
+          item->selected = FALSE;
+          thunar_desktop_view_queue_render_item (view, item);
+        }
+    }
 }
+
+
diff --git a/thunar/thunar-desktop-view.h b/thunar/thunar-desktop-view.h
index 7963ee91c..9311a80ff 100644
--- a/thunar/thunar-desktop-view.h
+++ b/thunar/thunar-desktop-view.h
@@ -22,28 +22,39 @@
 
 #include <gtk/gtk.h>
 
-#include <thunar/thunar-preferences.h>
-
 G_BEGIN_DECLS;
 
-typedef struct _ThunarDesktopViewClass  ThunarDesktopViewClass;
-typedef struct _ThunarDesktopView       ThunarDesktopView;
+typedef struct _ThunarDesktopViewClass ThunarDesktopViewClass;
+typedef struct _ThunarDesktopView      ThunarDesktopView;
 
 #define THUNAR_TYPE_DESKTOP_VIEW            (thunar_desktop_view_get_type ())
 #define THUNAR_DESKTOP_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopView))
 #define THUNAR_DESKTOP_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopViewClass))
 #define THUNAR_IS_DESKTOP_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DESKTOP_VIEW))
 #define THUNAR_IS_DESKTOP_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_DESKTOP_VIEW))
-#define THUNAR_DESKTOP_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopViewClass))
+#define THUNAR_DESKTOP_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_VIEW, ThunarDesktopView))
+
+GType         thunar_desktop_view_get_type             (void) G_GNUC_CONST;
+
+GtkWidget    *thunar_desktop_view_new                  (void);
+
+gint          thunar_desktop_view_get_icon_size        (ThunarDesktopView *view);
+void          thunar_desktop_view_set_icon_size        (ThunarDesktopView *view,
+                                                        gint               icon_size);
+
+GtkTreeModel *thunar_desktop_view_get_model            (ThunarDesktopView *view);
+void          thunar_desktop_view_set_model            (ThunarDesktopView *view,
+                                                        GtkTreeModel      *model);
 
-GType       thunar_desktop_view_get_type         (void) G_GNUC_CONST;
+gint          thunar_desktop_view_get_file_column      (ThunarDesktopView *view);
+void          thunar_desktop_view_set_file_column      (ThunarDesktopView *view,
+                                                        gint               file_column);
 
-GtkWidget  *thunar_desktop_view_new              (void);
-GtkWidget  *thunar_desktop_view_new_with_display (GdkDisplay        *display);
+gint          thunar_desktop_view_get_position_column  (ThunarDesktopView *view);
+void          thunar_desktop_view_set_position_column  (ThunarDesktopView *view,
+                                                        gint               position_column);
 
-GdkDisplay *thunar_desktop_view_get_display      (ThunarDesktopView *view);
-void        thunar_desktop_view_set_display      (ThunarDesktopView *view,
-                                                  GdkDisplay        *display);
+void          thunar_desktop_view_unselect_all         (ThunarDesktopView *view);
 
 G_END_DECLS;
 
diff --git a/thunar/thunar-desktop-window.c b/thunar/thunar-desktop-window.c
new file mode 100644
index 000000000..b7d7a1f9c
--- /dev/null
+++ b/thunar/thunar-desktop-window.c
@@ -0,0 +1,216 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <thunar/thunar-desktop-model.h>
+#include <thunar/thunar-desktop-window.h>
+#include <thunar/thunar-desktop-view.h>
+
+
+
+static void     thunar_desktop_window_class_init    (ThunarDesktopWindowClass *klass);
+static void     thunar_desktop_window_init          (ThunarDesktopWindow      *window);
+static void     thunar_desktop_window_size_request  (GtkWidget                *widget,
+                                                     GtkRequisition           *requisition);
+static void     thunar_desktop_window_realize       (GtkWidget                *widget);
+static void     thunar_desktop_window_unrealize     (GtkWidget                *widget);
+static gboolean thunar_desktop_window_forward_event (GtkWidget                *widget,
+                                                     GdkEvent                 *event);
+
+
+
+struct _ThunarDesktopWindowClass
+{
+  GtkWindowClass __parent__;
+};
+
+struct _ThunarDesktopWindow
+{
+  GtkWindow __parent__;
+
+  GtkWidget *view;
+};
+
+
+
+G_DEFINE_TYPE (ThunarDesktopWindow, thunar_desktop_window, GTK_TYPE_WINDOW);
+
+
+
+static void
+thunar_desktop_window_class_init (ThunarDesktopWindowClass *klass)
+{
+  GtkWidgetClass *gtkwidget_class;
+
+  gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  gtkwidget_class->size_request = thunar_desktop_window_size_request;
+  gtkwidget_class->realize = thunar_desktop_window_realize;
+  gtkwidget_class->unrealize = thunar_desktop_window_unrealize;
+  gtkwidget_class->button_press_event = (gpointer) thunar_desktop_window_forward_event;
+  gtkwidget_class->button_release_event = (gpointer) thunar_desktop_window_forward_event;
+}
+
+
+
+static void
+thunar_desktop_window_init (ThunarDesktopWindow *window)
+{
+  ThunarDesktopModel *model;
+
+  GTK_WIDGET_UNSET_FLAGS (window, GTK_DOUBLE_BUFFERED);
+
+  gtk_widget_add_events (GTK_WIDGET (window),
+                         GDK_BUTTON_PRESS_MASK
+                       | GDK_BUTTON_RELEASE_MASK);
+
+  gtk_window_move (GTK_WINDOW (window), 0, 0);
+  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DESKTOP);
+
+  /* setup the view */
+  window->view = thunar_desktop_view_new ();
+  thunar_desktop_view_set_file_column (THUNAR_DESKTOP_VIEW (window->view), THUNAR_DESKTOP_MODEL_COLUMN_FILE);
+  thunar_desktop_view_set_position_column (THUNAR_DESKTOP_VIEW (window->view), THUNAR_DESKTOP_MODEL_COLUMN_POSITION);
+  gtk_container_add (GTK_CONTAINER (window), window->view);
+  gtk_widget_show (window->view);
+
+  /* setup the model */
+  model = thunar_desktop_model_get_default ();
+  thunar_desktop_view_set_model (THUNAR_DESKTOP_VIEW (window->view), GTK_TREE_MODEL (model));
+  g_object_unref (G_OBJECT (model));
+}
+
+
+
+static void
+thunar_desktop_window_size_request (GtkWidget      *widget,
+                                    GtkRequisition *requisition)
+{
+  GdkScreen *screen = gtk_widget_get_screen (widget);
+
+  requisition->width = gdk_screen_get_width (screen);
+  requisition->height = gdk_screen_get_height (screen);
+}
+
+
+
+static void
+thunar_desktop_window_realize (GtkWidget *widget)
+{
+  GdkScreen *screen;
+  GdkWindow *root;
+  GdkAtom    atom;
+  Window     xid;
+
+  GTK_WIDGET_CLASS (thunar_desktop_window_parent_class)->realize (widget);
+
+  xid = GDK_DRAWABLE_XID (widget->window);
+  screen = gtk_widget_get_screen (widget);
+  root = gdk_screen_get_root_window (screen);
+
+  /* configure this window to be a "desktop" window */
+  atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DESKTOP", FALSE);
+  gdk_property_change (widget->window,
+                       gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE),
+                       gdk_atom_intern ("ATOM", FALSE), 32,
+                       GDK_PROP_MODE_REPLACE, (gpointer) &atom, 1);
+
+  /* tell the root window that we have a new "desktop" window */
+  gdk_property_change (root,
+                       gdk_atom_intern ("NAUTILUS_DESKTOP_WINDOW_ID", FALSE),
+                       gdk_atom_intern ("WINDOW", FALSE), 32,
+                       GDK_PROP_MODE_REPLACE, (gpointer) &xid, 1);
+  gdk_property_change (root,
+                       gdk_atom_intern ("XFCE_DESKTOP_WINDOW", FALSE),
+                       gdk_atom_intern ("WINDOW", FALSE), 32,
+                       GDK_PROP_MODE_REPLACE, (gpointer) &xid, 1);
+
+  /* XRandR support */
+  g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (gtk_widget_queue_resize), widget);
+}
+
+
+
+static void
+thunar_desktop_window_unrealize (GtkWidget *widget)
+{
+  GdkScreen *screen;
+  GdkWindow *root;
+
+  screen = gtk_widget_get_screen (widget);
+  root = gdk_screen_get_root_window (screen);
+
+  /* disconnect the XRandR support handler */
+  g_signal_handlers_disconnect_by_func (G_OBJECT (screen), gtk_widget_queue_resize, widget);
+
+  /* unset root window properties */
+  gdk_property_delete (root, gdk_atom_intern ("NAUTILUS_DESKTOP_WINDOW_ID", FALSE));
+  gdk_property_delete (root, gdk_atom_intern ("XFCE_DESKTOP_WINDOW", FALSE));
+
+  GTK_WIDGET_CLASS (thunar_desktop_window_parent_class)->unrealize (widget);
+}
+
+
+
+static gboolean
+thunar_desktop_window_forward_event (GtkWidget *widget,
+                                     GdkEvent  *event)
+{
+  if (G_LIKELY (GTK_BIN (widget)->child != NULL))
+    return gtk_widget_event (GTK_BIN (widget)->child, event);
+  return FALSE;
+}
+
+
+
+/**
+ * thunar_desktop_window_new:
+ *
+ * Allocates a new #ThunarDesktopWindow instance.
+ *
+ * Return value: the newly allocated #ThunarDesktopWindow.
+ **/
+GtkWidget*
+thunar_desktop_window_new (void)
+{
+  return thunar_desktop_window_new_with_screen (gdk_screen_get_default ());
+}
+
+
+
+/**
+ * thunar_desktop_window_new_with_screen:
+ * @screen : a #GdkScreen.
+ *
+ * Allocates a new #ThunarDesktopWindow instance and
+ * associates it with the given @screen.
+ *
+ * Return value: the newly allocated #ThunarDesktopWindow.
+ **/
+GtkWidget*
+thunar_desktop_window_new_with_screen (GdkScreen *screen)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+  return g_object_new (THUNAR_TYPE_DESKTOP_WINDOW,
+                       "screen", screen,
+                       NULL);
+}
+
diff --git a/thunar/thunar-desktop-window.h b/thunar/thunar-desktop-window.h
new file mode 100644
index 000000000..9e5cd7bf8
--- /dev/null
+++ b/thunar/thunar-desktop-window.h
@@ -0,0 +1,44 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __THUNAR_DESKTOP_WINDOW_H__
+#define __THUNAR_DESKTOP_WINDOW_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS;
+
+typedef struct _ThunarDesktopWindowClass ThunarDesktopWindowClass;
+typedef struct _ThunarDesktopWindow      ThunarDesktopWindow;
+
+#define THUNAR_TYPE_DESKTOP_WINDOW            (thunar_desktop_window_get_type ())
+#define THUNAR_DESKTOP_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_DESKTOP_WINDOW, ThunarDesktopWindow))
+#define THUNAR_DESKTOP_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_DESKTOP_WINDOW, ThunarDesktopWindowClass))
+#define THUNAR_IS_DESKTOP_WINDOW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_DESKTOP_WINDOW))
+#define THUNAR_IS_DESKTOP_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_DESKTOP_WINDOW))
+#define THUNAR_DESKTOP_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_DESKTOP_WINDOW, ThunarDesktopWindowClass))
+
+GType      thunar_desktop_window_get_type         (void) G_GNUC_CONST;
+
+GtkWidget *thunar_desktop_window_new              (void);
+GtkWidget *thunar_desktop_window_new_with_screen  (GdkScreen  *screen);
+
+G_END_DECLS;
+
+#endif /* !__THUNAR_DESKTOP_WINDOW_H__ */
diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index d8a9143e4..938b6f57c 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -1168,17 +1168,22 @@ thunar_file_load_icon (ThunarFile *file,
   g_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
 
   /* see if we have a cached icon that matches the request */
-  if (file->cached_icon != NULL && file->cached_size == size)
+  if (file->cached_icon == NULL || file->cached_size != size)
     {
-      /* take a reference on the cached icon for the caller */
-      g_object_ref (G_OBJECT (file->cached_icon));
-      return file->cached_icon;
+      /* drop any previous icon */
+      if (file->cached_icon != NULL)
+        g_object_unref (G_OBJECT (file->cached_icon));
+
+      /* load the icon */
+      icon_factory = thunar_icon_factory_get_default ();
+      icon_theme = thunar_icon_factory_get_icon_theme (icon_factory);
+      icon_name = THUNAR_FILE_GET_CLASS (file)->get_icon_name (file, icon_theme);
+      file->cached_icon = thunar_icon_factory_load_icon (icon_factory, icon_name, size, NULL, TRUE);
     }
 
-  icon_factory = thunar_icon_factory_get_default ();
-  icon_theme = thunar_icon_factory_get_icon_theme (icon_factory);
-  icon_name = THUNAR_FILE_GET_CLASS (file)->get_icon_name (file, icon_theme);
-  return thunar_icon_factory_load_icon (icon_factory, icon_name, size, NULL, TRUE);
+  /* take a reference on the cached icon for the caller */
+  g_object_ref (G_OBJECT (file->cached_icon));
+  return file->cached_icon;
 }
 
 
diff --git a/thunarx/Makefile.am b/thunarx/Makefile.am
new file mode 100644
index 000000000..4f639bd25
--- /dev/null
+++ b/thunarx/Makefile.am
@@ -0,0 +1,25 @@
+# $Id$
+
+INCLUDES =								\
+	-I$(top_srcdir)							\
+	-DEXO_API_SUBJECT_TO_CHANGE					\
+	-DEXO_DISABLE_DEPRECATED					\
+	-DG_LOG_DOMAIN=\"thunarx\"
+
+noinst_LTLIBRARIES =							\
+	libthunarx.la
+
+libthunarx_la_SOURCES =							\
+	thunarx-gdk-pixbuf-extensions.c					\
+	thunarx-gdk-pixbuf-extensions.h
+
+libthunarx_la_CFLAGS =							\
+	$(EXO_CFLAGS)
+
+libthunarx_la_LDFLAGS =							\
+	-no-undefined
+
+libthunarx_la_LIBADD =							\
+	$(EXO_LIBS)
+
+# vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
diff --git a/thunarx/thunarx-gdk-pixbuf-extensions.c b/thunarx/thunarx-gdk-pixbuf-extensions.c
new file mode 100644
index 000000000..f5d51bfd9
--- /dev/null
+++ b/thunarx/thunarx-gdk-pixbuf-extensions.c
@@ -0,0 +1,90 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <thunarx/thunarx-gdk-pixbuf-extensions.h>
+
+
+
+/**
+ * thunarx_gdk_pixbuf_colorize:
+ * @src   : the source #GdkPixbuf.
+ * @color : the new color.
+ *
+ * Creates a new #GdkPixbuf based on @src, which is
+ * colorized to @color.
+ *
+ * Return value: the colorized #GdkPixbuf.
+ **/
+GdkPixbuf*
+thunarx_gdk_pixbuf_colorize (GdkPixbuf      *src,
+                             const GdkColor *color)
+{
+  gint i, j;
+  gint width, height, has_alpha, src_row_stride, dst_row_stride;
+  gint red_value, green_value, blue_value;
+  guchar *target_pixels;
+  guchar *original_pixels;
+  guchar *pixsrc;
+  guchar *pixdest;
+  GdkPixbuf *dest;
+
+  red_value = color->red / 255.0;
+  green_value = color->green / 255.0;
+  blue_value = color->blue / 255.0;
+
+  dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
+                         gdk_pixbuf_get_has_alpha (src),
+                         gdk_pixbuf_get_bits_per_sample (src),
+                         gdk_pixbuf_get_width (src),
+                         gdk_pixbuf_get_height (src));
+  
+  has_alpha = gdk_pixbuf_get_has_alpha (src);
+  width = gdk_pixbuf_get_width (src);
+  height = gdk_pixbuf_get_height (src);
+  src_row_stride = gdk_pixbuf_get_rowstride (src);
+  dst_row_stride = gdk_pixbuf_get_rowstride (dest);
+  target_pixels = gdk_pixbuf_get_pixels (dest);
+  original_pixels = gdk_pixbuf_get_pixels (src);
+
+  for (i = 0; i < height; i++)
+    {
+      pixdest = target_pixels + i*dst_row_stride;
+      pixsrc = original_pixels + i*src_row_stride;
+      
+      for (j = 0; j < width; j++)
+        {
+          *pixdest++ = (*pixsrc++ * red_value) >> 8;
+          *pixdest++ = (*pixsrc++ * green_value) >> 8;
+          *pixdest++ = (*pixsrc++ * blue_value) >> 8;
+          
+          if (has_alpha)
+            *pixdest++ = *pixsrc++;
+        }
+    }
+
+  return dest;
+}
+
+
+
+
diff --git a/thunarx/thunarx-gdk-pixbuf-extensions.h b/thunarx/thunarx-gdk-pixbuf-extensions.h
new file mode 100644
index 000000000..6f685cdaa
--- /dev/null
+++ b/thunarx/thunarx-gdk-pixbuf-extensions.h
@@ -0,0 +1,32 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __THUNARX_GDK_PIXBUF_EXTENSIONS_H__
+#define __THUNARX_GDK_PIXBUF_EXTENSIONS_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS;
+
+GdkPixbuf *thunarx_gdk_pixbuf_colorize (GdkPixbuf      *src,
+                                        const GdkColor *color);
+
+G_END_DECLS;
+
+#endif /* !__THUNARX_GDK_PIXBUF_EXTENSIONS_H__ */
-- 
GitLab