Index: gtk/gtkfilechooserdefault.c
===================================================================
--- gtk/gtkfilechooserdefault.c	(revision 17340)
+++ gtk/gtkfilechooserdefault.c	(working copy)
@@ -297,6 +297,7 @@ static void           gtk_file_chooser_d
 static GSList *       gtk_file_chooser_default_list_filters       	   (GtkFileChooser    *chooser);
 static gboolean       gtk_file_chooser_default_add_shortcut_folder    (GtkFileChooser    *chooser,
 								       const GtkFilePath *path,
+                                                                       const gchar       *label,
 								       GError           **error);
 static gboolean       gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
 								       const GtkFilePath *path,
@@ -1396,7 +1397,7 @@ get_file_info_finished (GtkFileSystemHan
 
       goto out;
     }
-  
+ 
   if (!request->label_copy)
     request->label_copy = g_strdup (gtk_file_info_get_display_name (info));
   pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
@@ -1508,7 +1509,7 @@ shortcuts_insert_path (GtkFileChooserDef
   GdkPixbuf *pixbuf = NULL;
   gpointer data = NULL;
   GtkTreeIter iter;
-  GtkIconTheme *icon_theme;      
+  GtkIconTheme *icon_theme; 
 
   profile_start ("start", is_volume ? "volume" : (char *) path);
 
@@ -1850,6 +1851,85 @@ shortcuts_add_volumes (GtkFileChooserDef
   profile_end ("end", NULL);
 }
 
+/* add global desktop places */
+static void
+shortcuts_add_places (GtkFileChooserDefault *impl)
+{
+#if 0
+  gboolean old_changing_folders;
+  gchar *filename;
+  GBookmarkFile *places;
+  gchar **uris;
+  gsize n_uris, i;
+  GError *error;
+
+  profile_start ("start", NULL);
+
+  old_changing_folders = impl->changing_folder;
+  impl->changing_folder = TRUE;
+
+  places = g_bookmark_file_new ();
+
+  error = NULL;
+  g_bookmark_file_load_from_data_dirs (places, ".places.xbel",
+                                       &filename,
+                                       &error);
+  if (error)
+    {
+      if (error->domain == G_BOOKMARK_FILE_ERROR &&
+          error->code != G_BOOKMARK_FILE_ERROR_FILE_NOT_FOUND)
+        {
+          g_warning ("Unable to load places: %s", error->message);
+        }
+
+      profile_end ("no places found", NULL);
+
+      g_error_free (error);
+      g_bookmark_file_free (places);
+
+      return;
+    }
+
+  uris = g_bookmark_file_get_uris (places, &n_uris);
+  for (i = 0; i < n_uris; i++)
+    {
+      GtkFilePath *path;
+      gchar *title, *label;
+
+      path = gtk_file_system_uri_to_path (impl->file_system, uris[i]);
+      if (!path)
+        {
+          g_warning ("Unable to add `%s' because it is an invalid path",
+                     uris[i]);
+          continue;
+        }
+
+      label = NULL;
+      title = g_bookmark_file_get_title (places, uris[i], NULL);
+      if (title)
+        label = g_strdup (gettext (title));
+
+      /* we don't want an error relayed here */
+      gtk_file_chooser_default_add_shortcut_folder (impl, path, label, NULL);
+
+      g_free (label);
+      g_free (title);
+      gtk_file_path_free (path);
+    }
+
+  if (impl->shortcuts_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+
+  g_strfreev (uris);
+  g_bookmark_file_free (places);
+  g_free (filename);
+  
+  impl->changing_folder = old_changing_folders;
+
+  profile_end ("end", NULL);
+#endif
+}
+
 /* Inserts a separator node in the shortcuts list */
 static void
 shortcuts_insert_separator (GtkFileChooserDefault *impl,
@@ -2061,6 +2141,7 @@ shortcuts_model_create (GtkFileChooserDe
       shortcuts_append_home (impl);
       shortcuts_append_desktop (impl);
       shortcuts_add_volumes (impl);
+      shortcuts_add_places (impl);
     }
 
   impl->shortcuts_filter_model = shortcuts_model_filter_new (impl,
@@ -6898,6 +6979,7 @@ struct AddShortcutData
 {
   GtkFileChooserDefault *impl;
   GtkFilePath *path;
+  gchar *label;
 };
 
 static void
@@ -6920,11 +7002,12 @@ add_shortcut_get_info_cb (GtkFileSystemH
 
   pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
 
-  shortcuts_insert_path (data->impl, pos, FALSE, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
+  shortcuts_insert_path (data->impl, pos, FALSE, NULL, data->path, data->label, FALSE, SHORTCUTS_SHORTCUTS);
 
 out:
   g_object_unref (data->impl);
   gtk_file_path_free (data->path);
+  g_free (data->label);
   g_free (data);
 
   g_object_unref (handle);
@@ -6933,6 +7016,7 @@ out:
 static gboolean
 gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser    *chooser,
 					      const GtkFilePath *path,
+                                              const gchar       *label,
 					      GError           **error)
 {
   GtkFileSystemHandle *handle;
@@ -6984,6 +7068,7 @@ gtk_file_chooser_default_add_shortcut_fo
   data = g_new0 (struct AddShortcutData, 1);
   data->impl = g_object_ref (impl);
   data->path = gtk_file_path_copy (path);
+  data->label = g_strdup (label);
 
   handle = gtk_file_system_get_info (impl->file_system, path,
 				     GTK_FILE_INFO_IS_FOLDER,
Index: gtk/gtkfilechooserprivate.h
===================================================================
--- gtk/gtkfilechooserprivate.h	(revision 17340)
+++ gtk/gtkfilechooserprivate.h	(working copy)
@@ -66,6 +66,7 @@ struct _GtkFileChooserIface
   GSList *       (*list_filters)       	   (GtkFileChooser    *chooser);
   gboolean       (*add_shortcut_folder)    (GtkFileChooser    *chooser,
 					    const GtkFilePath *path,
+                                            const gchar       *label,
 					    GError           **error);
   gboolean       (*remove_shortcut_folder) (GtkFileChooser    *chooser,
 					    const GtkFilePath *path,
@@ -95,6 +96,7 @@ GSList *       _gtk_file_chooser_get_pat
 GtkFilePath *  _gtk_file_chooser_get_preview_path        (GtkFileChooser    *chooser);
 gboolean       _gtk_file_chooser_add_shortcut_folder     (GtkFileChooser    *chooser,
 							  const GtkFilePath *path,
+                                                          const gchar       *label,
 							  GError           **error);
 gboolean       _gtk_file_chooser_remove_shortcut_folder  (GtkFileChooser    *chooser,
 							  const GtkFilePath *path,
Index: gtk/gtkfilechooserbutton.c
===================================================================
--- gtk/gtkfilechooserbutton.c	(revision 17340)
+++ gtk/gtkfilechooserbutton.c	(working copy)
@@ -199,6 +199,7 @@ enum
 static void     gtk_file_chooser_button_file_chooser_iface_init (GtkFileChooserIface *iface);
 static gboolean gtk_file_chooser_button_add_shortcut_folder     (GtkFileChooser      *chooser,
 								 const GtkFilePath   *path,
+                                                                 const gchar         *label,
 								 GError             **error);
 static gboolean gtk_file_chooser_button_remove_shortcut_folder  (GtkFileChooser      *chooser,
 								 const GtkFilePath   *path,
@@ -315,9 +316,11 @@ static guint file_chooser_button_signals
  *  GType Declaration  *
  * ******************* */
 
-G_DEFINE_TYPE_WITH_CODE (GtkFileChooserButton, gtk_file_chooser_button, GTK_TYPE_HBOX, { \
-    G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER, gtk_file_chooser_button_file_chooser_iface_init) \
-})
+G_DEFINE_TYPE_WITH_CODE (GtkFileChooserButton,
+                         gtk_file_chooser_button,
+                         GTK_TYPE_HBOX,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
+                                                gtk_file_chooser_button_file_chooser_iface_init))
 
 
 /* ***************** *
@@ -542,6 +545,7 @@ gtk_file_chooser_button_file_chooser_ifa
 static gboolean
 gtk_file_chooser_button_add_shortcut_folder (GtkFileChooser     *chooser,
 					     const GtkFilePath  *path,
+                                             const gchar        *label,
 					     GError            **error)
 {
   GtkFileChooser *delegate;
@@ -549,7 +553,7 @@ gtk_file_chooser_button_add_shortcut_fol
 
   delegate = g_object_get_qdata (G_OBJECT (chooser),
 				 GTK_FILE_CHOOSER_DELEGATE_QUARK);
-  retval = _gtk_file_chooser_add_shortcut_folder (delegate, path, error);
+  retval = _gtk_file_chooser_add_shortcut_folder (delegate, path, label, error);
 
   if (retval)
     {
@@ -557,14 +561,21 @@ gtk_file_chooser_button_add_shortcut_fol
       GtkFileChooserButtonPrivate *priv = button->priv;
       GtkTreeIter iter;
       gint pos;
+      const gchar *display_name;
 
       pos = model_get_type_position (button, ROW_TYPE_SHORTCUT);
       pos += priv->n_shortcuts;
 
+      if (label)
+        display_name = label;
+      else
+        display_name = _(FALLBACK_DISPLAY_NAME);
+
+
       gtk_list_store_insert (GTK_LIST_STORE (priv->model), &iter, pos);
       gtk_list_store_set (GTK_LIST_STORE (priv->model), &iter,
 			  ICON_COLUMN, NULL,
-			  DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME),
+			  DISPLAY_NAME_COLUMN, display_name,
 			  TYPE_COLUMN, ROW_TYPE_SHORTCUT,
 			  DATA_COLUMN, gtk_file_path_copy (path),
 			  IS_FOLDER_COLUMN, FALSE,
Index: gtk/gtkfilesystemunix.c
===================================================================
--- gtk/gtkfilesystemunix.c	(revision 17340)
+++ gtk/gtkfilesystemunix.c	(working copy)
@@ -46,7 +46,8 @@
 #include <stdio.h>
 #include <time.h>
 
-#define BOOKMARKS_FILENAME ".gtk-bookmarks"
+#define BOOKMARKS_OLD_FILENAME  ".gtk-bookmarks"
+#define BOOKMARKS_FILENAME      "gtk-bookmarks.xbel"
 
 #define HIDDEN_FILENAME ".hidden"
 
@@ -78,6 +79,9 @@ struct _GtkFileSystemUnix
   guint execute_callbacks_idle_id;
   GSList *callbacks;
 
+  GBookmarkFile *bookmarks;
+  time_t bookmarks_last_mtime;
+
   guint have_afs : 1;
   guint have_net : 1;
 };
@@ -358,6 +362,9 @@ gtk_file_system_unix_init (GtkFileSystem
 
   system_unix->execute_callbacks_idle_id = 0;
   system_unix->callbacks = NULL;
+
+  system_unix->bookmarks = NULL;
+  system_unix->bookmarks_last_mtime = (time_t) -1;
 }
 
 static void
@@ -1769,17 +1776,6 @@ get_icon_name_for_mime_type (const char 
 #endif
 }
 
-static void
-bookmark_list_free (GSList *list)
-{
-  GSList *l;
-
-  for (l = list; l; l = l->next)
-    g_free (l->data);
-
-  g_slist_free (list);
-}
-
 /* Returns whether a URI is a local file:// */
 static gboolean
 is_local_uri (const char *uri)
@@ -1799,81 +1795,172 @@ is_local_uri (const char *uri)
   return result;
 }
 
-static char *
-bookmark_get_filename (void)
+static gchar *
+bookmark_get_filename (gboolean old_format)
 {
-  char *filename;
+  gchar *filename;
+
+  if (!old_format)
+    {
+      filename = g_build_filename (g_get_home_dir (),
+                                   ".local",
+                                   "share",
+                                   "places",
+                                   BOOKMARKS_FILENAME,
+                                   NULL);
+    }
+  else
+    {
+      filename = g_build_filename (g_get_home_dir (),
+                                   BOOKMARKS_OLD_FILENAME,
+                                   NULL);
+    }
 
-  filename = g_build_filename (g_get_home_dir (), 
-			       BOOKMARKS_FILENAME, NULL);
   g_assert (filename != NULL);
   return filename;
 }
 
 static gboolean
-bookmark_list_read (GSList **bookmarks, GError **error)
+bookmark_list_read (GtkFileSystemUnix  *system_unix,
+                    GError            **error)
 {
   gchar *filename;
   gchar *contents;
+  GBookmarkFile *bookmark;
+  struct stat stat_buf;
+  time_t now;
+  gboolean try_old_format = FALSE;
   gboolean result = FALSE;
 
-  filename = bookmark_get_filename ();
-  *bookmarks = NULL;
+  if (!system_unix->bookmarks)
+    {
+      bookmark = g_bookmark_file_new ();
+      system_unix->bookmarks = bookmark;
+    }
+  else
+    bookmark = system_unix->bookmarks;
 
-  if (g_file_get_contents (filename, &contents, NULL, error))
+  filename = g_build_filename (g_get_home_dir (),
+                               ".local",
+                               "share",
+                               "places",
+                               NULL);
+  g_mkdir_with_parents (filename, 0700);
+  g_free (filename);
+
+  time (&now);
+
+  filename = bookmark_get_filename (FALSE);
+  if (stat (filename, &stat_buf) == -1)
     {
-      gchar **lines = g_strsplit (contents, "\n", -1);
-      int i;
-      GHashTable *table;
+      if (errno != ENOENT)
+        {
+          g_set_error (error, GTK_FILE_SYSTEM_ERROR,
+                       GTK_FILE_SYSTEM_ERROR_FAILED,
+                       _("Bookmark loading failed: %s"),
+                       g_strerror (errno));
+          g_free (filename);
+          return FALSE;
+        }
+      else
+        {
+          /* force a read, and load the old format first */
+          stat_buf.st_mtime = now;
+          system_unix->bookmarks_last_mtime = (time_t) -1;
+          try_old_format = TRUE;
+        }
+    }
 
-      table = g_hash_table_new (g_str_hash, g_str_equal);
+  /* read the bookmarks only if the on disk representation
+   * has been changed, or if we didn't load them already
+   */
+  if (stat_buf.st_mtime > system_unix->bookmarks_last_mtime)
+    {
+      /* load new format if we found the file */
+      if (!try_old_format)
+        result = g_bookmark_file_load_from_file (bookmark, filename, error);
+       
+      /* merge with the old one */
+      g_free (filename);
+      filename = bookmark_get_filename (TRUE);
+      if (g_file_get_contents (filename, &contents, NULL, error))
+        {
+          gchar **lines = g_strsplit (contents, "\n", -1);
+          int i;
 
-      for (i = 0; lines[i]; i++)
-	{
-	  if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
-	    {
-	      *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
-	      g_hash_table_insert (table, lines[i], lines[i]);
-	    }
-	}
+          for (i = 0; lines[i]; i++)
+            {
+              gchar *uri, *label;
+
+              uri = lines[i];
+              if (!uri || *uri == '\0')
+                break;
+
+              label = strchr (lines[i], ' ');
+              if (label && *label != '\0')
+                {
+                  *label = '\0';
+                  label += 1;
+                }
+
+              if (!g_bookmark_file_has_item (bookmark, uri))
+                {
+                  if (label && *label)
+                    g_bookmark_file_set_title (bookmark, uri, label);
+
+                  /* use what gnome-vfs uses for MIME type */
+                  g_bookmark_file_set_mime_type (bookmark, uri,
+                                                 "x-directory/normal");
+                  g_bookmark_file_add_application (bookmark, uri,
+                                                   NULL, NULL);
+                }
+            }
 
-      g_free (contents);
-      g_hash_table_destroy (table);
-      g_strfreev (lines);
+          g_free (contents);
+          g_strfreev (lines);
 
-      *bookmarks = g_slist_reverse (*bookmarks);
-      result = TRUE;
+          result = TRUE;
+        }
     }
+  else
+    result = TRUE;
 
   g_free (filename);
 
+  if (result)
+    system_unix->bookmarks_last_mtime = stat_buf.st_mtime;
+
   return result;
 }
 
 static gboolean
-bookmark_list_write (GSList  *bookmarks, 
-		     GError **error)
+bookmark_list_write (GtkFileSystemUnix  *system_unix,
+		     GError            **error)
 {
-  GSList *l;
-  GString *string;
-  char *filename;
+  gchar *data;
+  gchar *filename;
+  gsize len;
   GError *tmp_error = NULL;
   gboolean result;
 
-  string = g_string_new ("");
+  filename = g_build_filename (g_get_home_dir (),
+                               ".local",
+                               "share",
+                               "places",
+                               NULL);
+  g_mkdir_with_parents (filename, 0700);
+  g_free (filename);
 
-  for (l = bookmarks; l; l = l->next)
-    {
-      g_string_append (string, l->data);
-      g_string_append_c (string, '\n');
-    }
+  filename = bookmark_get_filename (FALSE);
 
-  filename = bookmark_get_filename ();
+  if (!system_unix->bookmarks)
+    system_unix->bookmarks = g_bookmark_file_new ();
 
-  result = g_file_set_contents (filename, string->str, -1, &tmp_error);
+  data = g_bookmark_file_to_data (system_unix->bookmarks, &len, NULL);
+  result = g_file_set_contents (filename, data, len, &tmp_error);
 
+  g_free (data);
   g_free (filename);
-  g_string_free (string, TRUE);
 
   if (!result)
     {
@@ -1886,6 +1973,9 @@ bookmark_list_write (GSList  *bookmarks,
       g_error_free (tmp_error);
     }
 
+  /* force a reload next time we read the list */
+  system_unix->bookmarks_last_mtime = (time_t) -1;
+
   return result;
 }
 
@@ -1895,63 +1985,51 @@ gtk_file_system_unix_insert_bookmark (Gt
 				      gint               position,
 				      GError           **error)
 {
-  GSList *bookmarks;
-  int num_bookmarks;
-  GSList *l;
-  char *uri;
+  GtkFileSystemUnix *system_unix;
+  gint num_bookmarks;
+  gchar *uri;
   gboolean result;
   GError *err;
 
+  system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
+
   err = NULL;
-  if (!bookmark_list_read (&bookmarks, &err) && err->code != G_FILE_ERROR_NOENT)
+  if (!bookmark_list_read (system_unix, &err) &&
+      err->domain == G_FILE_ERROR &&
+      err->code != G_FILE_ERROR_NOENT)
     {
       g_propagate_error (error, err);
       return FALSE;
     }
 
-  num_bookmarks = g_slist_length (bookmarks);
+  num_bookmarks = g_bookmark_file_get_size (system_unix->bookmarks);
   g_return_val_if_fail (position >= -1 && position <= num_bookmarks, FALSE);
 
   result = FALSE;
-
   uri = gtk_file_system_unix_path_to_uri (file_system, path);
-
-  for (l = bookmarks; l; l = l->next)
+  if (!g_bookmark_file_has_item (system_unix->bookmarks, uri))
     {
-      char *bookmark, *space;
-
-      bookmark = l->data;
-      
-      space = strchr (bookmark, ' ');
-      if (space)
-	*space = '\0';
-      if (strcmp (bookmark, uri) != 0)
-	{
-	  if (space)
-	    *space = ' ';
-	}
-      else
-	{
-	  g_set_error (error,
-		       GTK_FILE_SYSTEM_ERROR,
-		       GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
-		       _("'%s' already exists in the bookmarks list"),
-		       uri);
-	  goto out;
-	}
+      g_bookmark_file_set_mime_type (system_unix->bookmarks, uri, "x-directory/normal");
+      g_bookmark_file_add_application (system_unix->bookmarks, uri, NULL, NULL);
+    }
+  else
+    {
+      g_set_error (error,
+                   GTK_FILE_SYSTEM_ERROR,
+		   GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
+		   _("'%s' already exists in the bookmarks list"),
+		   uri);
+      goto out;
     }
 
-  bookmarks = g_slist_insert (bookmarks, g_strdup (uri), position);
-  if (bookmark_list_write (bookmarks, error))
+  if (bookmark_list_write (system_unix, error))
     {
       result = TRUE;
       g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
     }
 
- out:
-
+out:
   g_free (uri);
-  bookmark_list_free (bookmarks);
 
   return result;
 }
@@ -1961,59 +2039,37 @@ gtk_file_system_unix_remove_bookmark (Gt
 				      const GtkFilePath *path,
 				      GError           **error)
 {
-  GSList *bookmarks;
-  char *uri;
-  GSList *l;
+  GtkFileSystemUnix *system_unix;
+  gchar *uri;
   gboolean result;
 
-  if (!bookmark_list_read (&bookmarks, error))
+  system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
+  
+  if (!bookmark_list_read (system_unix, error))
     return FALSE;
 
   result = FALSE;
 
   uri = gtk_file_system_path_to_uri (file_system, path);
 
-  for (l = bookmarks; l; l = l->next)
+  if (!g_bookmark_file_remove_item (system_unix->bookmarks, uri, NULL))
     {
-      char *bookmark, *space;
-
-      bookmark = (char *)l->data;
-      space = strchr (bookmark, ' ');
-      if (space)
-	*space = '\0';
-
-      if (strcmp (bookmark, uri) != 0)
-	{
-	  if (space)
-	    *space = ' ';
-	}
-      else
-	{
-	  g_free (l->data);
-	  bookmarks = g_slist_remove_link (bookmarks, l);
-	  g_slist_free_1 (l);
-
-	  if (bookmark_list_write (bookmarks, error))
-	    {
-	      result = TRUE;
-
-	      g_signal_emit_by_name (file_system, "bookmarks-changed", 0);	      
-	    }
-
-	  goto out;
-	}
+      g_set_error (error,
+                   GTK_FILE_SYSTEM_ERROR,
+                   GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
+                   _("'%s' does not exist in the bookmarks list"),
+                   uri);
+    }
+  else
+    {
+      if (bookmark_list_write (system_unix, error))
+        {
+          result = TRUE;
+          g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
+        }
     }
-
-  g_set_error (error,
-	       GTK_FILE_SYSTEM_ERROR,
-	       GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
-	       _("'%s' does not exist in the bookmarks list"),
-	       uri);
-
- out:
 
   g_free (uri);
-  bookmark_list_free (bookmarks);
 
   return result;
 }
@@ -2021,63 +2077,54 @@ gtk_file_system_unix_remove_bookmark (Gt
 static GSList *
 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
 {
-  GSList *bookmarks;
+  GtkFileSystemUnix *system_unix;
   GSList *result;
-  GSList *l;
 
-  if (!bookmark_list_read (&bookmarks, NULL))
+  system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
+  if (!bookmark_list_read (system_unix, NULL))
     return NULL;
 
   result = NULL;
 
-  for (l = bookmarks; l; l = l->next)
+  if (system_unix->bookmarks)
     {
-      char *bookmark, *space;
+      gchar **uris;
+      gsize n_uris, i;
 
-      bookmark = (char *)l->data;
-      space = strchr (bookmark, ' ');
-      if (space)
-	*space = '\0';
-
-      if (is_local_uri (bookmark))
-	result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, bookmark));
+      uris = g_bookmark_file_get_uris (system_unix->bookmarks, &n_uris);
+      for (i = 0; i < n_uris; i++)
+        {
+          if (is_local_uri (uris[i]))
+            {
+              GtkFilePath *path;
+
+              path = gtk_file_system_unix_uri_to_path (file_system, uris[i]);
+              result = g_slist_prepend (result, path);
+            }
+        }
+      
+      g_strfreev (uris);
     }
 
-  bookmark_list_free (bookmarks);
-
-  result = g_slist_reverse (result);
-  return result;
+  return g_slist_reverse (result);
 }
 
 static gchar *
 gtk_file_system_unix_get_bookmark_label (GtkFileSystem     *file_system,
 					 const GtkFilePath *path)
 {
-  GSList *labels;
-  gchar *label;
-  GSList *l;
-  char *bookmark, *space, *uri;
-  
-  labels = NULL;
-  label = NULL;
-
-  uri = gtk_file_system_path_to_uri (file_system, path);
-  bookmark_list_read (&labels, NULL);
-
-  for (l = labels; l && !label; l = l->next) 
-    {
-      bookmark = (char *)l->data;
-      space = strchr (bookmark, ' ');
-      if (!space)
-	continue;
+  GtkFileSystemUnix *system_unix;
+  gchar *uri, *label;
 
-      *space = '\0';
+  system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
+  if (!bookmark_list_read (system_unix, NULL))
+    return NULL;
 
-      if (strcmp (uri, bookmark) == 0)
-	label = g_strdup (space + 1);
-    }
+  label = NULL;
+  
+  uri = gtk_file_system_path_to_uri (file_system, path);
+  label = g_bookmark_file_get_title (system_unix->bookmarks, uri, NULL);
 
-  bookmark_list_free (labels);
   g_free (uri);
 
   return label;
@@ -2088,50 +2135,24 @@ gtk_file_system_unix_set_bookmark_label 
 					 const GtkFilePath *path,
 					 const gchar       *label)
 {
-  GSList *labels;
-  GSList *l;
-  gchar *bookmark, *space, *uri;
-  gboolean found;
+  GtkFileSystemUnix *system_unix;
+  gchar *uri;
 
-  labels = NULL;
+  system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
+  
+  if (!bookmark_list_read (system_unix, NULL))
+    return;
 
   uri = gtk_file_system_path_to_uri (file_system, path);
-  bookmark_list_read (&labels, NULL);
 
-  found = FALSE;
-  for (l = labels; l && !found; l = l->next) 
+  if (g_bookmark_file_has_item (system_unix->bookmarks, uri))
     {
-      bookmark = (gchar *)l->data;
-      space = strchr (bookmark, ' ');
-      if (space)
-	*space = '\0';
+      g_bookmark_file_set_title (system_unix->bookmarks, uri, label);
 
-      if (strcmp (bookmark, uri) != 0)
-	{
-	  if (space)
-	    *space = ' ';
-	}
-      else
-	{
-	  g_free (bookmark);
-	  
-	  if (label && *label)
-	    l->data = g_strdup_printf ("%s %s", uri, label);
-	  else
-	    l->data = g_strdup (uri);
-
-	  found = TRUE;
-	  break;
-	}
+      if (bookmark_list_write (system_unix, NULL))
+        g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
     }
 
-  if (found)
-    {
-      if (bookmark_list_write (labels, NULL))
-	g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
-    }
-  
-  bookmark_list_free (labels);
   g_free (uri);
 }
 
Index: gtk/Makefile.am
===================================================================
--- gtk/Makefile.am	(revision 17340)
+++ gtk/Makefile.am	(working copy)
@@ -853,7 +853,7 @@ LDADDS =								\
 #
 # Installed tools
 #
-bin_PROGRAMS = gtk-query-immodules-2.0 gtk-update-icon-cache
+bin_PROGRAMS = gtk-query-immodules-2.0 gtk-update-icon-cache gtk-update-bookmarks-cache
 
 gtk_query_immodules_2_0_DEPENDENCIES = $(DEPS)
 gtk_query_immodules_2_0_LDADD = $(LDADDS)
@@ -864,6 +864,10 @@ gtk_update_icon_cache_LDADD = $(top_buil
 
 gtk_update_icon_cache_SOURCES = updateiconcache.c
 
+gtk_update_bookmarks_cache_DEPENDENCIES = $(DEPS)
+gtk_update_bookmarks_cache_LDADD = $(LDADDS)
+gtk_update_bookmarks_cache_SOURCES = updatebookmarkscache.c
+
 .PHONY: files test test-debug
 
 files:
Index: gtk/gtkfilechooserutils.c
===================================================================
--- gtk/gtkfilechooserutils.c	(revision 17340)
+++ gtk/gtkfilechooserutils.c	(working copy)
@@ -50,6 +50,7 @@ static void           delegate_remove_fi
 static GSList *       delegate_list_filters           (GtkFileChooser    *chooser);
 static gboolean       delegate_add_shortcut_folder    (GtkFileChooser    *chooser,
 						       const GtkFilePath *path,
+                                                       const gchar       *label,
 						       GError           **error);
 static gboolean       delegate_remove_shortcut_folder (GtkFileChooser    *chooser,
 						       const GtkFilePath *path,
@@ -270,9 +271,10 @@ delegate_list_filters (GtkFileChooser *c
 static gboolean
 delegate_add_shortcut_folder (GtkFileChooser    *chooser,
 			      const GtkFilePath *path,
+                              const gchar       *label,
 			      GError           **error)
 {
-  return _gtk_file_chooser_add_shortcut_folder (get_delegate (chooser), path, error);
+  return _gtk_file_chooser_add_shortcut_folder (get_delegate (chooser), path, label, error);
 }
 
 static gboolean
Index: gtk/gtkfilechooser.c
===================================================================
--- gtk/gtkfilechooser.c	(revision 17340)
+++ gtk/gtkfilechooser.c	(working copy)
@@ -1384,6 +1384,7 @@ _gtk_file_chooser_get_preview_path (GtkF
  * _gtk_file_chooser_add_shortcut_folder:
  * @chooser: a #GtkFileChooser
  * @path: path of the folder to add
+ * @label: label for the folder, or %NULL
  * @error: location to store error, or %NULL
  * 
  * Adds a folder to be displayed with the shortcut folders in a file chooser.
@@ -1397,12 +1398,13 @@ _gtk_file_chooser_get_preview_path (GtkF
 gboolean
 _gtk_file_chooser_add_shortcut_folder (GtkFileChooser    *chooser,
 				       const GtkFilePath *path,
+                                       const gchar       *label,
 				       GError           **error)
 {
   g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
   g_return_val_if_fail (path != NULL, FALSE);
 
-  return GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser, path, error);
+  return GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser, path, label, error);
 }
 
 /**
@@ -1696,7 +1698,7 @@ gtk_file_chooser_add_shortcut_folder (Gt
       return FALSE;
     }
 
-  result = GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser, path, error);
+  result = GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser, path, NULL, error);
 
   gtk_file_path_free (path);
 
@@ -1815,7 +1817,7 @@ gtk_file_chooser_add_shortcut_folder_uri
       return FALSE;
     }
 
-  result = GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser, path, error);
+  result = GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser, path, NULL, error);
 
   gtk_file_path_free (path);
 
@@ -1990,6 +1992,100 @@ gtk_file_chooser_get_do_overwrite_confir
   return do_overwrite_confirmation;
 }
 
+/**
+ * gtk_file_chooser_add_shortcuts_from_file:
+ * @chooser: a #GtkFileChooser
+ * @filename: location for the bookmarks file
+ * @domain: translation domain for localising the shortcuts label
+ * @error: return location for a #GError or %NULL
+ *
+ * Adds all the shortcuts from @filename.
+ *
+ * Return value: %TRUE if the shortcuts were added successfully,
+ *   %FALSE otherwise
+ *
+ * Since: 2.14
+ */
+gboolean
+gtk_file_chooser_add_shortcuts_from_file (GtkFileChooser  *chooser,
+                                          const gchar     *filename,
+                                          const gchar     *domain,
+                                          GError         **error)
+{
+  GBookmarkFile *bookmarks;
+  GError *err = NULL;
+  gchar **uris = NULL;
+  gsize n_uris, i;
+  gboolean retval = FALSE;
+
+  g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
+  g_return_val_if_fail (filename != NULL, FALSE);
+
+  bookmarks = g_bookmark_file_new ();
+  retval = g_bookmark_file_load_from_file (bookmarks, filename, &err);
+  if (!retval)
+    {
+      g_propagate_error (error, err);
+      goto out;
+    }
+
+  uris = g_bookmark_file_get_uris (bookmarks, &n_uris);
+  for (i = 0; i < n_uris; i++)
+    {
+      gchar *uri = uris[i];
+      GtkFilePath *path;
+      gchar *title;
+
+      path = gtk_file_system_uri_to_path (_gtk_file_chooser_get_file_system (chooser), uri);
+      if (!path)
+        {
+          g_set_error (error,
+                       GTK_FILE_CHOOSER_ERROR,
+                       GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+                       _("Invalid filename: %s"),
+                       uri);
+          retval = FALSE;
+          break;
+        }
+
+      title = g_bookmark_file_get_title (bookmarks, uri, NULL);
+      if (title)
+        {
+          gchar *label = g_strdup (dgettext (domain, title));
+
+          retval =
+            GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser,
+                                                                       path,
+                                                                       title,
+                                                                       error);
+          g_free (title);
+          g_free (label);
+        }
+      else
+        {
+          retval =
+            GTK_FILE_CHOOSER_GET_IFACE (chooser)->add_shortcut_folder (chooser,
+                                                                       path,
+                                                                       NULL,
+                                                                       error);
+        }
+      
+      gtk_file_path_free (path);
+      
+      if (!retval)
+        break;
+    }
+
+  if (uris)
+    g_strfreev (uris);
+  
+out:
+  g_bookmark_file_free (bookmarks);
+
+  return retval;
+}
+
+
 #ifdef G_OS_WIN32
 
 /* DLL ABI stability backward compatibility versions */
@@ -2157,7 +2253,7 @@ gtk_file_chooser_list_shortcut_folders (
   return list;
 }
 
-#endif
+#endif /* G_OS_WIN32 */
 
 #define __GTK_FILE_CHOOSER_C__
 #include "gtkaliasdef.c"
Index: gtk/gtkfilechooser.h
===================================================================
--- gtk/gtkfilechooser.h	(revision 17340)
+++ gtk/gtkfilechooser.h	(working copy)
@@ -174,7 +174,7 @@ gboolean gtk_file_chooser_add_shortcut_f
 gboolean gtk_file_chooser_remove_shortcut_folder (GtkFileChooser *chooser,
 						  const char     *folder,
 						  GError        **error);
-GSList *gtk_file_chooser_list_shortcut_folders   (GtkFileChooser *chooser);
+GSList * gtk_file_chooser_list_shortcut_folders  (GtkFileChooser *chooser);
 
 gboolean gtk_file_chooser_add_shortcut_folder_uri    (GtkFileChooser *chooser,
 						      const char     *uri,
@@ -184,6 +184,11 @@ gboolean gtk_file_chooser_remove_shortcu
 						      GError        **error);
 GSList *gtk_file_chooser_list_shortcut_folder_uris   (GtkFileChooser *chooser);
 
+gboolean gtk_file_chooser_add_shortcuts_from_file (GtkFileChooser *chooser,
+                                                   const gchar    *filename,
+                                                   const gchar    *domain,
+                                                   GError        **error);
+
 G_END_DECLS
 
 #endif /* __GTK_FILE_CHOOSER_H__ */
Index: tests/testbookmarks.xbel
===================================================================
--- tests/testbookmarks.xbel	(revision 0)
+++ tests/testbookmarks.xbel	(revision 0)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xbel version="1.0"
+      xmlns:bookmark="http://www.freedesktop.org/standards/desktop-bookmarks"
+      xmlns:mime="http://www.freedesktop.org/standards/shared-mime-info"
+>
+  <bookmark href="file:///usr/share/applications" added="2007-02-20T14:48:56Z" modified="2007-02-20T14:48:56Z" visited="2007-02-20T14:49:55Z">
+    <title>My Applications</title>
+    <info>
+      <metadata owner="http://freedesktop.org">
+        <mime:mime-type type="x-directory/normal"/>
+        <bookmark:applications>
+          <bookmark:application name="lt-testfilechooser" exec="lt-testfilechooser %u" timestamp="1171982936" count="1"/>
+        </bookmark:applications>
+      </metadata>
+    </info>
+  </bookmark>
+  <bookmark href="file:///home/ebassi/Media/Video" added="2007-02-20T14:48:56Z" modified="2007-02-20T14:48:56Z" visited="2007-02-20T14:49:55Z">
+    <title>My Movies</title>
+    <info>
+      <metadata owner="http://freedesktop.org">
+        <mime:mime-type type="x-directory/normal"/>
+        <bookmark:applications>
+          <bookmark:application name="lt-testfilechooser" exec="lt-testfilechooser %u" timestamp="1171982936" count="1"/>
+        </bookmark:applications>
+      </metadata>
+    </info>
+  </bookmark>
+</xbel>
Index: tests/testfilechooser.c
===================================================================
--- tests/testfilechooser.c	(revision 17340)
+++ tests/testfilechooser.c	(working copy)
@@ -601,6 +601,10 @@ main (int argc, char **argv)
   gtk_file_chooser_add_shortcut_folder_uri (GTK_FILE_CHOOSER (dialog),
 					    "file:///usr/share/pixmaps",
 					    NULL);
+  gtk_file_chooser_add_shortcuts_from_file (GTK_FILE_CHOOSER (dialog),
+                                            "testbookmarks.xbel",
+                                            NULL,
+                                            NULL);
 
   /* show_all() to reveal bugs in composite widget handling */
   gtk_widget_show_all (dialog);
