[Xfce4-commits] <thunar:jannis/new-shortcuts-pane> Squashme: Initial work on getting rid of ThunarShortcutsModel.

Jannis Pohlmann noreply at xfce.org
Fri Nov 4 02:14:01 CET 2011


Updating branch refs/heads/jannis/new-shortcuts-pane
         to 98bd465376724a640b378b71715b5dc39ef4bac7 (commit)
       from 618f042ccc1f1bf769733e51bee9e5673269c320 (commit)

commit 98bd465376724a640b378b71715b5dc39ef4bac7
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Fri Nov 4 02:08:42 2011 +0100

    Squashme: Initial work on getting rid of ThunarShortcutsModel.
    
    This commit is the first in a series of changes that merge
    ThunarShortcut and ThunarShortcutRow into a single widget. A new widget
    ThunarShortcutGroup is added to represent the devices, places and
    network shortcut categories and manage the individual ThunarShortcut
    widgets added for each shortcut. All in all, this will help in getting
    rid of code duplication, synchronization of asynchronously resolved file
    information etc.

 thunar/Makefile.am              |    2 +
 thunar/thunar-enum-types.c      |   11 +-
 thunar/thunar-enum-types.h      |   16 +-
 thunar/thunar-shortcut-row.c    |    4 +-
 thunar/thunar-shortcut.c        |  693 ++++++++++++++++++++++++++++++---------
 thunar/thunar-shortcut.h        |    3 +
 thunar/thunar-shortcuts-model.c |    8 +-
 thunar/thunar-shortcuts-view.c  |  633 +++++++++++++++++++++++++++++++++---
 8 files changed, 1150 insertions(+), 220 deletions(-)

diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 383c439..a91aaca 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -173,6 +173,8 @@ Thunar_SOURCES =							\
 	thunar-session-client.h						\
 	thunar-shortcut.c						\
 	thunar-shortcut.h						\
+	thunar-shortcut-group.c						\
+	thunar-shortcut-group.h						\
 	thunar-shortcut-row.c						\
 	thunar-shortcut-row.h						\
 	thunar-shortcuts-icon-renderer.c				\
diff --git a/thunar/thunar-enum-types.c b/thunar/thunar-enum-types.c
index 573c364..6893656 100644
--- a/thunar/thunar-enum-types.c
+++ b/thunar/thunar-enum-types.c
@@ -340,17 +340,20 @@ thunar_shortcut_type_get_type (void)
 
   if (G_UNLIKELY (type == G_TYPE_INVALID))
     {
-      static const GEnumValue values[] =
+      static const GFlagsValue values[] =
       {
         { THUNAR_SHORTCUT_REGULAR_FILE,     "THUNAR_SHORTCUT_REGULAR_FILE",     "regular-file",     },
+        { THUNAR_SHORTCUT_TRASH_FILE,       "THUNAR_SHORTCUT_NETWORK_FILE",     "network-file",     },
         { THUNAR_SHORTCUT_NETWORK_FILE,     "THUNAR_SHORTCUT_NETWORK_FILE",     "network-file",     },
-        { THUNAR_SHORTCUT_STANDALONE_MOUNT, "THUNAR_SHORTCUT_STANDALONE_MOUNT", "standalone-mount", },
-        { THUNAR_SHORTCUT_EJECTABLE_VOLUME, "THUNAR_SHORTCUT_EJECTABLE_VOLUME", "ejectable-volume", },
         { THUNAR_SHORTCUT_REGULAR_VOLUME,   "THUNAR_SHORTCUT_REGULAR_VOLUME",   "regular-volume",   },
+        { THUNAR_SHORTCUT_EJECTABLE_VOLUME, "THUNAR_SHORTCUT_EJECTABLE_VOLUME", "ejectable-volume", },
+        { THUNAR_SHORTCUT_REGULAR_MOUNT,    "THUNAR_SHORTCUT_REGULAR_MOUNT",    "regular-mount",    },
+        { THUNAR_SHORTCUT_ARCHIVE_MOUNT,    "THUNAR_SHORTCUT_ARCHIVE_MOUNT",    "archive-mount",    },
+        { THUNAR_SHORTCUT_NETWORK_MOUNT,    "THUNAR_SHORTCUT_NETWORK_MOUNT",    "network-mount",    },
         { 0,                                NULL,                               NULL,               },
       };
 
-      type = g_enum_register_static (I_("ThunarShortcutType"), values);
+      type = g_flags_register_static (I_("ThunarShortcutType"), values);
     }
 
   return type;
diff --git a/thunar/thunar-enum-types.h b/thunar/thunar-enum-types.h
index 75c61c2..609de31 100644
--- a/thunar/thunar-enum-types.h
+++ b/thunar/thunar-enum-types.h
@@ -297,16 +297,18 @@ GType thunar_file_mode_get_type (void) G_GNUC_CONST;
 /**
  * ThunarShortcutType:
  *
- * Enumeration used for classifying the different shortcuts
- * in #ThunarShortcutsModel.
+ * Flags used for classifying the different shortcuts.
  **/
 typedef enum
 {
-  THUNAR_SHORTCUT_REGULAR_FILE,
-  THUNAR_SHORTCUT_NETWORK_FILE,
-  THUNAR_SHORTCUT_STANDALONE_MOUNT,
-  THUNAR_SHORTCUT_EJECTABLE_VOLUME,
-  THUNAR_SHORTCUT_REGULAR_VOLUME,
+  THUNAR_SHORTCUT_REGULAR_FILE     = 1 << 0,
+  THUNAR_SHORTCUT_TRASH_FILE       = 1 << 1,
+  THUNAR_SHORTCUT_NETWORK_FILE     = 1 << 2,
+  THUNAR_SHORTCUT_REGULAR_VOLUME   = 1 << 3,
+  THUNAR_SHORTCUT_EJECTABLE_VOLUME = 1 << 4,
+  THUNAR_SHORTCUT_REGULAR_MOUNT    = 1 << 5,
+  THUNAR_SHORTCUT_ARCHIVE_MOUNT    = 1 << 6,
+  THUNAR_SHORTCUT_NETWORK_MOUNT    = 1 << 7,
 } ThunarShortcutType;
 
 GType thunar_shortcut_type_get_type (void) G_GNUC_CONST;
diff --git a/thunar/thunar-shortcut-row.c b/thunar/thunar-shortcut-row.c
index 2c5fad6..e2ed46c 100644
--- a/thunar/thunar-shortcut-row.c
+++ b/thunar/thunar-shortcut-row.c
@@ -1278,7 +1278,7 @@ thunar_shortcut_row_mount_changed (ThunarShortcutRow *row)
 
   /* don't update the row based on the mount unless we have
    * a standalone mount that is not associated with a volume */
-  if (row->shortcut_type != THUNAR_SHORTCUT_STANDALONE_MOUNT)
+  if (row->shortcut_type != THUNAR_SHORTCUT_REGULAR_MOUNT)
     return;
 
   if (row->mount != NULL)
@@ -1314,7 +1314,7 @@ thunar_shortcut_row_shortcut_type_changed (ThunarShortcutRow *row)
       thunar_shortcut_row_location_changed (row);
       break;
 
-    case THUNAR_SHORTCUT_STANDALONE_MOUNT:
+    case THUNAR_SHORTCUT_REGULAR_MOUNT:
       thunar_shortcut_row_mount_changed (row);
       break;
 
diff --git a/thunar/thunar-shortcut.c b/thunar/thunar-shortcut.c
index 070455e..5ad9dbf 100644
--- a/thunar/thunar-shortcut.c
+++ b/thunar/thunar-shortcut.c
@@ -27,14 +27,22 @@
 
 #include <gio/gio.h>
 
+#include <gtk/gtk.h>
+
 #include <thunar/thunar-browser.h>
 #include <thunar/thunar-enum-types.h>
 #include <thunar/thunar-file.h>
+#include <thunar/thunar-marshal.h>
+#include <thunar/thunar-preferences.h>
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-shortcut.h>
 
 
 
+#define THUNAR_SHORTCUT_MIN_HEIGHT 20
+
+
+
 /* property identifiers */
 enum
 {
@@ -49,6 +57,7 @@ enum
   PROP_NAME,
   PROP_CUSTOM_NAME,
   PROP_SHORTCUT_TYPE,
+  PROP_ICON_SIZE,
   PROP_HIDDEN,
   PROP_MUTABLE,
   PROP_PERSISTENT,
@@ -57,73 +66,106 @@ enum
 /* signal identifiers */
 enum
 {
+  SIGNAL_ACTIVATED,
+  SIGNAL_CONTEXT_MENU,
   LAST_SIGNAL,
 };
 
-
-
-static void thunar_shortcut_constructed          (GObject        *object);
-static void thunar_shortcut_finalize             (GObject        *object);
-static void thunar_shortcut_get_property         (GObject        *object,
-                                                  guint           prop_id,
-                                                  GValue         *value,
-                                                  GParamSpec     *pspec);
-static void thunar_shortcut_set_property         (GObject        *object,
-                                                  guint           prop_id,
-                                                  const GValue   *value,
-                                                  GParamSpec     *pspec);
-static void thunar_shortcut_poke_location_finish (ThunarBrowser  *browser,
-                                                  GFile          *location,
-                                                  ThunarFile     *file,
-                                                  ThunarFile     *target_file,
-                                                  GError         *error,
-                                                  gpointer        user_data);
-static void thunar_shortcut_load_file            (ThunarShortcut *shortcut);
+/* row states */
+typedef enum
+{
+  THUNAR_SHORTCUT_NORMAL,
+  THUNAR_SHORTCUT_RESOLVING,
+  THUNAR_SHORTCUT_EJECTING,
+} ThunarShortcutState;
+
+
+
+static void     thunar_shortcut_constructed             (GObject           *object);
+static void     thunar_shortcut_finalize                (GObject           *object);
+static void     thunar_shortcut_get_property            (GObject           *object,
+                                                         guint              prop_id,
+                                                         GValue            *value,
+                                                         GParamSpec        *pspec);
+static void     thunar_shortcut_set_property            (GObject           *object,
+                                                         guint              prop_id,
+                                                         const GValue      *value,
+                                                         GParamSpec        *pspec);
+static void     thunar_shortcut_size_request            (GtkWidget         *widget,
+                                                         GtkRequisition    *requisition);
+static gboolean thunar_shortcut_matches_types           (ThunarShortcut    *shortcut,
+                                                         ThunarShortcutType types);
+static void     thunar_shortcut_location_changed        (ThunarShortcut    *shortcut);
+static void     thunar_shortcut_file_changed            (ThunarShortcut    *shortcut);
+static void     thunar_shortcut_icon_changed            (ThunarShortcut    *shortcut);
+static void     thunar_shortcut_resolve_location_finish (ThunarBrowser     *browser,
+                                                         GFile             *location,
+                                                         ThunarFile        *file,
+                                                         ThunarFile        *target_file,
+                                                         GError            *error,
+                                                         gpointer           user_data);
 
 
 
 struct _ThunarShortcutClass
 {
-  GObjectClass __parent__;
+  GtkEventBoxClass __parent__;
 };
 
 struct _ThunarShortcut
 {
-  GObject __parent__;
-
-  GFile             *location;
+  GtkEventBox         __parent__;
 
-  ThunarFile        *file;
-  GVolume           *volume;
-  GMount            *mount;
+  GFile              *location;
+  GVolume            *volume;
+  GMount             *mount;
   
-  GIcon             *icon;
-  GIcon             *custom_icon;
-  GIcon             *eject_icon;
+  ThunarFile         *file;
+
+  GIcon              *icon;
+  GIcon              *custom_icon;
+  GIcon              *eject_icon;
   
-  gchar             *name;
-  gchar             *custom_name;
+  gchar              *name;
+  gchar              *custom_name;
   
-  ThunarShortcutType type;
+  ThunarShortcutType  type;
+
+  guint               hidden : 1;
+  guint               mutable : 1;
+  guint               persistent : 1;
+  guint               constructed : 1;
+
+  GtkWidget          *label_widget;
+  GtkWidget          *icon_image;
+  GtkWidget          *action_button;
+  GtkWidget          *action_image;
+  GtkWidget          *spinner;
+
+  ThunarPreferences  *preferences;
+  ThunarIconSize      icon_size;
 
-  guint              hidden : 1;
-  guint              mutable : 1;
-  guint              persistent : 1;
+  GCancellable       *cancellable;
 
-  guint              constructed : 1;
+  ThunarShortcutState state;
 };
 
 
 
-G_DEFINE_TYPE_WITH_CODE (ThunarShortcut, thunar_shortcut, G_TYPE_OBJECT,
+G_DEFINE_TYPE_WITH_CODE (ThunarShortcut, thunar_shortcut, GTK_TYPE_EVENT_BOX,
                          G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL))
 
 
 
+static guint shortcut_signals[LAST_SIGNAL];
+
+
+
 static void
 thunar_shortcut_class_init (ThunarShortcutClass *klass)
 {
-  GObjectClass *gobject_class;
+  GtkWidgetClass *gtkwidget_class;
+  GObjectClass   *gobject_class;
 
   /* Determine the parent type class */
   thunar_shortcut_parent_class = g_type_class_peek_parent (klass);
@@ -134,6 +176,19 @@ thunar_shortcut_class_init (ThunarShortcutClass *klass)
   gobject_class->get_property = thunar_shortcut_get_property;
   gobject_class->set_property = thunar_shortcut_set_property;
 
+  gtkwidget_class = GTK_WIDGET_CLASS (klass);
+#if 0
+  gtkwidget_class->button_press_event = thunar_shortcut_button_press_event;
+  gtkwidget_class->button_release_event = thunar_shortcut_button_release_event;
+  gtkwidget_class->key_press_event = thunar_shortcut_key_press_event;
+  gtkwidget_class->enter_notify_event = thunar_shortcut_enter_notify_event;
+  gtkwidget_class->leave_notify_event = thunar_shortcut_leave_notify_event;
+  gtkwidget_class->expose_event = thunar_shortcut_expose_event;
+  gtkwidget_class->focus = thunar_shortcut_focus;
+  gtkwidget_class->focus_in_event = thunar_shortcut_focus_in_event;
+#endif
+  gtkwidget_class->size_request = thunar_shortcut_size_request;
+
   g_object_class_install_property (gobject_class,
                                    PROP_LOCATION,
                                    g_param_spec_object ("location",
@@ -215,13 +270,22 @@ thunar_shortcut_class_init (ThunarShortcutClass *klass)
 
   g_object_class_install_property (gobject_class,
                                    PROP_SHORTCUT_TYPE,
-                                   g_param_spec_enum ("shortcut-type",
-                                                      "shortcut-type",
-                                                      "shortcut-type",
-                                                      THUNAR_TYPE_SHORTCUT_TYPE,
-                                                      THUNAR_SHORTCUT_REGULAR_FILE,
-                                                      EXO_PARAM_READWRITE |
-                                                      G_PARAM_CONSTRUCT));
+                                   g_param_spec_flags ("shortcut-type",
+                                                       "shortcut-type",
+                                                       "shortcut-type",
+                                                       THUNAR_TYPE_SHORTCUT_TYPE,
+                                                       THUNAR_SHORTCUT_REGULAR_FILE,
+                                                       EXO_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_ICON_SIZE,
+                                   g_param_spec_enum ("icon-size",
+                                                      "icon-size",
+                                                      "icon-size",
+                                                      THUNAR_TYPE_ICON_SIZE,
+                                                      THUNAR_ICON_SIZE_SMALLER,
+                                                      EXO_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class,
                                    PROP_HIDDEN,
@@ -249,6 +313,24 @@ thunar_shortcut_class_init (ThunarShortcutClass *klass)
                                                          FALSE,
                                                          EXO_PARAM_READWRITE |
                                                          G_PARAM_CONSTRUCT));
+
+  shortcut_signals[SIGNAL_ACTIVATED] = 
+    g_signal_new (I_("activated"),
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  _thunar_marshal_VOID__OBJECT_BOOLEAN,
+                  G_TYPE_NONE, 2, 
+                  THUNAR_TYPE_FILE,
+                  G_TYPE_BOOLEAN);
+
+  shortcut_signals[SIGNAL_CONTEXT_MENU] =
+    g_signal_new (I_("context-menu"),
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
 }
 
 
@@ -256,6 +338,85 @@ thunar_shortcut_class_init (ThunarShortcutClass *klass)
 static void
 thunar_shortcut_init (ThunarShortcut *shortcut)
 {
+  GtkWidget *alignment;
+  GtkWidget *box;
+
+  /* create a cancellable for aborting mount/unmount operations */
+  shortcut->cancellable = g_cancellable_new ();
+
+  /* set the shortcut state to normal */
+  shortcut->state = THUNAR_SHORTCUT_NORMAL;
+
+  /* configure general widget behavior */
+  gtk_widget_set_can_focus (GTK_WIDGET (shortcut), TRUE);
+  gtk_widget_set_sensitive (GTK_WIDGET (shortcut), TRUE);
+
+  /* create the alignment for left and right padding */
+  alignment = gtk_alignment_new (0.0f, 0.0f, 1.0f, 1.0f);
+  /* TODO use expander arrow width instead of 16 here */
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 16, 4);
+  gtk_container_add (GTK_CONTAINER (shortcut), alignment);
+  gtk_widget_show (alignment);
+
+  /* create a box for the different sub-widgets */
+  box = gtk_hbox_new (FALSE, 4);
+  gtk_container_add (GTK_CONTAINER (alignment), box);
+  gtk_widget_show (box);
+
+  /* create the icon widget */
+  shortcut->icon_image = gtk_image_new ();
+  gtk_box_pack_start (GTK_BOX (box), shortcut->icon_image, FALSE, TRUE, 0);
+  gtk_widget_hide (shortcut->icon_image);
+
+  /* create the label widget */
+  shortcut->label_widget = gtk_label_new (NULL);
+  gtk_label_set_ellipsize (GTK_LABEL (shortcut->label_widget), PANGO_ELLIPSIZE_END);
+  gtk_misc_set_alignment (GTK_MISC (shortcut->label_widget), 0.0f, 0.5f);
+  gtk_container_add (GTK_CONTAINER (box), shortcut->label_widget);
+  gtk_widget_hide (shortcut->label_widget);
+
+  /* create the action button */
+  shortcut->action_button = gtk_button_new ();
+  gtk_button_set_relief (GTK_BUTTON (shortcut->action_button), GTK_RELIEF_NONE);
+  gtk_box_pack_start (GTK_BOX (box), shortcut->action_button, FALSE, TRUE, 0);
+  gtk_widget_hide (shortcut->action_button);
+
+#if 0
+  /* adjust the state transitions of the button */
+  g_signal_connect_swapped (shortcut->action_button, "state-changed",
+                            G_CALLBACK (thunar_shortcut_button_state_changed), shortcut);
+
+  /* react on button click events */
+  g_signal_connect_swapped (shortcut->action_button, "clicked",
+                            G_CALLBACK (thunar_shortcut_button_clicked), shortcut);
+#endif
+
+  /* create the action button image */
+  shortcut->action_image = gtk_image_new ();
+  gtk_button_set_image (GTK_BUTTON (shortcut->action_button), shortcut->action_image);
+  gtk_widget_show (shortcut->action_image);
+
+  /* take a reference because we need to be able to remove it from the
+   * button temporarily */
+  g_object_ref (shortcut->action_image);
+
+  /* default to "media-eject", we only set this for the button size
+  * to be computed so that all shortcuts have equal heights */
+  gtk_image_set_from_icon_name (GTK_IMAGE (shortcut->action_image), "media-eject",
+                                GTK_ICON_SIZE_MENU);
+
+  /* create the spinner icon */
+  shortcut->spinner = gtk_spinner_new ();
+  gtk_spinner_stop (GTK_SPINNER (shortcut->spinner));
+
+  /* take a reference because we need to be able to remove it from the
+   * button temporarily */
+  g_object_ref (shortcut->spinner);
+
+  /* update the icon size whenever necessary */
+  shortcut->preferences = thunar_preferences_get ();
+  exo_binding_new (G_OBJECT (shortcut->preferences), "shortcuts-icon-size",
+                   G_OBJECT (shortcut), "icon-size");
 }
 
 
@@ -276,6 +437,17 @@ thunar_shortcut_finalize (GObject *object)
 {
   ThunarShortcut *shortcut = THUNAR_SHORTCUT (object);
 
+  /* release the spinner and action image */
+  g_object_unref (shortcut->spinner);
+  g_object_unref (shortcut->action_image);
+
+  /* release the cancellable */
+  g_cancellable_cancel (shortcut->cancellable);
+  g_object_unref (shortcut->cancellable);
+
+  /* release the preferences */
+  g_object_unref (shortcut->preferences);
+
   if (shortcut->location != NULL)
     g_object_unref (shortcut->location);
 
@@ -352,7 +524,11 @@ thunar_shortcut_get_property (GObject    *object,
       break;
 
     case PROP_SHORTCUT_TYPE:
-      g_value_set_enum (value, thunar_shortcut_get_shortcut_type (shortcut));
+      g_value_set_flags (value, thunar_shortcut_get_shortcut_type (shortcut));
+      break;
+
+    case PROP_ICON_SIZE:
+      g_value_set_enum (value, thunar_shortcut_get_icon_size (shortcut));
       break;
 
     case PROP_HIDDEN:
@@ -422,7 +598,11 @@ thunar_shortcut_set_property (GObject      *object,
       break;
 
     case PROP_SHORTCUT_TYPE:
-      thunar_shortcut_set_shortcut_type (shortcut, g_value_get_enum (value));
+      thunar_shortcut_set_shortcut_type (shortcut, g_value_get_flags (value));
+      break;
+
+    case PROP_ICON_SIZE:
+      thunar_shortcut_set_icon_size (shortcut, g_value_get_enum (value));
       break;
 
     case PROP_HIDDEN:
@@ -446,51 +626,289 @@ thunar_shortcut_set_property (GObject      *object,
 
 
 static void
-thunar_shortcut_poke_location_finish (ThunarBrowser *browser,
-                                      GFile         *location,
-                                      ThunarFile    *file,
-                                      ThunarFile    *target_file,
-                                      GError        *error,
-                                      gpointer       user_data)
+thunar_shortcut_size_request (GtkWidget      *widget,
+                              GtkRequisition *requisition)
 {
-  ThunarShortcut *shortcut = THUNAR_SHORTCUT (browser);
+  ThunarShortcut *shortcut = THUNAR_SHORTCUT (widget);
+  GtkRequisition  button_requisition;
 
-  _thunar_return_if_fail (G_IS_FILE (location));
-  _thunar_return_if_fail (file == NULL || THUNAR_IS_FILE (file));
-  _thunar_return_if_fail (target_file == NULL || THUNAR_IS_FILE (target_file));
   _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  /* let the event box class compute the size we need for its children */
+  (*GTK_WIDGET_CLASS (thunar_shortcut_parent_class)->size_request) (widget, requisition);
+
+  /* compute the button size */
+  gtk_widget_size_request (shortcut->action_button, &button_requisition);
+
+  /* use the maximum of the computed requisition height, the button height,
+   * the icon size + 4, and the minimum allowed height for rows */
+  requisition->height = MAX (requisition->height, button_requisition.height);
+  requisition->height = MAX (requisition->height, (gint) shortcut->icon_size + 4);
+  requisition->height = MAX (requisition->height, THUNAR_SHORTCUT_MIN_HEIGHT);
+}
+
+
+
+static gboolean
+thunar_shortcut_matches_types (ThunarShortcut    *shortcut,
+                               ThunarShortcutType types)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_SHORTCUT (shortcut), FALSE);
+  return (shortcut->type & types) != 0;
+}
+
+
+
+static void
+thunar_shortcut_location_changed (ThunarShortcut *shortcut)
+{
+  GIcon *icon;
+  gchar *uri;
+  gchar *base_name;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  /* only update the shortcut if this is a file shortcut */
+  if (!thunar_shortcut_matches_types (shortcut, 
+                                      THUNAR_SHORTCUT_REGULAR_FILE
+                                      | THUNAR_SHORTCUT_NETWORK_FILE))
+    {
+      return;
+    }
   
-  if (error != NULL)
+  /* check whether we have a location */
+  if (shortcut->location != NULL)
     {
-      g_debug ("file load error: %s", error->message);
+      /* use the location base name as the default name */
+      uri = g_file_get_uri (shortcut->location);
+      base_name = g_filename_display_basename (uri);
+      thunar_shortcut_set_name (shortcut, base_name);
+      g_free (base_name);
+      g_free (uri);
+
+      /* use the folder icon as the default icon */
+      if (shortcut->icon == NULL)
+        {
+          icon = g_themed_icon_new ("folder");
+          thunar_shortcut_set_icon (shortcut, icon);
+          g_object_unref (icon);
+        }
+
+      /* load additional file information asynchronously */
+      thunar_browser_poke_location (THUNAR_BROWSER (shortcut),
+                                    shortcut->location,
+                                    shortcut,
+                                    thunar_shortcut_resolve_location_finish,
+                                    NULL);
     }
   else
     {
-      /* set the file and update the shortcut */
-      thunar_shortcut_set_file (shortcut, target_file);
+      /* if this is reached, there is something wrong with the
+       * shortcut classification */
+      _thunar_assert_not_reached ();
     }
-
-  /* release the shortcut */
-  g_object_unref (shortcut);
 }
 
 
 
 static void
-thunar_shortcut_load_file (ThunarShortcut *shortcut)
+thunar_shortcut_file_changed (ThunarShortcut *shortcut)
 {
+  const gchar *display_name;
+  GIcon       *icon;
+
   _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
-  
+
+  /* only update the information if this is a file shortcut */
+  if (!thunar_shortcut_matches_types (shortcut, 
+                                      THUNAR_SHORTCUT_REGULAR_FILE
+                                      | THUNAR_SHORTCUT_NETWORK_FILE))
+    {
+      return;
+    }
+
+  /* update only if we have a file */
   if (shortcut->file != NULL)
-    return;
+    {
+      /* update the name of the shortcut */
+      display_name = thunar_file_get_display_name (shortcut->file);
+      thunar_shortcut_set_name (shortcut, display_name);
+
+      /* update the icon of the shortcut */
+      icon = thunar_file_get_icon (shortcut->file);
+      thunar_shortcut_set_icon (shortcut, icon);
+    }
+}
+
+
+
+static void
+thunar_shortcut_name_changed (ThunarShortcut *shortcut)
+{
+  const gchar *name;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  /* get the name (custom name overrides the regular name) */
+  name = thunar_shortcut_get_custom_name (shortcut);
+  if (name == NULL)
+    name = thunar_shortcut_get_name (shortcut);
+
+  /* update the label widget */
+  gtk_label_set_text (GTK_LABEL (shortcut->label_widget), name);
+  gtk_widget_set_visible (shortcut->label_widget, name != NULL && *name != '\0');
+}
+
+
+
+static void
+thunar_shortcut_volume_changed (ThunarShortcut *shortcut)
+{
+  GIcon *icon;
+  gchar *name;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  /* don't update if this is not a volume */
+  if (!thunar_shortcut_matches_types (shortcut,
+                                      THUNAR_SHORTCUT_REGULAR_VOLUME
+                                      | THUNAR_SHORTCUT_EJECTABLE_VOLUME))
+    {
+      return;
+    }
+
+  /* only update if we have a volume */
+  if (shortcut->volume != NULL)
+    {
+      /* update the name of the shortcut */
+      name = g_volume_get_name (shortcut->volume);
+      thunar_shortcut_set_name (shortcut, name);
+      g_free (name);
+
+      /* update the icon of the shortcut */
+      icon = g_volume_get_icon (shortcut->volume);
+      thunar_shortcut_set_icon (shortcut, icon);
+      g_object_unref (icon);
+    }
+  else
+    {
+      /* if this is reached, there is something wrong the 
+       * shortcut classification */
+      _thunar_assert_not_reached ();
+    }
+}
+
+
+
+static void
+thunar_shortcut_mount_changed (ThunarShortcut *shortcut)
+{
+  GIcon *icon;
+  gchar *name;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  /* don't update the information if this is not a mount shortcut */
+  if (!thunar_shortcut_matches_types (shortcut,
+                                      THUNAR_SHORTCUT_REGULAR_MOUNT 
+                                      | THUNAR_SHORTCUT_ARCHIVE_MOUNT
+                                      | THUNAR_SHORTCUT_NETWORK_MOUNT))
+    {
+      return;
+    }
 
-  /* load the ThunarFile asynchronously */
-  /* TODO pass a cancellable here */
-  thunar_browser_poke_location (THUNAR_BROWSER (shortcut),
-                                shortcut->location,
-                                NULL,
-                                thunar_shortcut_poke_location_finish,
-                                g_object_ref (shortcut));
+  /* only update if we have a mount */
+  if (shortcut->mount != NULL)
+    {
+      /* update the name of the shortcut */
+      name = g_mount_get_name (shortcut->mount);
+      thunar_shortcut_set_name (shortcut, name);
+      g_free (name);
+
+      /* update the icon of the shortcut  */
+      icon = g_mount_get_icon (shortcut->mount);
+      thunar_shortcut_set_icon (shortcut, icon);
+      g_object_unref (icon);
+
+      /* update the action button */
+      if (g_mount_can_unmount (shortcut->mount) || g_mount_can_eject (shortcut->mount))
+        gtk_widget_set_visible (shortcut->action_button, TRUE);
+      else
+        gtk_widget_set_visible (shortcut->action_button, FALSE);
+    }
+  else
+    {
+      /* if this is reached, there is something wrong the 
+       * shortcut classification */
+      _thunar_assert_not_reached ();
+    }
+}
+
+
+
+static void
+thunar_shortcut_icon_changed (ThunarShortcut *shortcut)
+{
+  GIcon *icon;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  /* get the icon (custom icon overrides the regular icon) */
+  icon = thunar_shortcut_get_custom_icon (shortcut);
+  if (icon == NULL)
+    icon = thunar_shortcut_get_icon (shortcut);
+
+  /* update the icon image */
+  gtk_image_set_from_gicon (GTK_IMAGE (shortcut->icon_image), icon, shortcut->icon_size);
+
+  /* update the icon's visibility */
+  gtk_widget_set_visible (shortcut->icon_image, icon != NULL);
+}
+
+
+
+static void
+thunar_shortcut_icon_size_changed (ThunarShortcut *shortcut)
+{
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  gtk_image_set_pixel_size (GTK_IMAGE (shortcut->icon_image), shortcut->icon_size);
+  gtk_image_set_pixel_size (GTK_IMAGE (shortcut->action_image), shortcut->icon_size);
+
+  gtk_widget_set_size_request (shortcut->spinner,
+                               shortcut->icon_size,
+                               shortcut->icon_size);
+}
+
+
+
+static void
+thunar_shortcut_hidden_changed (ThunarShortcut *shortcut)
+{
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  gtk_widget_set_visible (GTK_WIDGET (shortcut), !!shortcut->hidden);
+}
+
+
+
+static void
+thunar_shortcut_resolve_location_finish (ThunarBrowser *browser,
+                                         GFile         *location,
+                                         ThunarFile    *file,
+                                         ThunarFile    *target_file,
+                                         GError        *error,
+                                         gpointer       user_data)
+{
+  ThunarShortcut *shortcut = THUNAR_SHORTCUT (browser);
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+  _thunar_return_if_fail (G_IS_FILE (location));
+  _thunar_return_if_fail (file == NULL || THUNAR_IS_FILE (file));
+  _thunar_return_if_fail (target_file == NULL || THUNAR_IS_FILE (target_file));
+
+  /* assign the file to the shortcut */
+  thunar_shortcut_set_file (shortcut, target_file);
 }
 
 
@@ -508,10 +926,6 @@ void
 thunar_shortcut_set_location (ThunarShortcut *shortcut,
                               GFile          *location)
 {
-  GIcon *icon;
-  gchar *base_name;
-  gchar *uri;
-
   _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
   _thunar_return_if_fail (location == NULL || G_IS_FILE (location));
 
@@ -529,32 +943,7 @@ thunar_shortcut_set_location (ThunarShortcut *shortcut,
   else
     shortcut->location = NULL;
 
-  /* check if we have a file shortcut */
-  if (shortcut->type == THUNAR_SHORTCUT_REGULAR_FILE
-      || shortcut->type == THUNAR_SHORTCUT_NETWORK_FILE)
-    {
-      /* check whether we have a location */
-      if (shortcut->location != NULL)
-        {
-          /* use the location base name as the default name */
-          uri = g_file_get_uri (shortcut->location);
-          base_name = g_filename_display_basename (uri);
-          thunar_shortcut_set_name (shortcut, base_name);
-          g_free (base_name);
-          g_free (uri);
-
-          /* use the folder icon as the default icon */
-          if (shortcut->icon == NULL)
-            {
-              icon = g_themed_icon_new ("folder");
-              thunar_shortcut_set_icon (shortcut, icon);
-              g_object_unref (icon);
-            }
-
-          /* load file asynchronously */
-          thunar_shortcut_load_file (shortcut);
-        }
-    }
+  thunar_shortcut_location_changed (shortcut);
 
   g_object_notify (G_OBJECT (shortcut), "location");
 }
@@ -574,8 +963,6 @@ void
 thunar_shortcut_set_file (ThunarShortcut *shortcut,
                           ThunarFile     *file)
 {
-  GIcon *icon;
-
   _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
   _thunar_return_if_fail (file == NULL || THUNAR_IS_FILE (file));
 
@@ -593,22 +980,7 @@ thunar_shortcut_set_file (ThunarShortcut *shortcut,
   else
     shortcut->file = NULL;
 
-  /* check whether we have a file shortcut */
-  if (shortcut->type == THUNAR_SHORTCUT_REGULAR_FILE
-      || shortcut->type == THUNAR_SHORTCUT_NETWORK_FILE)
-    {
-      /* update only if we have a file */
-      if (shortcut->file != NULL)
-        {
-          /* update the name and icon of the shortcut */
-          thunar_shortcut_set_name (shortcut, 
-                                    thunar_file_get_display_name (shortcut->file));
-
-          icon = thunar_file_get_icon (shortcut->file);
-          if (icon != NULL)
-            thunar_shortcut_set_icon (shortcut, icon);
-        }
-    }
+  thunar_shortcut_file_changed (shortcut);
 
   g_object_notify (G_OBJECT (shortcut), "file");
 }
@@ -628,9 +1000,6 @@ void
 thunar_shortcut_set_volume (ThunarShortcut *shortcut,
                             GVolume        *volume)
 {
-  GIcon *icon;
-  gchar *name;
-
   _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
   _thunar_return_if_fail (volume == NULL || G_IS_VOLUME (volume));
 
@@ -648,22 +1017,7 @@ thunar_shortcut_set_volume (ThunarShortcut *shortcut,
   else
     shortcut->volume = NULL;
 
-  /* check if we have a regular or ejectable volume */
-  if (shortcut->type == THUNAR_SHORTCUT_REGULAR_VOLUME
-      || shortcut->type == THUNAR_SHORTCUT_EJECTABLE_VOLUME)
-    {
-      /* only update if we have a volume */
-      if (shortcut->volume != NULL)
-        {
-          /* update the name and icon of the shortcut */
-          name = g_volume_get_name (shortcut->volume);
-          icon = g_volume_get_icon (shortcut->volume);
-          thunar_shortcut_set_name (shortcut, name);
-          thunar_shortcut_set_icon (shortcut, icon);
-          g_object_unref (icon);
-          g_free (name);
-        }
-    }
+  thunar_shortcut_volume_changed (shortcut);
 
   g_object_notify (G_OBJECT (shortcut), "volume");
 }
@@ -683,9 +1037,6 @@ void
 thunar_shortcut_set_mount (ThunarShortcut *shortcut,
                            GMount         *mount)
 {
-  GIcon *icon;
-  gchar *name;
-
   _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
   _thunar_return_if_fail (mount == NULL || G_IS_MOUNT (mount));
 
@@ -703,21 +1054,8 @@ thunar_shortcut_set_mount (ThunarShortcut *shortcut,
   else
     shortcut->mount = NULL;
 
-  /* check if we have a standalone mount */
-  if (shortcut->type == THUNAR_SHORTCUT_STANDALONE_MOUNT)
-    {
-      /* only update if we have a mount */
-      if (shortcut->mount != NULL)
-        {
-          /* update the name and icon of the shortcut  */
-          name = g_mount_get_name (shortcut->mount);
-          icon = g_mount_get_icon (shortcut->mount);
-          thunar_shortcut_set_name (shortcut, name);
-          thunar_shortcut_set_icon (shortcut, icon);
-          g_object_unref (icon);
-          g_free (name);
-        }
-    }
+  thunar_shortcut_mount_changed (shortcut);
+
   g_object_notify (G_OBJECT (shortcut), "mount");
 }
 
@@ -753,6 +1091,8 @@ thunar_shortcut_set_icon (ThunarShortcut *shortcut,
   else
     shortcut->icon = NULL;
 
+  thunar_shortcut_icon_changed (shortcut);
+
   g_object_notify (G_OBJECT (shortcut), "icon");
 }
 
@@ -788,6 +1128,8 @@ thunar_shortcut_set_custom_icon (ThunarShortcut *shortcut,
   else
     shortcut->custom_icon = NULL;
 
+  thunar_shortcut_icon_changed (shortcut);
+
   g_object_notify (G_OBJECT (shortcut), "custom-icon");
 }
 
@@ -853,6 +1195,8 @@ thunar_shortcut_set_name (ThunarShortcut *shortcut,
 
   shortcut->name = g_strdup (name);
 
+  thunar_shortcut_name_changed (shortcut);
+
   g_object_notify (G_OBJECT (shortcut), "name");
 }
 
@@ -883,6 +1227,8 @@ thunar_shortcut_set_custom_name (ThunarShortcut *shortcut,
 
   shortcut->custom_name = g_strdup (custom_name);
 
+  thunar_shortcut_name_changed (shortcut);
+
   g_object_notify (G_OBJECT (shortcut), "custom-name");
 }
 
@@ -913,6 +1259,33 @@ thunar_shortcut_set_shortcut_type (ThunarShortcut    *shortcut,
 
 
 
+ThunarIconSize
+thunar_shortcut_get_icon_size (ThunarShortcut *shortcut)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_SHORTCUT (shortcut), 0);
+  return shortcut->icon_size;
+}
+
+
+
+void
+thunar_shortcut_set_icon_size (ThunarShortcut    *shortcut,
+                               ThunarIconSize icon_size)
+{
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  if (shortcut->icon_size == icon_size)
+    return;
+
+  shortcut->icon_size = icon_size;
+
+  thunar_shortcut_icon_size_changed (shortcut);
+
+  g_object_notify (G_OBJECT (shortcut), "icon-size");
+}
+
+
+
 gboolean
 thunar_shortcut_get_hidden (ThunarShortcut *shortcut)
 {
@@ -933,6 +1306,8 @@ thunar_shortcut_set_hidden (ThunarShortcut *shortcut,
 
   shortcut->hidden = hidden;
 
+  thunar_shortcut_hidden_changed (shortcut);
+
   g_object_notify (G_OBJECT (shortcut), "hidden");
 }
 
diff --git a/thunar/thunar-shortcut.h b/thunar/thunar-shortcut.h
index 1a8d6a7..8680f1d 100644
--- a/thunar/thunar-shortcut.h
+++ b/thunar/thunar-shortcut.h
@@ -69,6 +69,9 @@ void               thunar_shortcut_set_custom_name   (ThunarShortcut    *shortcu
 ThunarShortcutType thunar_shortcut_get_shortcut_type (ThunarShortcut    *shortcut);
 void               thunar_shortcut_set_shortcut_type (ThunarShortcut    *shortcut,
                                                       ThunarShortcutType shortcut_type);
+ThunarIconSize     thunar_shortcut_get_icon_size     (ThunarShortcut    *shortcut);
+void               thunar_shortcut_set_icon_size     (ThunarShortcut    *shortcut,
+                                                      ThunarIconSize     icon_size);
 gboolean           thunar_shortcut_get_hidden        (ThunarShortcut    *shortcut);
 void               thunar_shortcut_set_hidden        (ThunarShortcut    *shortcut,
                                                       gboolean           hidden);
diff --git a/thunar/thunar-shortcuts-model.c b/thunar/thunar-shortcuts-model.c
index cd7c91a..c59a8cd 100644
--- a/thunar/thunar-shortcuts-model.c
+++ b/thunar/thunar-shortcuts-model.c
@@ -934,7 +934,7 @@ thunar_shortcuts_model_find_category (ThunarShortcutsModel    *model,
             item_belongs_here = TRUE;
 
           /* mounts with mount points that are in archive:// belong here */
-          if (type == THUNAR_SHORTCUT_STANDALONE_MOUNT 
+          if (type == THUNAR_SHORTCUT_REGULAR_MOUNT 
               && file != NULL 
               && g_file_has_uri_scheme (file, "archive"))
             {
@@ -942,7 +942,7 @@ thunar_shortcuts_model_find_category (ThunarShortcutsModel    *model,
             }
 
           /* mounts with mount points that are in file:// belong here */
-          if (type == THUNAR_SHORTCUT_STANDALONE_MOUNT 
+          if (type == THUNAR_SHORTCUT_REGULAR_MOUNT 
               && file != NULL 
               && g_file_has_uri_scheme (file, "file"))
             {
@@ -966,7 +966,7 @@ thunar_shortcuts_model_find_category (ThunarShortcutsModel    *model,
             item_belongs_here = TRUE;
 
           /* remote mounts belong here */
-          if (type == THUNAR_SHORTCUT_STANDALONE_MOUNT
+          if (type == THUNAR_SHORTCUT_REGULAR_MOUNT
               && file != NULL 
               && !g_file_has_uri_scheme (file, "archive")
               && !g_file_has_uri_scheme (file, "file")
@@ -1633,7 +1633,7 @@ thunar_shortcuts_model_mount_added (ThunarShortcutsModel *model,
 
       /* create a shortcut for the mount */
       shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
-                               "shortcut-type", THUNAR_SHORTCUT_STANDALONE_MOUNT,
+                               "shortcut-type", THUNAR_SHORTCUT_REGULAR_MOUNT,
                                "location", location,
                                "mount", mount,
                                "eject-icon", eject_icon,
diff --git a/thunar/thunar-shortcuts-view.c b/thunar/thunar-shortcuts-view.c
index c1ff630..17f8dca 100644
--- a/thunar/thunar-shortcuts-view.c
+++ b/thunar/thunar-shortcuts-view.c
@@ -42,7 +42,8 @@
 #include <thunar/thunar-gtk-extensions.h>
 #include <thunar/thunar-preferences.h>
 #include <thunar/thunar-private.h>
-#include <thunar/thunar-shortcut-row.h>
+#include <thunar/thunar-shortcut-group.h>
+#include <thunar/thunar-shortcut.h>
 #include <thunar/thunar-shortcuts-model.h>
 #include <thunar/thunar-shortcuts-view.h>
 
@@ -73,9 +74,11 @@ enum
 
 
 
+#if 0
 typedef void (*ThunarShortcutsViewForeachRowFunc) (ThunarShortcutsView *view,
                                                    ThunarShortcutRow   *row,
                                                    gpointer             user_data);
+#endif
 
 
 
@@ -89,6 +92,23 @@ static void               thunar_shortcuts_view_set_property             (GObjec
                                                                           guint                             prop_id,
                                                                           const GValue                     *value,
                                                                           GParamSpec                       *pspec);
+static gboolean           thunar_shortcuts_view_load_system_shortcuts    (gpointer                          user_data);
+static void               thunar_shortcuts_view_create_home_shortcut     (ThunarShortcutsView              *view);
+static void               thunar_shortcuts_view_create_desktop_shortcut  (ThunarShortcutsView              *view);
+static void               thunar_shortcuts_view_create_trash_shortcut    (ThunarShortcutsView              *view);
+static void               thunar_shortcuts_view_create_network_shortcut  (ThunarShortcutsView              *view);
+static gboolean           thunar_shortcuts_view_load_user_dirs           (gpointer                          user_data);
+static gboolean           thunar_shortcuts_view_load_bookmarks           (gpointer                          user_data);
+static gboolean           thunar_shortcuts_view_load_volumes             (gpointer                          user_data);
+static void               thunar_shortcuts_view_volume_added             (ThunarShortcutsView              *view,
+                                                                          GVolume                          *volume,
+                                                                          GVolumeMonitor                   *monitor);
+static void               thunar_shortcuts_view_mount_added              (ThunarShortcutsView              *view,
+                                                                          GMount                           *mount,
+                                                                          GVolumeMonitor                   *monitor);
+static void               thunar_shortcuts_view_add_shortcut             (ThunarShortcutsView              *view,
+                                                                          ThunarShortcut                   *shortcut);
+#if 0
 static void               thunar_shortcuts_view_row_inserted             (ThunarShortcutsView              *view,
                                                                           GtkTreePath                      *path,
                                                                           GtkTreeIter                      *iter,
@@ -136,6 +156,7 @@ static void               thunar_shortcuts_view_unprelight_rows          (Thunar
 static void               thunar_shortcuts_view_update_selection_by_file (ThunarShortcutsView              *view,
                                                                           ThunarShortcutRow                *row,
                                                                           gpointer                          user_data);
+#endif
 
 
 
@@ -150,8 +171,10 @@ struct _ThunarShortcutsView
 
   ThunarxProviderFactory *provider_factory;
 
-  GtkTreeModel           *model;
-  GtkWidget              *expander_box;
+  GVolumeMonitor         *volume_monitor;
+  GtkWidget              *group_box;
+
+  guint                   load_idle_id;
 };
 
 
@@ -184,21 +207,7 @@ thunar_shortcuts_view_class_init (ThunarShortcutsViewClass *klass)
   gobject_class->set_property = thunar_shortcuts_view_set_property;
 
   /**
-   * ThunarShortcutsView:model:
-   *
-   * The #GtkTreeModel associated with this view.
-   **/
-  g_object_class_install_property (gobject_class,
-                                   PROP_MODEL,
-                                   g_param_spec_object ("model",
-                                                        "model",
-                                                        "model",
-                                                        GTK_TYPE_TREE_MODEL,
-                                                        EXO_PARAM_READWRITE |
-                                                        G_PARAM_CONSTRUCT));
-
-  /**
-   * ThunarShortcutsView:row-activated:
+   * ThunarShortcutsView:shortcut-activated:
    *
    * Invoked whenever a shortcut is activated by the user.
    **/
@@ -246,20 +255,44 @@ static void
 thunar_shortcuts_view_init (ThunarShortcutsView *view)
 {
   GtkWidget *alignment;
-
-  view->model = NULL;
+  GtkWidget *group;
 
   /* grab a reference on the provider factory */
   view->provider_factory = thunarx_provider_factory_get_default ();
 
+  /* add 4 pixels top and bottom padding around the contents of the shortcuts view */
   alignment = gtk_alignment_new (0.0f, 0.0f, 1.0f, 1.0f);
   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 4, 4, 0, 0);
   gtk_container_add (GTK_CONTAINER (view), alignment);
   gtk_widget_show (alignment);
 
-  view->expander_box = gtk_vbox_new (FALSE, 10);
-  gtk_container_add (GTK_CONTAINER (alignment), view->expander_box);
-  gtk_widget_show (view->expander_box);
+  /* create a box to put the groups of shortcuts in */
+  view->group_box = gtk_vbox_new (FALSE, 10);
+  gtk_container_add (GTK_CONTAINER (alignment), view->group_box);
+  gtk_widget_show (view->group_box);
+
+  /* create the devices group */
+  group = thunar_shortcut_group_new (_("DEVICES"), 
+                                     THUNAR_SHORTCUT_REGULAR_VOLUME 
+                                     | THUNAR_SHORTCUT_EJECTABLE_VOLUME 
+                                     | THUNAR_SHORTCUT_REGULAR_MOUNT
+                                     | THUNAR_SHORTCUT_ARCHIVE_MOUNT);
+  gtk_box_pack_start (GTK_BOX (view->group_box), group, FALSE, TRUE, 0);
+  gtk_widget_show (group);
+
+  /* create the places group */
+  group = thunar_shortcut_group_new (_("PLACES"),
+                                     THUNAR_SHORTCUT_REGULAR_FILE
+                                     | THUNAR_SHORTCUT_TRASH_FILE);
+  gtk_box_pack_start (GTK_BOX (view->group_box), group, FALSE, TRUE, 0);
+  gtk_widget_show (group);
+
+  /* create the network group */
+  group = thunar_shortcut_group_new (_("NETWORK"),
+                                     THUNAR_SHORTCUT_NETWORK_FILE 
+                                     | THUNAR_SHORTCUT_NETWORK_MOUNT);
+  gtk_box_pack_start (GTK_BOX (view->group_box), group, FALSE, TRUE, 0);
+  gtk_widget_show (group);
 }
 
 
@@ -268,6 +301,11 @@ static void
 thunar_shortcuts_view_constructed (GObject *object)
 {
   ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (object);
+
+  /* load shortcuts in a series of idle handlers */
+  view->load_idle_id = g_idle_add (thunar_shortcuts_view_load_system_shortcuts, view);
+
+#if 0
   GtkTreeIter          iter;
   GtkTreeIter          child_iter;
   GtkTreePath         *path;
@@ -356,6 +394,7 @@ thunar_shortcuts_view_constructed (GObject *object)
   /* be notified when a shortcut changes */
   g_signal_connect_swapped (view->model, "row-changed",
                             G_CALLBACK (thunar_shortcuts_view_row_changed), view);
+#endif
 }
 
 
@@ -368,9 +407,11 @@ thunar_shortcuts_view_finalize (GObject *object)
   /* release the provider factory */
   g_object_unref (G_OBJECT (view->provider_factory));
 
-  /* release the shortcuts model */
-  if (view->model != NULL)
-    g_object_unref (view->model);
+  /* disconnect and release the volume monitor */
+  g_signal_handlers_disconnect_matched (view->volume_monitor,
+                                        G_SIGNAL_MATCH_DATA,
+                                        0, 0, NULL, NULL, view);
+  g_object_unref (view->volume_monitor);
 
   (*G_OBJECT_CLASS (thunar_shortcuts_view_parent_class)->finalize) (object);
 }
@@ -383,14 +424,12 @@ thunar_shortcuts_view_get_property (GObject    *object,
                                     GValue     *value,
                                     GParamSpec *pspec)
 {
+#if 0
   ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (object);
+#endif
 
   switch (prop_id)
     {
-    case PROP_MODEL:
-      g_value_set_object (value, view->model);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -405,14 +444,12 @@ thunar_shortcuts_view_set_property (GObject      *object,
                                     const GValue *value,
                                     GParamSpec   *pspec)
 {
+#if 0
   ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (object);
+#endif
 
   switch (prop_id)
     {
-    case PROP_MODEL:
-      view->model = g_value_dup_object (value);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -421,6 +458,7 @@ thunar_shortcuts_view_set_property (GObject      *object,
 
 
 
+#if 0
 static void
 thunar_shortcuts_view_row_inserted (ThunarShortcutsView *view,
                                     GtkTreePath         *path,
@@ -1274,28 +1312,528 @@ thunar_shortcuts_view_open (ThunarShortcutsView *view,
       g_signal_emit (view, view_signals[SHORTCUT_ACTIVATED], 0, file);
     }
 }
+#endif
+
+
+
+static gboolean
+thunar_shortcuts_view_load_system_shortcuts (gpointer user_data)
+{
+  ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data);
+
+  _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view), FALSE);
+
+  thunar_shortcuts_view_create_home_shortcut (view);
+  thunar_shortcuts_view_create_desktop_shortcut (view);
+  thunar_shortcuts_view_create_trash_shortcut (view);
+  thunar_shortcuts_view_create_network_shortcut (view);
+
+  /* load rest of the user dirs next */
+  view->load_idle_id = g_idle_add (thunar_shortcuts_view_load_user_dirs, view);
+
+  return FALSE;
+}
+
+
+
+static void
+thunar_shortcuts_view_create_home_shortcut (ThunarShortcutsView *view)
+{
+  ThunarShortcut       *shortcut;
+  GFile                *home_file;
+  GIcon                *icon;
+  gchar                *path;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+
+  /* request a GFile for the home directory */
+  home_file = thunar_g_file_new_for_home ();
+
+  /* create $HOME information */
+  icon = g_themed_icon_new ("user-home");
+  path = g_file_get_path (home_file);
+  
+  /* create the $HOME shortcut */
+  shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
+                           "shortcut-type", THUNAR_SHORTCUT_REGULAR_FILE,
+                           "location", home_file,
+                           "icon", icon,
+                           "custom-name", NULL,
+                           "hidden", FALSE,
+                           "mutable", FALSE,
+                           "persistent", TRUE,
+                           NULL);
+
+  /* add the shortcut */
+  thunar_shortcuts_view_add_shortcut (view, shortcut);
+
+  /* release information */
+  g_free (path);
+  g_object_unref (icon);
+  g_object_unref (home_file);
+}
+
+
+
+static void
+thunar_shortcuts_view_create_desktop_shortcut (ThunarShortcutsView *view)
+{
+  ThunarShortcut       *shortcut;
+  GFile                *home_file;
+  GFile                *location;
+  GIcon                *icon;
+  gchar                *name = NULL;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+
+  /* request a GFile for the home directory */
+  home_file = thunar_g_file_new_for_home ();
+
+  /* request a GFile for the desktop directory */
+  location = thunar_g_file_new_for_desktop ();
+
+  /* check if desktop is set to home (in that case, ignore it) */
+  if (!g_file_equal (home_file, location))
+    {
+      /* create desktop information */
+      icon = g_themed_icon_new ("user-desktop");
+      name = g_strdup (_("Desktop"));
+
+      /* create the desktop shortcut */
+      shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
+                               "shortcut-type", THUNAR_SHORTCUT_REGULAR_FILE,
+                               "location", location,
+                               "icon", icon,
+                               "custom-name", name,
+                               "hidden", FALSE,
+                               "mutable", FALSE,
+                               "persistent", TRUE,
+                               NULL);
+
+      /* add the shortcut */
+      thunar_shortcuts_view_add_shortcut (view, shortcut);
+
+      /* release desktop information */
+      g_free (name);
+      g_object_unref (icon);
+    }
+
+  /* release desktop and home files */
+  g_object_unref (location);
+  g_object_unref (home_file);
+}
+
+
+
+static void
+thunar_shortcuts_view_create_trash_shortcut (ThunarShortcutsView *view)
+{
+  ThunarShortcut       *shortcut;
+  GFile                *location;
+  GIcon                *icon;
+  gchar                *name = NULL;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+
+  /* create trash information */
+  location = thunar_g_file_new_for_trash ();
+  icon = g_themed_icon_new ("user-trash");
+  name = g_strdup (_("Trash"));
+
+  /* create the trash shortcut */
+  shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
+                           "shortcut-type", THUNAR_SHORTCUT_TRASH_FILE,
+                           "location", location,
+                           "icon", icon,
+                           "custom-name", name,
+                           "hidden", FALSE,
+                           "mutable", FALSE,
+                           "persistent", TRUE,
+                           NULL);
+
+  /* add the shortcut */
+  thunar_shortcuts_view_add_shortcut (view, shortcut);
+
+  /* release trash information */
+  g_free (name);
+  g_object_unref (icon);
+  g_object_unref (location);
+}
+
+
+
+static void
+thunar_shortcuts_view_create_network_shortcut (ThunarShortcutsView *view)
+{
+  ThunarShortcut       *shortcut;
+  GFile                *location;
+  GIcon                *icon;
+  gchar                *name = NULL;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+
+  /* create network information */
+  /* TODO we need a new "uri" property for ThunarShortcut that is 
+   * resolved into a real GFile and then into a ThunarFile 
+   * asynchronously, otherwise allocating the network GFile may
+   * slow down the Thunar startup */
+  location = g_file_new_for_uri ("network://");
+  icon = g_themed_icon_new (GTK_STOCK_NETWORK);
+  name = g_strdup (_("Browse Network"));
+
+  /* create the network shortcut */
+  shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
+                           "shortcut-type", THUNAR_SHORTCUT_NETWORK_FILE,
+                           "location", location,
+                           "icon", icon,
+                           "custom-name", name,
+                           "hidden", FALSE,
+                           "mutable", FALSE,
+                           "persistent", TRUE,
+                           NULL);
+
+  /* add the network shortcut */
+  thunar_shortcuts_view_add_shortcut (view, shortcut);
+
+  /* release network information */
+  g_free (name);
+  g_object_unref (icon);
+  g_object_unref (location);
+}
+
+
+
+static gboolean
+thunar_shortcuts_view_load_user_dirs (gpointer user_data)
+{
+  ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data);
+
+  _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view), FALSE);
+  
+  /* load GTK bookmarks next */
+  view->load_idle_id = g_idle_add (thunar_shortcuts_view_load_bookmarks, view);
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_shortcuts_view_load_bookmarks (gpointer user_data)
+{
+  ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data);
+  ThunarShortcutType   type;
+  ThunarShortcut      *shortcut;
+  gboolean             is_local;
+  GFile               *bookmarks_file;
+  GFile               *home_file;
+  GFile               *location;
+  GIcon               *eject_icon;
+  GIcon               *icon;
+  gchar               *bookmarks_path;
+  gchar                line[2048];
+  gchar               *name;
+  FILE                *fp;
+
+  _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view), FALSE);
+
+  /* create an eject icon */
+  eject_icon = g_themed_icon_new ("media-eject");
+
+  /* resolve the bookmarks file */
+  home_file = thunar_g_file_new_for_home ();
+  bookmarks_file = g_file_resolve_relative_path (home_file, ".gtk-bookmarks");
+  bookmarks_path = g_file_get_path (bookmarks_file);
+  g_object_unref (bookmarks_file);
+  g_object_unref (home_file);
+
+  /* TODO remove all existing bookmarks */
+  
+  /* open the GTK bookmarks file for reading */
+  fp = fopen (bookmarks_path, "r");
+  if (fp != NULL)
+    {
+      while (fgets (line, sizeof (line), fp) != NULL)
+        {
+          /* strip leading and trailing whitespace */
+          g_strstrip (line);
+
+          /* skip over the URI */
+          for (name = line; *name != '\0' && !g_ascii_isspace (*name); ++name);
+
+          /* zero-terminate the URI */
+          *name++ = '\0';
+
+          /* check if we have a name */
+          for (; g_ascii_isspace (*name); ++name);
+
+          /* check if we have something that looks like a URI */
+          if (exo_str_looks_like_an_uri (line))
+            {
+              /* parse the URI */
+              location = g_file_new_for_uri (line);
+
+              /* only set the name property if the name is not empty */
+              name = *name != '\0' ? g_strdup (name) : NULL;
+
+              /* set initial icon and type based on the URI scheme */
+              is_local = g_file_has_uri_scheme (location, "file");
+              if (is_local)
+                {
+                  icon = g_themed_icon_new ("folder");
+                  type = THUNAR_SHORTCUT_REGULAR_FILE;
+                }
+              else
+                {
+                  icon = g_themed_icon_new ("folder-remote");
+                  type = THUNAR_SHORTCUT_NETWORK_FILE;
+                }
+
+              /* create the shortcut */
+              shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
+                                       "shortcut-type", type,
+                                       "location", location,
+                                       "icon", icon,
+                                       "eject-icon", eject_icon,
+                                       "custom-name", name,
+                                       "hidden", FALSE,
+                                       "mutable", TRUE,
+                                       "persistent", TRUE,
+                                       NULL);
+
+              /* add the shortcut */
+              thunar_shortcuts_view_add_shortcut (view, shortcut);
+
+              /* release file information */
+              g_free (name);
+              g_object_unref (icon);
+              g_object_unref (location);
+            }
+        }
+
+      /* close the file handle */
+      fclose (fp);
+    }
+  
+  /* free the bookmarks file path */
+  g_free (bookmarks_path);
+
+  /* release the eject icon */
+  g_object_unref (eject_icon);
+
+  /* TODO monitor the bookmarks file for changes */
+
+  /* load volumes next */
+  view->load_idle_id = g_idle_add (thunar_shortcuts_view_load_volumes, view);
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_shortcuts_view_load_volumes (gpointer user_data)
+{
+  ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (user_data);
+  GList               *mounts;
+  GList               *volumes;
+  GList               *lp;
+
+  _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view), FALSE);
+
+  /* get the default volume monitor */
+  view->volume_monitor = g_volume_monitor_get ();
+
+  /* get a list of all volumes available */
+  volumes = g_volume_monitor_get_volumes (view->volume_monitor);
+
+  /* create shortcuts for the volumes */
+  for (lp = volumes; lp != NULL; lp = lp->next)
+    {
+      /* add a new volume shortcut */
+      thunar_shortcuts_view_volume_added (view, lp->data, view->volume_monitor);
+    }
+
+  /* release the volume list */
+  g_list_free (volumes);
+
+  /* get a list of all mounts available */
+  mounts = g_volume_monitor_get_mounts (view->volume_monitor);
+
+  /* create shortcuts for the mounts */
+  for (lp = mounts; lp != NULL; lp = lp->next)
+    {
+      /* add a new mount shortcut */
+      thunar_shortcuts_view_mount_added (view, lp->data, view->volume_monitor);
+    }
+
+  /* release the mount list */
+  g_list_free (mounts);
+
+  /* be notified of new and removed volumes on the system */
+  g_signal_connect_swapped (view->volume_monitor, "volume-added",
+                            G_CALLBACK (thunar_shortcuts_view_volume_added), view);
+#if 0
+  g_signal_connect_swapped (view->volume_monitor, "volume-removed",
+                            G_CALLBACK (thunar_shortcuts_view_volume_removed), view);
+#endif
+  g_signal_connect_swapped (view->volume_monitor, "mount-added",
+                            G_CALLBACK (thunar_shortcuts_view_mount_added), view);
+#if 0
+  g_signal_connect_swapped (view->volume_monitor, "mount-removed",
+                            G_CALLBACK (thunar_shortcuts_view_mount_removed), view);
+#endif
+
+  /* reset the load idle ID */
+  view->load_idle_id = 0;
+
+  return FALSE;
+};
+
+
+
+static void
+thunar_shortcuts_view_volume_added (ThunarShortcutsView *view,
+                                    GVolume              *volume,
+                                    GVolumeMonitor       *monitor)
+{
+  ThunarShortcut *shortcut;
+  gboolean        hidden = FALSE;
+  GIcon          *eject_icon;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+  _thunar_return_if_fail (G_IS_VOLUME (volume));
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (monitor));
+
+  /* read information from the volume */
+  eject_icon = g_themed_icon_new ("media-eject");
+
+  /* hide the volume if there is no media */
+  if (!thunar_g_volume_is_present (volume))
+    hidden = TRUE;
+
+  /* hide the volume if it is not removable (this can be 
+   * overridden by the user in the shortcuts editor) */
+  if (!thunar_g_volume_is_removable (volume))
+    hidden = TRUE;
+
+  /* create a shortcut for the volume */
+  shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
+                           "shortcut-type", THUNAR_SHORTCUT_REGULAR_VOLUME,
+                           "volume", volume,
+                           "eject-icon", eject_icon,
+                           "hidden", hidden,
+                           "mutable", FALSE,
+                           "persistent", FALSE,
+                           NULL);
+
+  /* add the shortcut to the view */
+  thunar_shortcuts_view_add_shortcut (view, shortcut);
+
+  /* release volume information */
+  g_object_unref (eject_icon);
+}
+
+
+
+static void
+thunar_shortcuts_view_mount_added (ThunarShortcutsView *view,
+                                    GMount               *mount,
+                                    GVolumeMonitor       *monitor)
+{
+  ThunarShortcutType shortcut_type;
+  ThunarShortcut    *shortcut;
+  GVolume           *volume;
+  GFile             *location;
+  GIcon             *eject_icon;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+  _thunar_return_if_fail (G_IS_MOUNT (mount));
+  _thunar_return_if_fail (G_IS_VOLUME_MONITOR (monitor));
+
+  /* only create the shortcut if it has no volume */
+  volume = g_mount_get_volume (mount);
+  if (volume != NULL)
+    {
+      /* release the volume again */
+      g_object_unref (volume);
+    }
+  else
+    {
+      /* read information from the mount */
+      location = g_mount_get_root (mount);
+      eject_icon = g_themed_icon_new ("media-eject");
+
+      /* determine the shortcut type */
+      if (g_file_has_uri_scheme (location, "file"))
+        shortcut_type = THUNAR_SHORTCUT_REGULAR_MOUNT;
+      else if (g_file_has_uri_scheme (location, "archive"))
+        shortcut_type = THUNAR_SHORTCUT_ARCHIVE_MOUNT;
+      else
+        shortcut_type = THUNAR_SHORTCUT_NETWORK_MOUNT;
+
+      /* create a shortcut for the mount */
+      shortcut = g_object_new (THUNAR_TYPE_SHORTCUT,
+                               "shortcut-type", shortcut_type,
+                               "location", location,
+                               "mount", mount,
+                               "eject-icon", eject_icon,
+                               "hidden", FALSE,
+                               "mutable", FALSE,
+                               "persistent", FALSE,
+                               NULL);
+
+      /* add the shortcut to the view */
+      thunar_shortcuts_view_add_shortcut (view, shortcut);
+
+      /* release volume information */
+      g_object_unref (eject_icon);
+      g_object_unref (location);
+    }
+}
+
+
+
+static void
+thunar_shortcuts_view_add_shortcut (ThunarShortcutsView *view,
+                                    ThunarShortcut      *shortcut)
+{
+  ThunarShortcutGroup *group;
+  gboolean             shortcut_inserted = FALSE;
+  GList               *children;
+  GList               *child;
+
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUT (shortcut));
+
+  children = gtk_container_get_children (GTK_CONTAINER (view->group_box));
+  for (child = children; child != NULL && !shortcut_inserted; child = child->next)
+    {
+      group = THUNAR_SHORTCUT_GROUP (child->data);
+
+      if (thunar_shortcut_group_try_add_shortcut (group, shortcut))
+        shortcut_inserted = TRUE;
+    }
+  g_list_free (children);
+
+  /* TODO improve this error message by including the URI or volume/mount name */
+  if (!shortcut_inserted)
+    g_warning ("Failed to add a shortcut to the side pane.");
+}
 
 
 
 /**
  * thunar_shortcuts_view_new:
  *
- * Allocates a new #ThunarShortcutsView instance and associates
- * it with the default #ThunarShortcutsModel instance.
+ * Allocates a new #ThunarShortcutsView instance.
  *
  * Return value: the newly allocated #ThunarShortcutsView instance.
  **/
 GtkWidget*
 thunar_shortcuts_view_new (void)
 {
-  ThunarShortcutsModel *model;
-  GtkWidget            *view;
-
-  model = thunar_shortcuts_model_get_default ();
-  view = g_object_new (THUNAR_TYPE_SHORTCUTS_VIEW, "model", model, NULL);
-  g_object_unref (G_OBJECT (model));
-
-  return view;
+  return g_object_new (THUNAR_TYPE_SHORTCUTS_VIEW, NULL);
 }
 
 
@@ -1307,6 +1845,8 @@ thunar_shortcuts_view_has_file (ThunarShortcutsView *view,
   _thunar_return_val_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view), FALSE);
   _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
 
+  /* TODO */
+
   return FALSE;
 }
 
@@ -1318,6 +1858,8 @@ thunar_shortcuts_view_add_file (ThunarShortcutsView *view,
 {
   _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
   _thunar_return_if_fail (THUNAR_IS_FILE (file));
+
+  /* TODO */
 }
 
 
@@ -1338,9 +1880,12 @@ thunar_shortcuts_view_select_by_file (ThunarShortcutsView *view,
   _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
   _thunar_return_if_fail (THUNAR_IS_FILE (file));
 
+  /* TODO */
+#if 0
   thunar_shortcuts_view_foreach_row (view,
                                      thunar_shortcuts_view_update_selection_by_file,
                                      file);
+#endif
 }
 
 


More information about the Xfce4-commits mailing list