]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilechooserdefault.c
When using gtk_dialog_run() for modal dialogs, make sure to inherit the
[~andy/gtk] / gtk / gtkfilechooserdefault.c
index 21432a6e4fc97000484024f98adae42fbe743caa..786a2519526f10b513f055210f787e54c6d7b6b7 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <config.h>
 #include "gdk/gdkkeysyms.h"
-#include "gtkalias.h"
 #include "gtkalignment.h"
 #include "gtkbindings.h"
 #include "gtkbutton.h"
 #include "gtkfilesystemwin32.h"
 #endif
 
+#include "gtkalias.h"
+
 #include <errno.h>
 #include <string.h>
 #include <time.h>
 
+\f
+
+/* Profiling stuff */
+
+#define PROFILE_FILE_CHOOSER
+#ifdef PROFILE_FILE_CHOOSER
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef G_OS_WIN32
+#include <io.h>
+#endif
+
+#ifndef F_OK 
+#define F_OK 0
+#endif
+
+#define PROFILE_INDENT 4
+static int profile_indent;
+
+static void
+profile_add_indent (int indent)
+{
+  profile_indent += indent;
+  if (profile_indent < 0)
+    g_error ("You screwed up your indentation");
+}
+
+void
+_gtk_file_chooser_profile_log (const char *func, int indent, const char *msg1, const char *msg2)
+{
+  char *str;
+
+  if (indent < 0)
+    profile_add_indent (indent);
+
+  if (profile_indent == 0)
+    str = g_strdup_printf ("MARK: %s %s %s", func, msg1 ? msg1 : "", msg2 ? msg2 : "");
+  else
+    str = g_strdup_printf ("MARK: %*c %s %s %s", profile_indent - 1, ' ', func, msg1 ? msg1 : "", msg2 ? msg2 : "");
+
+  access (str, F_OK);
+  g_free (str);
+
+  if (indent > 0)
+    profile_add_indent (indent);
+}
+
+#define profile_start(x, y) _gtk_file_chooser_profile_log (G_STRFUNC, PROFILE_INDENT, x, y)
+#define profile_end(x, y) _gtk_file_chooser_profile_log (G_STRFUNC, -PROFILE_INDENT, x, y)
+#define profile_msg(x, y) _gtk_file_chooser_profile_log (NULL, 0, x, y)
+#else
+#define profile_start(x, y)
+#define profile_end(x, y)
+#define profile_msg(x, y)
+#endif
+
+\f
+
 typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
 
 #define GTK_FILE_CHOOSER_DEFAULT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
 #define GTK_IS_FILE_CHOOSER_DEFAULT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT))
 #define GTK_FILE_CHOOSER_DEFAULT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
 
+typedef enum {
+  LOAD_EMPTY,                  /* There is no model */
+  LOAD_PRELOAD,                        /* Model is loading and a timer is running; model isn't inserted into the tree yet */
+  LOAD_LOADING,                        /* Timeout expired, model is inserted into the tree, but not fully loaded yet */
+  LOAD_FINISHED                        /* Model is fully loaded and inserted into the tree */
+} LoadState;
+
+#define MAX_LOADING_TIME 500
 
 struct _GtkFileChooserDefaultClass
 {
@@ -104,7 +173,6 @@ struct _GtkFileChooserDefault
   GtkWidget *save_file_name_entry;
   GtkWidget *save_folder_label;
   GtkWidget *save_folder_combo;
-  GtkWidget *save_extra_align;
   GtkWidget *save_expander;
 
   /* The file browsing widgets */
@@ -112,13 +180,15 @@ struct _GtkFileChooserDefault
   GtkWidget *browse_shortcuts_tree_view;
   GtkWidget *browse_shortcuts_add_button;
   GtkWidget *browse_shortcuts_remove_button;
+  GtkWidget *browse_shortcuts_popup_menu;
+  GtkWidget *browse_shortcuts_popup_menu_remove_item;
+  GtkWidget *browse_shortcuts_popup_menu_rename_item;
   GtkWidget *browse_files_tree_view;
   GtkWidget *browse_files_popup_menu;
   GtkWidget *browse_files_popup_menu_add_shortcut_item;
   GtkWidget *browse_files_popup_menu_hidden_files_item;
   GtkWidget *browse_new_folder_button;
   GtkWidget *browse_path_bar;
-  GtkWidget *browse_extra_align;
 
   GtkFileSystemModel *browse_files_model;
 
@@ -127,6 +197,7 @@ struct _GtkFileChooserDefault
   GtkWidget *preview_box;
   GtkWidget *preview_label;
   GtkWidget *preview_widget;
+  GtkWidget *extra_align;
   GtkWidget *extra_widget;
 
   GtkListStore *shortcuts_model;
@@ -134,6 +205,11 @@ struct _GtkFileChooserDefault
 
   GtkTreeModelSort *sort_model;
 
+  LoadState load_state;
+  guint load_timeout_id;
+
+  GSList *pending_select_paths;
+
   GtkFileFilter *current_filter;
   GSList *filters;
 
@@ -178,6 +254,7 @@ struct _GtkFileChooserDefault
   guint use_preview_label : 1;
   guint select_multiple : 1;
   guint show_hidden : 1;
+  guint do_overwrite_confirmation : 1;
   guint list_sort_ascending : 1;
   guint changing_folder : 1;
   guint shortcuts_current_folder_active : 1;
@@ -224,7 +301,7 @@ enum {
 };
 
 /* Target types for dragging from the shortcuts list */
-static GtkTargetEntry shortcuts_source_targets[] = {
+static const GtkTargetEntry shortcuts_source_targets[] = {
   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
 };
 
@@ -232,7 +309,7 @@ static const int num_shortcuts_source_targets = (sizeof (shortcuts_source_target
                                                 / sizeof (shortcuts_source_targets[0]));
 
 /* Target types for dropping into the shortcuts list */
-static GtkTargetEntry shortcuts_dest_targets[] = {
+static const GtkTargetEntry shortcuts_dest_targets[] = {
   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
   { "text/uri-list", 0, TEXT_URI_LIST }
 };
@@ -241,13 +318,22 @@ static const int num_shortcuts_dest_targets = (sizeof (shortcuts_dest_targets)
                                               / sizeof (shortcuts_dest_targets[0]));
 
 /* Target types for DnD from the file list */
-static GtkTargetEntry file_list_source_targets[] = {
+static const GtkTargetEntry file_list_source_targets[] = {
   { "text/uri-list", 0, TEXT_URI_LIST }
 };
 
 static const int num_file_list_source_targets = (sizeof (file_list_source_targets)
                                                 / sizeof (file_list_source_targets[0]));
 
+/* Target types for dropping into the file list */
+static const GtkTargetEntry file_list_dest_targets[] = {
+  { "text/uri-list", 0, TEXT_URI_LIST }
+};
+
+static const int num_file_list_dest_targets = (sizeof (file_list_dest_targets)
+                                              / sizeof (file_list_dest_targets[0]));
+
+
 /* Interesting places in the shortcuts bar */
 typedef enum {
   SHORTCUTS_HOME,
@@ -261,7 +347,7 @@ typedef enum {
 } ShortcutsIndex;
 
 /* Icon size for if we can't get it from the theme */
-#define FALLBACK_ICON_SIZE 20
+#define FALLBACK_ICON_SIZE 16
 
 #define PREVIEW_HBOX_SPACING 12
 #define NUM_LINES 40
@@ -286,6 +372,7 @@ static void     gtk_file_chooser_default_get_property (GObject               *ob
                                                       GParamSpec            *pspec);
 static void     gtk_file_chooser_default_dispose      (GObject               *object);
 static void     gtk_file_chooser_default_show_all       (GtkWidget             *widget);
+static void     gtk_file_chooser_default_map            (GtkWidget             *widget);
 static void     gtk_file_chooser_default_hierarchy_changed (GtkWidget          *widget,
                                                            GtkWidget          *previous_toplevel);
 static void     gtk_file_chooser_default_style_set      (GtkWidget             *widget,
@@ -296,6 +383,10 @@ static void     gtk_file_chooser_default_screen_changed (GtkWidget             *
 static gboolean       gtk_file_chooser_default_set_current_folder         (GtkFileChooser    *chooser,
                                                                            const GtkFilePath *path,
                                                                            GError           **error);
+static gboolean       gtk_file_chooser_default_update_current_folder      (GtkFileChooser    *chooser,
+                                                                           const GtkFilePath *path,
+                                                                           gboolean           keep_trail,
+                                                                           GError           **error);
 static GtkFilePath *  gtk_file_chooser_default_get_current_folder         (GtkFileChooser    *chooser);
 static void           gtk_file_chooser_default_set_current_name           (GtkFileChooser    *chooser,
                                                                            const gchar       *name);
@@ -358,6 +449,8 @@ static gboolean shortcuts_select_func   (GtkTreeSelection      *selection,
                                         GtkTreePath           *path,
                                         gboolean               path_currently_selected,
                                         gpointer               data);
+static gboolean shortcuts_get_selected  (GtkFileChooserDefault *impl,
+                                        GtkTreeIter           *iter);
 static void shortcuts_activate_iter (GtkFileChooserDefault *impl,
                                     GtkTreeIter           *iter);
 static int shortcuts_get_index (GtkFileChooserDefault *impl,
@@ -367,6 +460,12 @@ static int shortcut_find_position (GtkFileChooserDefault *impl,
 
 static void bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl);
 
+static gboolean list_select_func   (GtkTreeSelection      *selection,
+                                   GtkTreeModel          *model,
+                                   GtkTreePath           *path,
+                                   gboolean               path_currently_selected,
+                                   gpointer               data);
+
 static void list_selection_changed     (GtkTreeSelection      *tree_selection,
                                        GtkFileChooserDefault *impl);
 static void list_row_activated         (GtkTreeView           *tree_view,
@@ -374,6 +473,11 @@ static void list_row_activated         (GtkTreeView           *tree_view,
                                        GtkTreeViewColumn     *column,
                                        GtkFileChooserDefault *impl);
 
+static void select_func (GtkFileSystemModel *model,
+                        GtkTreePath        *path,
+                        GtkTreeIter        *iter,
+                        gpointer            user_data);
+
 static void path_bar_clicked           (GtkPathBar            *path_bar,
                                        GtkFilePath           *file_path,
                                        gboolean               child_is_hidden,
@@ -410,6 +514,9 @@ static void list_mtime_data_func (GtkTreeViewColumn *tree_column,
 static const GtkFileInfo *get_list_file_info (GtkFileChooserDefault *impl,
                                              GtkTreeIter           *iter);
 
+static void load_remove_timer (GtkFileChooserDefault *impl);
+static void browse_files_center_selected_row (GtkFileChooserDefault *impl);
+
 static GObjectClass *parent_class;
 
 \f
@@ -507,6 +614,7 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
   gobject_class->dispose = gtk_file_chooser_default_dispose;
 
   widget_class->show_all = gtk_file_chooser_default_show_all;
+  widget_class->map = gtk_file_chooser_default_map;
   widget_class->hierarchy_changed = gtk_file_chooser_default_hierarchy_changed;
   widget_class->style_set = gtk_file_chooser_default_style_set;
   widget_class->screen_changed = gtk_file_chooser_default_screen_changed;
@@ -560,6 +668,10 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                GDK_Up, GDK_MOD1_MASK,
                                "up-folder",
                                0);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_BackSpace, 0,
+                               "up-folder",
+                               0);
   gtk_binding_entry_add_signal (binding_set,
                                GDK_KP_Up, GDK_MOD1_MASK,
                                "up-folder",
@@ -589,7 +701,7 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                                      P_("Default file chooser backend"),
                                                      P_("Name of the GtkFileChooser backend to use by default"),
                                                      NULL,
-                                                     G_PARAM_READWRITE));
+                                                     GTK_PARAM_READWRITE));
 }
 
 static void
@@ -624,19 +736,24 @@ gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface *iface)
 static void
 gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
 {
+  profile_start ("start", NULL);
+
   impl->local_only = TRUE;
   impl->preview_widget_active = TRUE;
   impl->use_preview_label = TRUE;
   impl->select_multiple = FALSE;
   impl->show_hidden = FALSE;
   impl->icon_size = FALLBACK_ICON_SIZE;
+  impl->load_state = LOAD_EMPTY;
+  impl->pending_select_paths = NULL;
 
-  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (impl), TRUE);
   gtk_box_set_spacing (GTK_BOX (impl), 12);
 
   impl->tooltips = gtk_tooltips_new ();
   g_object_ref (impl->tooltips);
   gtk_object_sink (GTK_OBJECT (impl->tooltips));
+
+  profile_end ("end", NULL);
 }
 
 /* Frees the data columns for the specified iter in the shortcuts model*/
@@ -690,6 +807,61 @@ shortcuts_free (GtkFileChooserDefault *impl)
   impl->shortcuts_model = NULL;
 }
 
+static void
+pending_select_paths_free (GtkFileChooserDefault *impl)
+{
+  GSList *l;
+
+  for (l = impl->pending_select_paths; l; l = l->next)
+    {
+      GtkFilePath *path;
+
+      path = l->data;
+      gtk_file_path_free (path);
+    }
+
+  g_slist_free (impl->pending_select_paths);
+  impl->pending_select_paths = NULL;
+}
+
+static void
+pending_select_paths_add (GtkFileChooserDefault *impl,
+                         const GtkFilePath     *path)
+{
+  impl->pending_select_paths = g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path));
+}
+
+/* Used from gtk_tree_selection_selected_foreach() */
+static void
+store_selection_foreach (GtkTreeModel *model,
+                        GtkTreePath  *path,
+                        GtkTreeIter  *iter,
+                        gpointer      data)
+{
+  GtkFileChooserDefault *impl;
+  GtkTreeIter child_iter;
+  const GtkFilePath *file_path;
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
+
+  file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
+  pending_select_paths_add (impl, file_path);
+}
+
+/* Stores the current selection in the list of paths to select; this is used to
+ * preserve the selection when reloading the current folder.
+ */
+static void
+pending_select_paths_store_selection (GtkFileChooserDefault *impl)
+{
+  GtkTreeSelection *selection;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  gtk_tree_selection_selected_foreach (selection, store_selection_foreach, impl);
+}
+
 static void
 gtk_file_chooser_default_finalize (GObject *object)
 {
@@ -728,6 +900,10 @@ gtk_file_chooser_default_finalize (GObject *object)
   if (impl->preview_path)
     gtk_file_path_free (impl->preview_path);
 
+  pending_select_paths_free (impl);
+
+  load_remove_timer (impl);
+
   /* Free all the Models we have */
   if (impl->browse_files_model)
     g_object_unref (impl->browse_files_model);
@@ -747,7 +923,8 @@ gtk_file_chooser_default_finalize (GObject *object)
 /* Shows an error dialog set as transient for the specified window */
 static void
 error_message_with_parent (GtkWindow  *parent,
-                          const char *msg)
+                          const char *msg,
+                          const char *detail)
 {
   GtkWidget *dialog;
 
@@ -757,6 +934,12 @@ error_message_with_parent (GtkWindow  *parent,
                                   GTK_BUTTONS_OK,
                                   "%s",
                                   msg);
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                           "%s", detail);
+
+  if (parent->group)
+    gtk_window_group_add_window (parent->group, GTK_WINDOW (dialog));
+
   gtk_dialog_run (GTK_DIALOG (dialog));
   gtk_widget_destroy (dialog);
 }
@@ -777,9 +960,10 @@ get_toplevel (GtkWidget *widget)
 /* Shows an error dialog for the file chooser */
 static void
 error_message (GtkFileChooserDefault *impl,
-              const char            *msg)
+              const char            *msg,
+              const char            *detail)
 {
-  error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg);
+  error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg, detail);
 }
 
 /* Shows a simple error dialog relative to a path.  Frees the GError as well. */
@@ -789,15 +973,15 @@ error_dialog (GtkFileChooserDefault *impl,
              const GtkFilePath     *path,
              GError                *error)
 {
-  g_return_if_fail (path != NULL);
-
   if (error)
     {
-      char *uri = gtk_file_system_path_to_uri (impl->file_system, path);
-      char *text = g_strdup_printf (msg,
-                                   uri,
-                                   error->message);
-      error_message (impl, text);
+      char *uri = NULL;
+      char *text;
+
+      if (path)
+       uri = gtk_file_system_path_to_uri (impl->file_system, path);
+      text = g_strdup_printf (msg, uri);
+      error_message (impl, text, error->message);
       g_free (text);
       g_free (uri);
       g_error_free (error);
@@ -813,39 +997,67 @@ error_getting_info_dialog (GtkFileChooserDefault *impl,
                           GError                *error)
 {
   error_dialog (impl,
-               _("Could not retrieve information about %s:\n%s"),
+               _("Could not retrieve information about the file"),
                path, error);
 }
 
 /* Shows an error dialog about not being able to add a bookmark */
 static void
-error_could_not_add_bookmark_dialog (GtkFileChooserDefault *impl,
-                                    const GtkFilePath     *path,
-                                    GError                *error)
+error_adding_bookmark_dialog (GtkFileChooserDefault *impl,
+                             const GtkFilePath     *path,
+                             GError                *error)
+{
+  error_dialog (impl,
+               _("Could not add a bookmark"),
+               path, error);
+}
+
+/* Shows an error dialog about not being able to remove a bookmark */
+static void
+error_removing_bookmark_dialog (GtkFileChooserDefault *impl,
+                               const GtkFilePath     *path,
+                               GError                *error)
+{
+  error_dialog (impl,
+               _("Could not remove bookmark"),
+               path, error);
+}
+
+/* Shows an error dialog about not being able to create a folder */
+static void
+error_creating_folder_dialog (GtkFileChooserDefault *impl,
+                             const GtkFilePath     *path,
+                             GError                *error)
+{
+  error_dialog (impl, 
+               _("The folder could not be created"), 
+               path, error);
+}
+
+/* Shows an error about not being able to create a folder because a file with
+ * the same name is already there.
+ */
+static void
+error_creating_folder_over_existing_file_dialog (GtkFileChooserDefault *impl,
+                                                const GtkFilePath     *path,
+                                                GError                *error)
 {
   error_dialog (impl,
-               _("Could not add a bookmark for %s:\n%s"),
+               _("The folder could not be created, as a file with the same name "
+                 "already exists.  Try using a different name for the folder, "
+                 "or rename the file first."),
                path, error);
 }
 
-/* Shows an error dialog about not being able to compose a filename */
+/* Shows an error dialog about not being able to create a filename */
 static void
 error_building_filename_dialog (GtkFileChooserDefault *impl,
-                               const GtkFilePath     *base_path,
+                               const GtkFilePath     *folder_part,
                                const char            *file_part,
                                GError                *error)
 {
-  char *uri;
-  char *msg;
-
-  uri = gtk_file_system_path_to_uri (impl->file_system, base_path);
-  msg = g_strdup_printf (_("Could not build file name from '%s' and '%s':\n%s"),
-                        uri, file_part,
-                        error->message);
-  error_message (impl, msg);
-  g_free (uri);
-  g_free (msg);
-  g_error_free (error);
+  error_dialog (impl, _("Invalid file name"), 
+               NULL, error);
 }
 
 /* Shows an error dialog when we cannot switch to a folder */
@@ -854,10 +1066,8 @@ error_changing_folder_dialog (GtkFileChooserDefault *impl,
                              const GtkFilePath     *path,
                              GError                *error)
 {
-  error_dialog (impl,
-               _("Could not change the current folder to %s:\n%s"),
-               path,
-               error);
+  error_dialog (impl, _("The folder contents could not be displayed"),
+               path, error);
 }
 
 /* Changes folders, displaying an error dialog if this fails */
@@ -869,6 +1079,10 @@ change_folder_and_display_error (GtkFileChooserDefault *impl,
   gboolean result;
   GtkFilePath *path_copy;
 
+  g_return_val_if_fail (path != NULL, FALSE);
+
+  profile_start ("start", (char *) path);
+
   /* We copy the path because of this case:
    *
    * list_row_activated()
@@ -881,13 +1095,15 @@ change_folder_and_display_error (GtkFileChooserDefault *impl,
   path_copy = gtk_file_path_copy (path);
 
   error = NULL;
-  result = _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), path_copy, &error);
+  result = gtk_file_chooser_default_update_current_folder (GTK_FILE_CHOOSER (impl), path_copy, TRUE, &error);
 
   if (!result)
     error_changing_folder_dialog (impl, path_copy, error);
 
   gtk_file_path_free (path_copy);
 
+  profile_end ("end", (char *) path);
+
   return result;
 }
 
@@ -901,6 +1117,7 @@ update_preview_widget_visibility (GtkFileChooserDefault *impl)
          impl->preview_label = gtk_label_new (impl->preview_display_name);
          gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_label, FALSE, FALSE, 0);
          gtk_box_reorder_child (GTK_BOX (impl->preview_box), impl->preview_label, 0);
+         gtk_label_set_ellipsize (GTK_LABEL (impl->preview_label), PANGO_ELLIPSIZE_MIDDLE);
          gtk_widget_show (impl->preview_label);
        }
     }
@@ -951,8 +1168,10 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl)
 {
   GtkTreeIter iter;
 
+  profile_start ("start", NULL);
+
   if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
-    return;
+    goto out;
 
   do {
     gpointer data;
@@ -992,11 +1211,15 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl)
          g_object_unref (pixbuf);
       }
   } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
+
+ out:
+
+  profile_end ("end", NULL);
 }
 
-/* If a shortcut corresponds to the current folder, selects it */
-static void
-shortcuts_find_current_folder (GtkFileChooserDefault *impl)
+static void 
+shortcuts_find_folder (GtkFileChooserDefault *impl,
+                      GtkFilePath           *folder)
 {
   GtkTreeSelection *selection;
   int pos;
@@ -1004,7 +1227,8 @@ shortcuts_find_current_folder (GtkFileChooserDefault *impl)
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
 
-  pos = shortcut_find_position (impl, impl->current_folder);
+  g_assert (folder != NULL);
+  pos = shortcut_find_position (impl, folder);
   if (pos == -1)
     {
       gtk_tree_selection_unselect_all (selection);
@@ -1016,65 +1240,84 @@ shortcuts_find_current_folder (GtkFileChooserDefault *impl)
   gtk_tree_path_free (path);
 }
 
+/* If a shortcut corresponds to the current folder, selects it */
+static void
+shortcuts_find_current_folder (GtkFileChooserDefault *impl)
+{
+  shortcuts_find_folder (impl, impl->current_folder);
+}
+
 /* Convenience function to get the display name and icon info for a path */
 static GtkFileInfo *
-get_file_info (GtkFileSystem *file_system, const GtkFilePath *path, gboolean name_only, GError **error)
+get_file_info (GtkFileSystem      *file_system, 
+              const GtkFilePath  *path, 
+              gboolean            name_only, 
+              GError            **error)
 {
   GtkFilePath *parent_path;
   GtkFileFolder *parent_folder;
   GtkFileInfo *info;
+  GError *tmp = NULL;
+
+  profile_start ("start", (char *) path);
 
+  parent_path = NULL;
   info = NULL;
 
-  if (!gtk_file_system_get_parent (file_system, path, &parent_path, error))
-    return NULL;
+  if (!gtk_file_system_get_parent (file_system, path, &parent_path, &tmp))
+    goto out;
 
   parent_folder = gtk_file_system_get_folder (file_system, parent_path ? parent_path : path,
                                              GTK_FILE_INFO_DISPLAY_NAME
                                              | (name_only ? 0 : GTK_FILE_INFO_IS_FOLDER),
-                                             error);
+                                             &tmp);
   if (!parent_folder)
     goto out;
 
-  info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, error);
+  info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, &tmp);
   g_object_unref (parent_folder);
 
  out:
+  if (parent_path)
+    gtk_file_path_free (parent_path);
+
+  if (tmp)
+    {
+      g_set_error (error,
+                  GTK_FILE_CHOOSER_ERROR,
+                  GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+                  _("Could not get information about '%s': %s"), 
+                  gtk_file_path_get_string (path),
+                  tmp->message);
+      g_error_free (tmp);
+    }
+
+  profile_end ("end", (char *) path);
 
-  gtk_file_path_free (parent_path);
   return info;
 }
 
 /* Returns whether a path is a folder */
 static gboolean
-check_is_folder (GtkFileSystem *file_system, const GtkFilePath *path, GError **error)
+check_is_folder (GtkFileSystem      *file_system, 
+                const GtkFilePath  *path, 
+                GError            **error)
 {
-  GtkFileInfo *info;
-  gboolean is_folder;
+  GtkFileFolder *folder;
 
-  /* Use get_file_info() rather than trying get_folder() and checking
-   * for an error directly because older versions of the gnome-vfs
-   * backend don't return an error immediately. This way is also
-   * more efficient if we already have the parent folder. 
-   */
-  info = get_file_info (file_system, path, FALSE, error);
-  
-  if (!info)
-    return FALSE;
-  
-  is_folder = gtk_file_info_get_is_folder (info);
+  profile_start ("start", (char *) path);
 
-  if (!is_folder)
-    g_set_error (error,
-                GTK_FILE_SYSTEM_ERROR,
-                GTK_FILE_SYSTEM_ERROR_NOT_FOLDER,
-                "%s: %s", 
-                gtk_file_info_get_display_name (info),
-                g_strerror (ENOTDIR));
+  folder = gtk_file_system_get_folder (file_system, path, 0, error);
+  if (!folder)
+    {
+      profile_end ("end - is not folder", (char *) path);
+      return FALSE;
+    }
 
-  gtk_file_info_free (info);
+  g_object_unref (folder);
 
-  return is_folder;
+  profile_end ("end", (char *) path);
+  return TRUE;
 }
 
 /* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
@@ -1095,6 +1338,8 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
   gpointer data;
   GtkTreeIter iter;
 
+  profile_start ("start", is_volume ? "volume" : (char *) path);
+
   if (is_volume)
     {
       data = volume;
@@ -1105,7 +1350,10 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
   else
     {
       if (!check_is_folder (impl->file_system, path, error))
-       return FALSE;
+       {
+         profile_end ("end - is not folder", NULL);
+         return FALSE;
+       }
 
       if (label)
        label_copy = g_strdup (label);
@@ -1114,7 +1362,10 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
          GtkFileInfo *info = get_file_info (impl->file_system, path, TRUE, error);
 
          if (!info)
-           return FALSE;
+           {
+             profile_end ("end - could not get info", (char *) path);
+             return FALSE;
+           }
 
          label_copy = g_strdup (gtk_file_info_get_display_name (info));
          gtk_file_info_free (info);
@@ -1144,6 +1395,8 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
   if (pixbuf)
     g_object_unref (pixbuf);
 
+  profile_end ("end", NULL);
+
   return TRUE;
 }
 
@@ -1155,9 +1408,14 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
   GtkFilePath *home_path;
   GError *error;
 
+  profile_start ("start", NULL);
+
   home = g_get_home_dir ();
   if (home == NULL)
-    return;
+    {
+      profile_end ("end - no home directory!?", NULL);
+      return;
+    }
 
   home_path = gtk_file_system_filename_to_path (impl->file_system, home);
 
@@ -1167,21 +1425,32 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
     error_getting_info_dialog (impl, home_path, error);
 
   gtk_file_path_free (home_path);
+
+  profile_end ("end", NULL);
 }
 
 /* Appends the ~/Desktop directory to the shortcuts model */
 static void
 shortcuts_append_desktop (GtkFileChooserDefault *impl)
 {
-  const char *home;
   char *name;
   GtkFilePath *path;
 
-  home = g_get_home_dir ();
+  profile_start ("start", NULL);
+
+#ifdef G_OS_WIN32
+  name = _gtk_file_system_win32_get_desktop ();
+#else
+  const char *home = g_get_home_dir ();
   if (home == NULL)
-    return;
+    {
+      profile_end ("end - no home directory!?", NULL);
+      return;
+    }
 
   name = g_build_filename (home, "Desktop", NULL);
+#endif
+
   path = gtk_file_system_filename_to_path (impl->file_system, name);
   g_free (name);
 
@@ -1191,6 +1460,8 @@ shortcuts_append_desktop (GtkFileChooserDefault *impl)
    */
 
   gtk_file_path_free (path);
+
+  profile_end ("end", NULL);
 }
 
 /* Appends a list of GtkFilePath to the shortcuts model; returns how many were inserted */
@@ -1200,6 +1471,9 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
 {
   int start_row;
   int num_inserted;
+  gchar *label;
+
+  profile_start ("start", NULL);
 
   /* As there is no separator now, we want to start there.
    */
@@ -1218,11 +1492,17 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
          !gtk_file_system_path_is_local (impl->file_system, path))
        continue;
 
+      label = gtk_file_system_get_bookmark_label (impl->file_system, path);
+
       /* NULL GError, but we don't really want to show error boxes here */
-      if (shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, NULL, TRUE, NULL))
+      if (shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, NULL))
        num_inserted++;
+
+      g_free (label);
     }
 
+  profile_end ("end", NULL);
+
   return num_inserted;
 }
 
@@ -1314,6 +1594,8 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
   int n;
   gboolean old_changing_folders;
 
+  profile_start ("start", NULL);
+
   old_changing_folders = impl->changing_folder;
   impl->changing_folder = TRUE;
 
@@ -1357,6 +1639,8 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
 
   impl->changing_folder = old_changing_folders;
+
+  profile_end ("end", NULL);
 }
 
 /* Inserts a separator node in the shortcuts list */
@@ -1384,10 +1668,43 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
 {
   GSList *bookmarks;
   gboolean old_changing_folders;
+  GtkTreeIter iter;
+  GtkFilePath *list_selected = NULL;
+  GtkFilePath *combo_selected = NULL;
+  gboolean is_volume;
+  gpointer col_data;
 
+  profile_start ("start", NULL);
+        
   old_changing_folders = impl->changing_folder;
   impl->changing_folder = TRUE;
 
+  if (shortcuts_get_selected (impl, &iter))
+    {
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), 
+                         &iter, 
+                         SHORTCUTS_COL_DATA, &col_data,
+                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         -1);
+
+      if (col_data && !is_volume)
+       list_selected = gtk_file_path_copy (col_data);
+    }
+
+  if (impl->save_folder_combo &&
+      gtk_combo_box_get_active_iter (GTK_COMBO_BOX (impl->save_folder_combo), 
+                                    &iter))
+    {
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), 
+                         &iter, 
+                         SHORTCUTS_COL_DATA, &col_data,
+                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         -1);
+      
+      if (col_data && !is_volume)
+       combo_selected = gtk_file_path_copy (col_data);
+    }
+
   if (impl->num_bookmarks > 0)
     shortcuts_remove_rows (impl,
                           shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
@@ -1398,13 +1715,31 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
   gtk_file_paths_free (bookmarks);
 
   if (impl->num_bookmarks > 0)
-    {
-      shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
-    }
+    shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
+
   if (impl->shortcuts_filter_model)
     gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
 
+  if (list_selected)
+    {
+      shortcuts_find_folder (impl, list_selected);
+      gtk_file_path_free (list_selected);
+    }
+
+  if (combo_selected)
+    {
+      gint pos;
+
+      pos = shortcut_find_position (impl, combo_selected);
+      if (pos != -1)
+       gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), 
+                                 pos);
+      gtk_file_path_free (combo_selected);
+    }
+  
   impl->changing_folder = old_changing_folders;
+
+  profile_end ("end", NULL);
 }
 
 /* Appends a separator and a row to the shortcuts list for the current folder */
@@ -1418,6 +1753,8 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
 
   success = TRUE;
 
+  g_assert (impl->current_folder != NULL);
+
   pos = shortcut_find_position (impl, impl->current_folder);
   if (pos == -1)
     {
@@ -1545,6 +1882,9 @@ new_folder_button_clicked (GtkButton             *button,
   if (!impl->browse_files_model)
     return; /* FIXME: this sucks.  Disable the New Folder button or something. */
 
+  /* Prevent button from being clicked twice */
+  gtk_widget_set_sensitive (impl->browse_new_folder_button, FALSE);
+
   _gtk_file_system_model_add_editable (impl->browse_files_model, &iter);
 
   path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter);
@@ -1567,12 +1907,16 @@ new_folder_button_clicked (GtkButton             *button,
 static gboolean
 edited_idle_cb (GtkFileChooserDefault *impl)
 {
+  GDK_THREADS_ENTER ();
+  
   g_source_destroy (impl->edited_idle);
   impl->edited_idle = NULL;
 
   _gtk_file_system_model_remove_editable (impl->browse_files_model);
   g_object_set (impl->list_name_renderer, "editable", FALSE, NULL);
 
+  gtk_widget_set_sensitive (impl->browse_new_folder_button, TRUE);
+
   if (impl->edited_new_text) /* not cancelled? */
     {
       GError *error;
@@ -1587,19 +1931,19 @@ edited_idle_cb (GtkFileChooserDefault *impl)
          if (gtk_file_system_create_folder (impl->file_system, file_path, &error))
            change_folder_and_display_error (impl, file_path);
          else
-           error_dialog (impl,
-                         _("Could not create folder %s:\n%s"),
-                         file_path, error);
+           error_creating_folder_dialog (impl, file_path, error);
 
          gtk_file_path_free (file_path);
        }
       else
-       error_building_filename_dialog (impl, impl->current_folder, impl->edited_new_text, error);
+       error_creating_folder_dialog (impl, file_path, error);
 
       g_free (impl->edited_new_text);
       impl->edited_new_text = NULL;
     }
 
+  GDK_THREADS_LEAVE ();
+
   return FALSE;
 }
 
@@ -1655,6 +1999,8 @@ static GtkWidget *
 filter_create (GtkFileChooserDefault *impl)
 {
   impl->filter_combo = gtk_combo_box_new_text ();
+  gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
+
   g_signal_connect (impl->filter_combo, "changed",
                    G_CALLBACK (filter_combo_changed), impl);
 
@@ -1670,29 +2016,15 @@ button_new (GtkFileChooserDefault *impl,
            GCallback   callback)
 {
   GtkWidget *button;
-  GtkWidget *hbox;
-  GtkWidget *widget;
-  GtkWidget *align;
+  GtkWidget *image;
 
-  button = gtk_button_new ();
-  hbox = gtk_hbox_new (FALSE, 2);
-  align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
-
-  gtk_container_add (GTK_CONTAINER (button), align);
-  gtk_container_add (GTK_CONTAINER (align), hbox);
-  widget = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
-
-  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
-
-  widget = gtk_label_new_with_mnemonic (text);
-  gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (button));
-  gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+  button = gtk_button_new_with_mnemonic (text);
+  image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+  gtk_button_set_image (GTK_BUTTON (button), image);
 
   gtk_widget_set_sensitive (button, sensitive);
   g_signal_connect (button, "clicked", callback, impl);
 
-  gtk_widget_show_all (align);
-
   if (show)
     gtk_widget_show (button);
 
@@ -1734,8 +2066,8 @@ shortcut_find_position (GtkFileChooserDefault *impl,
              volume = col_data;
              base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
 
-             exists = strcmp (gtk_file_path_get_string (path),
-                              gtk_file_path_get_string (base_path)) == 0;
+             exists = base_path && strcmp (gtk_file_path_get_string (path),
+                                           gtk_file_path_get_string (base_path)) == 0;
              g_free (base_path);
 
              if (exists)
@@ -1766,6 +2098,8 @@ shortcuts_add_bookmark_from_path (GtkFileChooserDefault *impl,
 {
   GError *error;
 
+  g_return_val_if_fail (path != NULL, FALSE);
   if (shortcut_find_position (impl, path) != -1)
     return FALSE;
 
@@ -1773,17 +2107,14 @@ shortcuts_add_bookmark_from_path (GtkFileChooserDefault *impl,
   error = NULL;
   if (!check_is_folder (impl->file_system, path, &error))
     {
-      error_dialog (impl,
-                   _("Could not add bookmark for %s because it is not a folder."),
-                   path,
-                   error);
+      error_adding_bookmark_dialog (impl, path, error);
       return FALSE;
     }
 
   error = NULL;
   if (!gtk_file_system_insert_bookmark (impl->file_system, path, pos, &error))
     {
-      error_could_not_add_bookmark_dialog (impl, path, error);
+      error_adding_bookmark_dialog (impl, path, error);
       return FALSE;
     }
 
@@ -1844,6 +2175,9 @@ shortcuts_get_selected (GtkFileChooserDefault *impl,
   GtkTreeSelection *selection;
   GtkTreeIter parent_iter;
 
+  if (!impl->browse_shortcuts_tree_view)
+    return FALSE;
+
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
 
   if (!gtk_tree_selection_get_selected (selection, NULL, &parent_iter))
@@ -1861,7 +2195,6 @@ remove_selected_bookmarks (GtkFileChooserDefault *impl)
 {
   GtkTreeIter iter;
   gpointer col_data;
-  gboolean is_volume;
   GtkFilePath *path;
   gboolean removable;
   GError *error;
@@ -1871,11 +2204,9 @@ remove_selected_bookmarks (GtkFileChooserDefault *impl)
 
   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
                      SHORTCUTS_COL_DATA, &col_data,
-                     SHORTCUTS_COL_IS_VOLUME, &is_volume,
                      SHORTCUTS_COL_REMOVABLE, &removable,
                      -1);
   g_assert (col_data != NULL);
-  g_assert (!is_volume);
 
   if (!removable)
     return;
@@ -1884,12 +2215,7 @@ remove_selected_bookmarks (GtkFileChooserDefault *impl)
 
   error = NULL;
   if (!gtk_file_system_remove_bookmark (impl->file_system, path, &error))
-    {
-      error_dialog (impl,
-                   _("Could not remove bookmark for %s:\n%s"),
-                   path,
-                   error);
-    }
+    error_removing_bookmark_dialog (impl, path, error);
 }
 
 /* Callback used when the "Remove bookmark" button is clicked */
@@ -1925,7 +2251,7 @@ selection_check_foreach_cb (GtkTreeModel *model,
   gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
 
   info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
-  is_folder = gtk_file_info_get_is_folder (info);
+  is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE;
 
   closure->all_folders = closure->all_folders && is_folder;
   closure->all_files = closure->all_files && !is_folder;
@@ -2044,7 +2370,7 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
   selection_check (impl, &num_selected, NULL, &all_folders);
 
   if (num_selected == 0)
-    active = (shortcut_find_position (impl, impl->current_folder) == -1);
+    active = (impl->current_folder != NULL) && (shortcut_find_position (impl, impl->current_folder) == -1);
   else if (num_selected == 1)
     {
       const GtkFilePath *path;
@@ -2115,16 +2441,34 @@ bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
   g_free (name);
 }
 
-/* GtkWidget::drag-begin handler for the shortcuts list. */
 static void
-shortcuts_drag_begin_cb (GtkWidget             *widget,
-                        GdkDragContext        *context,
-                        GtkFileChooserDefault *impl)
+shortcuts_check_popup_sensitivity (GtkFileChooserDefault *impl)
 {
-#if 0
-  impl->shortcuts_drag_context = g_object_ref (context);
-#endif
-}
+  GtkTreeIter iter;
+  gboolean removable = FALSE;
+
+  if (impl->browse_shortcuts_popup_menu == NULL)
+    return;
+
+  if (shortcuts_get_selected (impl, &iter))
+    gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+                       SHORTCUTS_COL_REMOVABLE, &removable,
+                       -1);
+
+  gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_remove_item, removable);
+  gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_rename_item, removable);
+}
+
+/* GtkWidget::drag-begin handler for the shortcuts list. */
+static void
+shortcuts_drag_begin_cb (GtkWidget             *widget,
+                        GdkDragContext        *context,
+                        GtkFileChooserDefault *impl)
+{
+#if 0
+  impl->shortcuts_drag_context = g_object_ref (context);
+#endif
+}
 
 #if 0
 /* Removes the idle handler for outside drags */
@@ -2315,10 +2659,15 @@ shortcuts_drag_set_delete_cursor (GtkFileChooserDefault *impl,
 static gboolean
 shortcuts_drag_outside_idle_cb (GtkFileChooserDefault *impl)
 {
+  GDK_THREADS_ENTER ();
+  
   shortcuts_drag_set_delete_cursor (impl, TRUE);
   impl->shortcuts_drag_outside = TRUE;
 
   shortcuts_cancel_drag_outside_idle (impl);
+
+  GDK_THREADS_LEAVE ();
+
   return FALSE;
 }
 #endif
@@ -2509,12 +2858,15 @@ shortcuts_drop_uris (GtkFileChooserDefault *impl,
        }
       else
        {
-         char *msg;
+         GError *error;
 
-         msg = g_strdup_printf (_("Could not add a bookmark for %s because it is an invalid path name."),
-                                uri);
-         error_message (impl, msg);
-         g_free (msg);
+         g_set_error (&error,
+                      GTK_FILE_CHOOSER_ERROR,
+                      GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+                      _("Could not add a bookmark for '%s' "
+                        "because it is an invalid path name."),
+                      uri);
+         error_adding_bookmark_dialog (impl, path, error);
        }
     }
 
@@ -2571,7 +2923,7 @@ shortcuts_reorder (GtkFileChooserDefault *impl,
   if (gtk_file_system_remove_bookmark (impl->file_system, file_path_copy, &error))
     shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
   else
-    error_could_not_add_bookmark_dialog (impl, file_path_copy, error);
+    error_adding_bookmark_dialog (impl, file_path_copy, error);
 
  out:
 
@@ -2627,6 +2979,7 @@ shortcuts_selection_changed_cb (GtkTreeSelection      *selection,
                                GtkFileChooserDefault *impl)
 {
   bookmarks_check_remove_sensitivity (impl);
+  shortcuts_check_popup_sensitivity (impl);
 }
 
 static gboolean
@@ -2665,6 +3018,170 @@ tree_view_keybinding_cb (GtkWidget             *tree_view,
   return FALSE;
 }
 
+/* Callback used when the file list's popup menu is detached */
+static void
+shortcuts_popup_menu_detach_cb (GtkWidget *attach_widget,
+                               GtkMenu   *menu)
+{
+  GtkFileChooserDefault *impl;
+  
+  impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
+  g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
+
+  impl->browse_shortcuts_popup_menu = NULL;
+  impl->browse_shortcuts_popup_menu_remove_item = NULL;
+  impl->browse_shortcuts_popup_menu_rename_item = NULL;
+}
+
+static void
+remove_shortcut_cb (GtkMenuItem           *item,
+                   GtkFileChooserDefault *impl)
+{
+  remove_selected_bookmarks (impl);
+}
+
+static void
+rename_shortcut_cb (GtkMenuItem           *item,
+                   GtkFileChooserDefault *impl)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *cell;
+  GList *renderers;
+
+  if (shortcuts_get_selected (impl, &iter))
+    {
+      path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+      column = gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), 0);
+      renderers = gtk_tree_view_column_get_cell_renderers (column);
+      cell = g_list_nth_data (renderers, 1);
+      g_list_free (renderers);
+      g_object_set (cell, "editable", TRUE, NULL);
+      gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
+                                       path, column, cell, TRUE);
+      gtk_tree_path_free (path);
+    }
+}
+
+/* Constructs the popup menu for the file list if needed */
+static void
+shortcuts_build_popup_menu (GtkFileChooserDefault *impl)
+{
+  GtkWidget *item;
+
+  if (impl->browse_shortcuts_popup_menu)
+    return;
+
+  impl->browse_shortcuts_popup_menu = gtk_menu_new ();
+  gtk_menu_attach_to_widget (GTK_MENU (impl->browse_shortcuts_popup_menu),
+                            impl->browse_shortcuts_tree_view,
+                            shortcuts_popup_menu_detach_cb);
+
+  item = gtk_image_menu_item_new_with_label (_("Remove"));
+  impl->browse_shortcuts_popup_menu_remove_item = item;
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+                                gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
+  g_signal_connect (item, "activate",
+                   G_CALLBACK (remove_shortcut_cb), impl);
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
+
+  item = gtk_menu_item_new_with_label (_("Rename..."));
+  impl->browse_shortcuts_popup_menu_rename_item = item;
+  g_signal_connect (item, "activate",
+                   G_CALLBACK (rename_shortcut_cb), impl);
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
+
+  shortcuts_check_popup_sensitivity (impl);
+}
+
+static void
+shortcuts_update_popup_menu (GtkFileChooserDefault *impl)
+{
+  shortcuts_build_popup_menu (impl);  
+}
+
+static void
+popup_position_func (GtkMenu   *menu,
+                     gint      *x,
+                     gint      *y,
+                     gboolean  *push_in,
+                     gpointer  user_data);
+
+static void
+shortcuts_popup_menu (GtkFileChooserDefault *impl,
+                     GdkEventButton        *event)
+{
+  shortcuts_update_popup_menu (impl);
+  if (event)
+    gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
+                   NULL, NULL, NULL, NULL,
+                   event->button, event->time);
+  else
+    {
+      gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
+                     NULL, NULL,
+                     popup_position_func, impl->browse_shortcuts_tree_view,
+                     0, GDK_CURRENT_TIME);
+      gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu),
+                                  FALSE);
+    }
+}
+
+/* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
+static gboolean
+shortcuts_popup_menu_cb (GtkWidget *widget,
+                        GtkFileChooserDefault *impl)
+{
+  shortcuts_popup_menu (impl, NULL);
+  return TRUE;
+}
+
+/* Callback used when a button is pressed on the shortcuts list.  
+ * We trap button 3 to bring up a popup menu.
+ */
+static gboolean
+shortcuts_button_press_event_cb (GtkWidget             *widget,
+                                GdkEventButton        *event,
+                                GtkFileChooserDefault *impl)
+{
+  if (event->button != 3)
+    return FALSE;
+
+  shortcuts_popup_menu (impl, event);
+  return TRUE;
+}
+
+static void
+shortcuts_edited (GtkCellRenderer       *cell,
+                 gchar                 *path_string,
+                 gchar                 *new_text,
+                 GtkFileChooserDefault *impl)
+{
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GtkFilePath *shortcut;
+
+  g_object_set (cell, "editable", FALSE, NULL);
+
+  path = gtk_tree_path_new_from_string (path_string);
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path);
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+                     SHORTCUTS_COL_DATA, &shortcut,
+                     -1);
+  gtk_tree_path_free (path);
+  
+  gtk_file_system_set_bookmark_label (impl->file_system, shortcut, new_text);
+}
+
+static void
+shortcuts_editing_canceled (GtkCellRenderer       *cell,
+                           GtkFileChooserDefault *impl)
+{
+  g_object_set (cell, "editable", FALSE, NULL);
+}
 
 /* Creates the widgets for the shortcuts and bookmarks tree */
 static GtkWidget *
@@ -2689,6 +3206,10 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
   impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
   g_signal_connect (impl->browse_shortcuts_tree_view, "key-press-event",
                    G_CALLBACK (tree_view_keybinding_cb), impl);
+  g_signal_connect (impl->browse_shortcuts_tree_view, "popup-menu",
+                   G_CALLBACK (shortcuts_popup_menu_cb), impl);
+  g_signal_connect (impl->browse_shortcuts_tree_view, "button-press-event",
+                   G_CALLBACK (shortcuts_button_press_event_cb), impl);
   atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Shortcuts"));
   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), FALSE);
 
@@ -2753,6 +3274,10 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
                                       NULL);
 
   renderer = gtk_cell_renderer_text_new ();
+  g_signal_connect (renderer, "edited", 
+                   G_CALLBACK (shortcuts_edited), impl);
+  g_signal_connect (renderer, "editing-canceled", 
+                   G_CALLBACK (shortcuts_editing_canceled), impl);
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_attributes (column, renderer,
                                       "text", SHORTCUTS_COL_NAME,
@@ -2802,7 +3327,7 @@ shortcuts_pane_create (GtkFileChooserDefault *impl,
                                                  G_CALLBACK (add_bookmark_button_clicked_cb));
   gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_add_button, TRUE, TRUE, 0);
   gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_add_button,
-                        _("Add the selected folder to the bookmarks"), NULL);
+                        _("Add the selected folder to the Bookmarks"), NULL);
 
   /* Remove bookmark button */
 
@@ -2829,20 +3354,26 @@ trap_activate_cb (GtkWidget   *widget,
                  gpointer     data)
 {
   GtkFileChooserDefault *impl;
+  int modifiers;
 
   impl = (GtkFileChooserDefault *) data;
+
+  modifiers = gtk_accelerator_get_default_mod_mask ();
   
   if (event->keyval == GDK_slash &&
-      ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+      ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
     {
       location_popup_handler (impl, "/");
       return TRUE;
     }
 
-  if (event->keyval == GDK_Return
-      || event->keyval == GDK_ISO_Enter
-      || event->keyval == GDK_KP_Enter
-      || event->keyval == GDK_space)
+  if ((event->keyval == GDK_Return
+       || event->keyval == GDK_ISO_Enter
+       || event->keyval == GDK_KP_Enter
+       || event->keyval == GDK_space)
+      && ((event->state && modifiers) == 0)
+      && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+          impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
     {
       GtkWindow *window;
 
@@ -2875,7 +3406,7 @@ popup_menu_detach_cb (GtkWidget *attach_widget,
   impl->browse_files_popup_menu_hidden_files_item = NULL;
 }
 
-/* Callback used when the "Add to Shortcuts" menu item is activated */
+/* Callback used when the "Add to Bookmarks" menu item is activated */
 static void
 add_to_shortcuts_cb (GtkMenuItem           *item,
                     GtkFileChooserDefault *impl)
@@ -2883,6 +3414,14 @@ add_to_shortcuts_cb (GtkMenuItem           *item,
   bookmarks_add_selected_folder (impl);
 }
 
+/* Callback used when the "Open Location" menu item is activated */
+static void
+open_location_cb (GtkMenuItem           *item,
+                 GtkFileChooserDefault *impl)
+{
+  location_popup_handler (impl, "");
+}
+
 /* Callback used when the "Show Hidden Files" menu item is toggled */
 static void
 show_hidden_toggled_cb (GtkCheckMenuItem      *item,
@@ -2893,6 +3432,127 @@ show_hidden_toggled_cb (GtkCheckMenuItem      *item,
                NULL);
 }
 
+/* Shows an error dialog about not being able to select a dragged file */
+static void
+error_selecting_dragged_file_dialog (GtkFileChooserDefault *impl,
+                                    const GtkFilePath     *path,
+                                    GError                *error)
+{
+  error_dialog (impl,
+               _("Could not select file"),
+               path, error);
+}
+
+static void
+file_list_drag_data_received_cb (GtkWidget          *widget,
+                                GdkDragContext     *context,
+                                gint                x,
+                                gint                y,
+                                GtkSelectionData   *selection_data,
+                                guint               info,
+                                guint               time_,
+                                gpointer            data)
+{
+  GtkFileChooserDefault *impl;
+  GtkFileChooser *chooser;
+  gchar **uris;
+  char *uri;
+  GtkFilePath *path;
+  GError *error = NULL;
+  gint i;
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
+  chooser = GTK_FILE_CHOOSER (data);
+  
+  /* Parse the text/uri-list string, navigate to the first one */
+  uris = g_uri_list_extract_uris (selection_data->data);
+  if (uris[0]) 
+    {
+      uri = uris[0];
+      path = gtk_file_system_uri_to_path (impl->file_system, uri);
+      
+      if (path)
+       {
+         if ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+              impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
+             uris[1] == 0 &&
+             check_is_folder (impl->file_system, path, NULL))
+           change_folder_and_display_error (impl, path);
+          else
+            {
+              gtk_file_chooser_default_unselect_all (chooser);
+              gtk_file_chooser_default_select_path (chooser, path, &error);
+              if (error)
+               error_selecting_dragged_file_dialog (impl, path, error);
+             else
+               browse_files_center_selected_row (impl);
+            }
+
+         gtk_file_path_free (path);
+       }
+      else
+       {
+         g_set_error (&error,
+                      GTK_FILE_CHOOSER_ERROR,
+                      GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+                      _("Could not select file '%s' "
+                        "because it is an invalid path name."),
+                      uri);
+         error_selecting_dragged_file_dialog (impl, NULL, error);
+       }
+
+      
+      if (impl->select_multiple)
+       {
+         for (i = 1; uris[i]; i++)
+           {
+             uri = uris[i];
+             path = gtk_file_system_uri_to_path (impl->file_system, uri);
+             
+             if (path)
+               {
+                 gtk_file_chooser_default_select_path (chooser, path, &error);
+                 if (error)
+                   error_selecting_dragged_file_dialog (impl, path, error);
+
+                 gtk_file_path_free (path);
+               }
+           }
+       }
+    }
+
+  g_strfreev (uris);
+
+  g_signal_stop_emission_by_name (widget, "drag-data-received");
+}
+
+/* Don't do anything with the drag_drop signal */
+static gboolean
+file_list_drag_drop_cb (GtkWidget             *widget,
+                       GdkDragContext        *context,
+                       gint                   x,
+                       gint                   y,
+                       guint                  time_,
+                       GtkFileChooserDefault *impl)
+{
+  g_signal_stop_emission_by_name (widget, "drag-drop");
+  return TRUE;
+}
+
+/* Disable the normal tree drag motion handler, it makes it look like you're
+   dropping the dragged item onto a tree item */
+static gboolean
+file_list_drag_motion_cb (GtkWidget             *widget,
+                          GdkDragContext        *context,
+                          gint                   x,
+                          gint                   y,
+                          guint                  time_,
+                          GtkFileChooserDefault *impl)
+{
+  g_signal_stop_emission_by_name (widget, "drag-motion");
+  return TRUE;
+}
+
 /* Constructs the popup menu for the file list if needed */
 static void
 file_list_build_popup_menu (GtkFileChooserDefault *impl)
@@ -2907,7 +3567,7 @@ file_list_build_popup_menu (GtkFileChooserDefault *impl)
                             impl->browse_files_tree_view,
                             popup_menu_detach_cb);
 
-  item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Shortcuts"));
+  item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Bookmarks"));
   impl->browse_files_popup_menu_add_shortcut_item = item;
   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
                                 gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
@@ -2917,6 +3577,14 @@ file_list_build_popup_menu (GtkFileChooserDefault *impl)
   gtk_widget_show (item);
   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
 
+  item = gtk_image_menu_item_new_with_mnemonic (_("Open _Location"));
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+                                gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
+  g_signal_connect (item, "activate",
+                   G_CALLBACK (open_location_cb), impl);
+  gtk_widget_show (item);
+  gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
+
   item = gtk_separator_menu_item_new ();
   gtk_widget_show (item);
   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
@@ -2935,7 +3603,7 @@ file_list_update_popup_menu (GtkFileChooserDefault *impl)
 {
   file_list_build_popup_menu (impl);
 
-  /* The sensitivity of the Add to Shortcuts item is set in
+  /* The sensitivity of the Add to Bookmarks item is set in
    * bookmarks_check_add_sensitivity()
    */
 
@@ -3049,6 +3717,13 @@ create_file_list (GtkFileChooserDefault *impl)
 
   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE);
   gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
+
+  gtk_drag_dest_set (impl->browse_files_tree_view,
+                     GTK_DEST_DEFAULT_ALL,
+                     file_list_dest_targets,
+                     num_file_list_dest_targets,
+                     GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  
   g_signal_connect (impl->browse_files_tree_view, "row-activated",
                    G_CALLBACK (list_row_activated), impl);
   g_signal_connect (impl->browse_files_tree_view, "key-press-event",
@@ -3058,7 +3733,17 @@ create_file_list (GtkFileChooserDefault *impl)
   g_signal_connect (impl->browse_files_tree_view, "button-press-event",
                    G_CALLBACK (list_button_press_event_cb), impl);
 
+  g_signal_connect (impl->browse_files_tree_view, "drag-data-received",
+                    G_CALLBACK (file_list_drag_data_received_cb), impl);
+  g_signal_connect (impl->browse_files_tree_view, "drag-drop",
+                    G_CALLBACK (file_list_drag_drop_cb), impl);
+  g_signal_connect (impl->browse_files_tree_view, "drag-motion",
+                    G_CALLBACK (file_list_drag_motion_cb), impl);
+
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  gtk_tree_selection_set_select_function (selection,
+                                         list_select_func,
+                                         impl, NULL);
   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_files_tree_view),
                                          GDK_BUTTON1_MASK,
                                          file_list_source_targets,
@@ -3249,7 +3934,10 @@ save_folder_combo_create (GtkFileChooserDefault *impl)
   GtkWidget *combo;
   GtkCellRenderer *cell;
 
-  combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (impl->shortcuts_model));
+  combo = g_object_new (GTK_TYPE_COMBO_BOX,
+                       "model", impl->shortcuts_model,
+                       "focus-on-click", FALSE,
+                        NULL);
   gtk_widget_show (combo);
 
   cell = gtk_cell_renderer_pixbuf_new ();
@@ -3333,10 +4021,6 @@ save_widgets_create (GtkFileChooserDefault *impl)
                    0, 0);
   gtk_label_set_mnemonic_widget (GTK_LABEL (impl->save_folder_label), impl->save_folder_combo);
 
-  /* custom widget */
-  impl->save_extra_align = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
-  gtk_box_pack_start (GTK_BOX (vbox), impl->save_extra_align, FALSE, FALSE, 0);
-
   /* Expander */
   alignment = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
   gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
@@ -3377,10 +4061,6 @@ browse_widgets_create (GtkFileChooserDefault *impl)
 
   g_object_unref (size_group);
 
-  /* Alignment to hold custom widget */
-  impl->browse_extra_align = gtk_alignment_new (0.0, .5, 1.0, 1.0);
-  gtk_box_pack_start (GTK_BOX (vbox), impl->browse_extra_align, FALSE, FALSE, 0);
-
   return vbox;
 }
 
@@ -3413,6 +4093,10 @@ gtk_file_chooser_default_constructor (GType                  type,
   impl->browse_widgets = browse_widgets_create (impl);
   gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
 
+  /* Alignment to hold extra widget */
+  impl->extra_align = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
+  gtk_box_pack_start (GTK_BOX (impl), impl->extra_align, FALSE, FALSE, 0);
+
   gtk_widget_pop_composite_child ();
   update_appearance (impl);
 
@@ -3432,9 +4116,19 @@ set_extra_widget (GtkFileChooserDefault *impl,
     }
 
   if (impl->extra_widget)
-    g_object_unref (impl->extra_widget);
+    {
+      gtk_container_remove (GTK_CONTAINER (impl->extra_align), impl->extra_widget);
+      g_object_unref (impl->extra_widget);
+    }
 
   impl->extra_widget = extra_widget;
+  if (impl->extra_widget)
+    {
+      gtk_container_add (GTK_CONTAINER (impl->extra_align), impl->extra_widget);
+      gtk_widget_show (impl->extra_align);
+    }
+  else
+    gtk_widget_hide (impl->extra_align);
 }
 
 static void
@@ -3489,6 +4183,7 @@ bookmarks_changed_cb (GtkFileSystem         *file_system,
 
   bookmarks_check_add_sensitivity (impl);
   bookmarks_check_remove_sensitivity (impl);
+  shortcuts_check_popup_sensitivity (impl);
 }
 
 /* Sets the file chooser to multiple selection mode */
@@ -3518,6 +4213,8 @@ static void
 set_file_system_backend (GtkFileChooserDefault *impl,
                         const char *backend)
 {
+  profile_start ("start for backend", backend ? backend : "default");
+
   if (impl->file_system)
     {
       g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
@@ -3563,6 +4260,8 @@ set_file_system_backend (GtkFileChooserDefault *impl,
                                                     G_CALLBACK (bookmarks_changed_cb),
                                                     impl);
     }
+
+  profile_end ("end", NULL);
 }
 
 /* This function is basically a do_all function.
@@ -3573,8 +4272,6 @@ set_file_system_backend (GtkFileChooserDefault *impl,
 static void
 update_appearance (GtkFileChooserDefault *impl)
 {
-  GtkWidget *child;
-
   if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     {
@@ -3617,82 +4314,22 @@ update_appearance (GtkFileChooserDefault *impl)
       gtk_widget_hide (impl->save_widgets);
       gtk_widget_show (impl->browse_widgets);
     }
-  /* FIXME: */
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
-      impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-    {
-      if (impl->browse_files_model)
-       _gtk_file_system_model_set_show_files (impl->browse_files_model, FALSE);
-    }
-  else
-    {
-      if (impl->browse_files_model)
-       _gtk_file_system_model_set_show_files (impl->browse_files_model, TRUE);
-    }
 
   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
     gtk_widget_hide (impl->browse_new_folder_button);
   else
     gtk_widget_show (impl->browse_new_folder_button);
 
-  if (impl->extra_widget)
-    {
-      GtkWidget *align;
-      GtkWidget *unused_align;
-
-      if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-         || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-       {
-         align = impl->save_extra_align;
-         unused_align = impl->browse_extra_align;
-       }
-      else
-       {
-         align = impl->browse_extra_align;
-         unused_align = impl->save_extra_align;
-       }
+  gtk_widget_queue_draw (impl->browse_files_tree_view);
 
-      /* We own a ref on extra_widget, so it's safe to do this */
-      child = GTK_BIN (unused_align)->child;
-      if (child)
-       gtk_container_remove (GTK_CONTAINER (unused_align), child);
+  g_signal_emit_by_name (impl, "default-size-changed");
+}
 
-      child = GTK_BIN (align)->child;
-      if (child && child != impl->extra_widget)
-       {
-         gtk_container_remove (GTK_CONTAINER (align), child);
-         gtk_container_add (GTK_CONTAINER (align), impl->extra_widget);
-       }
-      else if (child == NULL)
-       {
-         gtk_container_add (GTK_CONTAINER (align), impl->extra_widget);
-       }
-
-      gtk_widget_show (align);
-      gtk_widget_hide (unused_align);
-    }
-  else
-    {
-      child = GTK_BIN (impl->browse_extra_align)->child;
-      if (child)
-       gtk_container_remove (GTK_CONTAINER (impl->browse_extra_align), child);
-
-      child = GTK_BIN (impl->save_extra_align)->child;
-      if (child)
-       gtk_container_remove (GTK_CONTAINER (impl->save_extra_align), child);
-
-      gtk_widget_hide (impl->save_extra_align);
-      gtk_widget_hide (impl->browse_extra_align);
-    }
-
-  g_signal_emit_by_name (impl, "default-size-changed");
-}
-
-static void
-gtk_file_chooser_default_set_property (GObject      *object,
-                                      guint         prop_id,
-                                      const GValue *value,
-                                      GParamSpec   *pspec)
+static void
+gtk_file_chooser_default_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
 
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
@@ -3705,9 +4342,14 @@ gtk_file_chooser_default_set_property (GObject      *object,
 
        if (action != impl->action)
          {
-           if (action == GTK_FILE_CHOOSER_ACTION_SAVE && impl->select_multiple)
+           gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
+           
+           if ((action == GTK_FILE_CHOOSER_ACTION_SAVE || action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+               && impl->select_multiple)
              {
-               g_warning ("Multiple selection mode is not allowed in Save mode");
+               g_warning ("Tried to change the file chooser action to SAVE or CREATE_FOLDER, but "
+                          "this is not allowed in multiple selection mode.  Resetting the file chooser "
+                          "to single selection mode.");
                set_select_multiple (impl, FALSE, TRUE);
              }
            impl->action = action;
@@ -3719,42 +4361,53 @@ gtk_file_chooser_default_set_property (GObject      *object,
                                              action);
       }
       break;
+
     case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
       set_file_system_backend (impl, g_value_get_string (value));
       break;
+
     case GTK_FILE_CHOOSER_PROP_FILTER:
       set_current_filter (impl, g_value_get_object (value));
       break;
+
     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
       set_local_only (impl, g_value_get_boolean (value));
       break;
+
     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
       set_preview_widget (impl, g_value_get_object (value));
       break;
+
     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
       impl->preview_widget_active = g_value_get_boolean (value);
       update_preview_widget_visibility (impl);
       break;
+
     case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
       impl->use_preview_label = g_value_get_boolean (value);
       update_preview_widget_visibility (impl);
       break;
+
     case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
       set_extra_widget (impl, g_value_get_object (value));
-      update_appearance (impl);
       break;
+
     case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
       {
        gboolean select_multiple = g_value_get_boolean (value);
-       if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE && select_multiple)
+       if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+           && select_multiple)
          {
-           g_warning ("Multiple selection mode is not allowed in Save mode");
+           g_warning ("Tried to set the file chooser to multiple selection mode, but this is "
+                      "not allowed in SAVE or CREATE_FOLDER modes.  Ignoring the change and "
+                      "leaving the file chooser in single selection mode.");
            return;
          }
 
        set_select_multiple (impl, select_multiple, FALSE);
       }
       break;
+
     case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
       {
        gboolean show_hidden = g_value_get_boolean (value);
@@ -3767,6 +4420,14 @@ gtk_file_chooser_default_set_property (GObject      *object,
          }
       }
       break;
+
+    case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
+      {
+       gboolean do_overwrite_confirmation = g_value_get_boolean (value);
+       impl->do_overwrite_confirmation = do_overwrite_confirmation;
+      }
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3786,30 +4447,43 @@ gtk_file_chooser_default_get_property (GObject    *object,
     case GTK_FILE_CHOOSER_PROP_ACTION:
       g_value_set_enum (value, impl->action);
       break;
+
     case GTK_FILE_CHOOSER_PROP_FILTER:
       g_value_set_object (value, impl->current_filter);
       break;
+
     case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
       g_value_set_boolean (value, impl->local_only);
       break;
+
     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
       g_value_set_object (value, impl->preview_widget);
       break;
+
     case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
       g_value_set_boolean (value, impl->preview_widget_active);
       break;
+
     case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
       g_value_set_boolean (value, impl->use_preview_label);
       break;
+
     case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
       g_value_set_object (value, impl->extra_widget);
       break;
+
     case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
       g_value_set_boolean (value, impl->select_multiple);
       break;
+
     case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
       g_value_set_boolean (value, impl->show_hidden);
       break;
+
+    case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
+      g_value_set_boolean (value, impl->do_overwrite_confirmation);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -3914,7 +4588,7 @@ change_icon_theme (GtkFileChooserDefault *impl)
 
   settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
 
-  if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_SMALL_TOOLBAR, &width, &height))
+  if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
     impl->icon_size = MAX (width, height);
   else
     impl->icon_size = FALLBACK_ICON_SIZE;
@@ -3965,6 +4639,8 @@ gtk_file_chooser_default_style_set (GtkWidget *widget,
 {
   GtkFileChooserDefault *impl;
 
+  profile_start ("start", NULL);
+
   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
 
   if (GTK_WIDGET_CLASS (parent_class)->style_set)
@@ -3974,6 +4650,8 @@ gtk_file_chooser_default_style_set (GtkWidget *widget,
     change_icon_theme (impl);
 
   g_signal_emit_by_name (widget, "default-size-changed");
+
+  profile_end ("end", NULL);
 }
 
 static void
@@ -3994,21 +4672,16 @@ gtk_file_chooser_default_screen_changed (GtkWidget *widget,
 }
 
 static gboolean
-list_model_filter_func (GtkFileSystemModel *model,
-                       GtkFilePath        *path,
-                       const GtkFileInfo  *file_info,
-                       gpointer            user_data)
+get_is_file_filtered (GtkFileChooserDefault *impl,
+                     const GtkFilePath     *path,
+                     GtkFileInfo           *file_info)
 {
-  GtkFileChooserDefault *impl = user_data;
   GtkFileFilterInfo filter_info;
   GtkFileFilterFlags needed;
   gboolean result;
 
   if (!impl->current_filter)
-    return TRUE;
-
-  if (gtk_file_info_get_is_folder (file_info))
-    return TRUE;
+    return FALSE;
 
   filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
 
@@ -4042,18 +4715,71 @@ list_model_filter_func (GtkFileSystemModel *model,
   if (filter_info.uri)
     g_free ((gchar *)filter_info.uri);
 
-  return result;
+  return !result;
+}
+
+/* GtkWidget::map method */
+static void
+gtk_file_chooser_default_map (GtkWidget *widget)
+{
+  GtkFileChooserDefault *impl;
+
+  profile_start ("start", NULL);
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+  GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+  if (impl->current_folder)
+    {
+      pending_select_paths_store_selection (impl);
+      change_folder_and_display_error (impl, impl->current_folder);
+    }
+
+  bookmarks_changed_cb (impl->file_system, impl);
+
+  profile_end ("end", NULL);
+}
+
+static gboolean
+list_model_filter_func (GtkFileSystemModel *model,
+                       GtkFilePath        *path,
+                       const GtkFileInfo  *file_info,
+                       gpointer            user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+
+  if (!impl->current_filter)
+    return TRUE;
+
+  if (gtk_file_info_get_is_folder (file_info))
+    return TRUE;
+
+  return !get_is_file_filtered (impl, path, (GtkFileInfo *) file_info);
 }
 
 static void
 install_list_model_filter (GtkFileChooserDefault *impl)
 {
+  GtkFileSystemModelFilter filter;
+  gpointer data;
+
   g_assert (impl->browse_files_model != NULL);
 
   if (impl->current_filter)
-    _gtk_file_system_model_set_filter (impl->browse_files_model,
-                                      list_model_filter_func,
-                                      impl);
+    {
+      filter = list_model_filter_func;
+      data   = impl;
+    }
+  else
+    {
+      filter = NULL;
+      data   = NULL;
+    }
+  
+  _gtk_file_system_model_set_filter (impl->browse_files_model,
+                                    filter,
+                                    data);
 }
 
 #define COMPARE_DIRECTORIES                                                                                   \
@@ -4160,12 +4886,317 @@ set_busy_cursor (GtkFileChooserDefault *impl,
     gdk_cursor_unref (cursor);
 }
 
+/* Creates a sort model to wrap the file system model and sets it on the tree view */
+static void
+load_set_model (GtkFileChooserDefault *impl)
+{
+  g_assert (impl->browse_files_model != NULL);
+  g_assert (impl->sort_model == NULL);
+
+  impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_MTIME, mtime_sort_func, impl, NULL);
+  gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, GTK_SORT_ASCENDING);
+  impl->list_sort_ascending = TRUE;
+
+  g_signal_connect (impl->sort_model, "sort-column-changed",
+                   G_CALLBACK (list_sort_column_changed_cb), impl);
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                          GTK_TREE_MODEL (impl->sort_model));
+  gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                                  GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
+}
+
+/* Timeout callback used when the loading timer expires */
+static gboolean
+load_timeout_cb (gpointer data)
+{
+  GtkFileChooserDefault *impl;
+
+  profile_start ("start", NULL);
+
+  GDK_THREADS_ENTER ();
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
+  g_assert (impl->load_state == LOAD_PRELOAD);
+  g_assert (impl->load_timeout_id != 0);
+  g_assert (impl->browse_files_model != NULL);
+
+  impl->load_timeout_id = 0;
+  impl->load_state = LOAD_LOADING;
+
+  load_set_model (impl);
+
+  GDK_THREADS_LEAVE ();
+
+  profile_end ("end", NULL);
+
+  return FALSE;
+}
+
+/* Sets up a new load timer for the model and switches to the LOAD_LOADING state */
+static void
+load_setup_timer (GtkFileChooserDefault *impl)
+{
+  g_assert (impl->load_timeout_id == 0);
+  g_assert (impl->load_state != LOAD_PRELOAD);
+
+  impl->load_timeout_id = g_timeout_add (MAX_LOADING_TIME, load_timeout_cb, impl);
+  impl->load_state = LOAD_PRELOAD;
+}
+
+/* Removes the load timeout and switches to the LOAD_FINISHED state */
+static void
+load_remove_timer (GtkFileChooserDefault *impl)
+{
+  if (impl->load_timeout_id != 0)
+    {
+      g_assert (impl->load_state == LOAD_PRELOAD);
+
+      g_source_remove (impl->load_timeout_id);
+      impl->load_timeout_id = 0;
+      impl->load_state = LOAD_EMPTY;
+    }
+  else
+    g_assert (impl->load_state == LOAD_EMPTY ||
+             impl->load_state == LOAD_LOADING ||
+             impl->load_state == LOAD_FINISHED);
+}
+
+/* Selects the first row in the file list */
+static void
+browse_files_select_first_row (GtkFileChooserDefault *impl)
+{
+  GtkTreePath *path;
+
+  if (!impl->sort_model)
+    return;
+
+  path = gtk_tree_path_new_from_indices (0, -1);
+  gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
+  gtk_tree_path_free (path);
+}
+
+struct center_selected_row_closure {
+  GtkFileChooserDefault *impl;
+  gboolean already_centered;
+};
+
+/* Callback used from gtk_tree_selection_selected_foreach(); centers the
+ * selected row in the tree view.
+ */
+static void
+center_selected_row_foreach_cb (GtkTreeModel      *model,
+                               GtkTreePath       *path,
+                               GtkTreeIter       *iter,
+                               gpointer           data)
+{
+  struct center_selected_row_closure *closure;
+
+  closure = data;
+  if (closure->already_centered)
+    return;
+
+  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0);
+  closure->already_centered = TRUE;
+}
+
+/* Centers the selected row in the tree view */
+static void
+browse_files_center_selected_row (GtkFileChooserDefault *impl)
+{
+  struct center_selected_row_closure closure;
+  GtkTreeSelection *selection;
+
+  closure.impl = impl;
+  closure.already_centered = FALSE;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
+}
+
+static gboolean
+show_and_select_paths (GtkFileChooserDefault *impl,
+                      const GtkFilePath     *parent_path,
+                      const GtkFilePath     *only_one_path,
+                      GSList                *paths,
+                      GError               **error)
+{
+  GtkFileFolder *folder;
+  gboolean success;
+  gboolean have_hidden;
+  gboolean have_filtered;
+
+  profile_start ("start", NULL);
+
+  if (!only_one_path && !paths)
+    {
+      profile_end ("end", NULL);
+      return TRUE;
+    }
+
+  folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_HIDDEN, error);
+  if (!folder)
+    {
+      profile_end ("end", NULL);
+      return FALSE;
+    }
+
+  success = FALSE;
+  have_hidden = FALSE;
+  have_filtered = FALSE;
+
+  if (only_one_path)
+    {
+      GtkFileInfo *info;
+
+      info = gtk_file_folder_get_info (folder, only_one_path, error);
+      if (info)
+       {
+         success = TRUE;
+         have_hidden = gtk_file_info_get_is_hidden (info);
+         have_filtered = get_is_file_filtered (impl, only_one_path, info);
+         gtk_file_info_free (info);
+       }
+    }
+  else
+    {
+      GSList *l;
+
+      for (l = paths; l; l = l->next)
+       {
+         const GtkFilePath *path;
+         GtkFileInfo *info;
+
+         path = l->data;
+
+         /* NULL GError */
+         info = gtk_file_folder_get_info (folder, path, NULL);
+         if (info)
+           {
+             if (!have_hidden)
+               have_hidden = gtk_file_info_get_is_hidden (info);
+
+             if (!have_filtered)
+               have_filtered = get_is_file_filtered (impl, path, info);
+
+             gtk_file_info_free (info);
+
+             if (have_hidden && have_filtered)
+               break; /* we now have all the information we need */
+           }
+       }
+
+      success = TRUE;
+    }
+
+  g_object_unref (folder);
+
+  if (!success)
+    {
+      profile_end ("end", NULL);
+      return FALSE;
+    }
+
+  if (have_hidden)
+    g_object_set (impl, "show-hidden", TRUE, NULL);
+
+  if (have_filtered)
+    set_current_filter (impl, NULL);
+
+  if (only_one_path)
+    _gtk_file_system_model_path_do (impl->browse_files_model, only_one_path, select_func, impl);
+  else
+    {
+      GSList *l;
+
+      for (l = paths; l; l = l->next)
+       {
+         const GtkFilePath *path;
+
+         path = l->data;
+         _gtk_file_system_model_path_do (impl->browse_files_model, path, select_func, impl);
+       }
+    }
+
+  profile_end ("end", NULL);
+  return TRUE;
+}
+
+/* Processes the pending operation when a folder is finished loading */
+static void
+pending_select_paths_process (GtkFileChooserDefault *impl)
+{
+  g_assert (impl->load_state == LOAD_FINISHED);
+  g_assert (impl->browse_files_model != NULL);
+  g_assert (impl->sort_model != NULL);
+
+  if (impl->pending_select_paths)
+    {
+      /* NULL GError */
+      show_and_select_paths (impl, impl->current_folder, NULL, impl->pending_select_paths, NULL);
+      pending_select_paths_free (impl);
+      browse_files_center_selected_row (impl);
+    }
+  else
+    {
+      /* We only select the first row if the chooser is actually mapped ---
+       * selecting the first row is to help the user when he is interacting with
+       * the chooser, but sometimes a chooser works not on behalf of the user,
+       * but rather on behalf of something else like GtkFileChooserButton.  In
+       * that case, the chooser's selection should be what the caller expects,
+       * as the user can't see that something else got selected.  See bug #165264.
+       *
+       * Also, we don't select the first file if we are not in OPEN mode.  Doing
+       * so would change the contents of the filename entry for SAVE or
+       * CREATE_FOLDER, which is undesired; in SELECT_FOLDER, we don't want to
+       * select a *different* folder from the one into which the user just
+       * navigated.
+       */
+      if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+       browse_files_select_first_row (impl);
+    }
+
+  g_assert (impl->pending_select_paths == NULL);
+}
+
 /* Callback used when the file system model finishes loading */
 static void
 browse_files_model_finished_loading_cb (GtkFileSystemModel    *model,
                                        GtkFileChooserDefault *impl)
 {
+  profile_start ("start", NULL);
+
+  if (impl->load_state == LOAD_PRELOAD)
+    {
+      load_remove_timer (impl);
+      load_set_model (impl);
+    }
+  else if (impl->load_state == LOAD_LOADING)
+    {
+      /* Nothing */
+    }
+  else
+    {
+      /* We can't g_assert_not_reached(), as something other than us may have
+       *  initiated a folder reload.  See #165556.
+       */
+      profile_end ("end", NULL);
+      return;
+    }
+
+  g_assert (impl->load_timeout_id == 0);
+
+  impl->load_state = LOAD_FINISHED;
+
+  pending_select_paths_process (impl);
   set_busy_cursor (impl, FALSE);
+
+  profile_end ("end", NULL);
 }
 
 /* Gets rid of the old list model and creates a new one for the current folder */
@@ -4173,16 +5204,26 @@ static gboolean
 set_list_model (GtkFileChooserDefault *impl,
                GError               **error)
 {
+  g_assert (impl->current_folder != NULL);
+
+  profile_start ("start", NULL);
+
+  load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
+
   if (impl->browse_files_model)
     {
       g_object_unref (impl->browse_files_model);
       impl->browse_files_model = NULL;
+    }
 
+  if (impl->sort_model)
+    {
       g_object_unref (impl->sort_model);
       impl->sort_model = NULL;
     }
 
   set_busy_cursor (impl, TRUE);
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
 
   impl->browse_files_model = _gtk_file_system_model_new (impl->file_system,
                                                         impl->current_folder, 0,
@@ -4191,45 +5232,20 @@ set_list_model (GtkFileChooserDefault *impl,
   if (!impl->browse_files_model)
     {
       set_busy_cursor (impl, FALSE);
-      gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+      profile_end ("end", NULL);
       return FALSE;
     }
 
+  load_setup_timer (impl); /* This changes the state to LOAD_PRELOAD */
+
   g_signal_connect (impl->browse_files_model, "finished-loading",
                    G_CALLBACK (browse_files_model_finished_loading_cb), impl);
 
   _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden);
-  switch (impl->action)
-    {
-    case GTK_FILE_CHOOSER_ACTION_OPEN:
-    case GTK_FILE_CHOOSER_ACTION_SAVE:
-      _gtk_file_system_model_set_show_files (impl->browse_files_model, TRUE);
-      break;
-    case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
-    case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
-      _gtk_file_system_model_set_show_files (impl->browse_files_model, FALSE);
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-  install_list_model_filter (impl);
 
-  impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
-  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
-  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
-  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_MTIME, mtime_sort_func, impl, NULL);
-  gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
-  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, GTK_SORT_ASCENDING);
-  impl->list_sort_ascending = TRUE;
+  install_list_model_filter (impl);
 
-  g_signal_connect (impl->sort_model, "sort-column-changed",
-                   G_CALLBACK (list_sort_column_changed_cb), impl);
-
-  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
-                          GTK_TREE_MODEL (impl->sort_model));
-  gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
-                                  GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
+  profile_end ("end", NULL);
 
   return TRUE;
 }
@@ -4241,15 +5257,19 @@ update_chooser_entry (GtkFileChooserDefault *impl)
   const GtkFileInfo *info;
   GtkTreeIter iter;
   GtkTreeIter child_iter;
+  gboolean change_entry;
 
-  if (impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
+  if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
     return;
 
   g_assert (!impl->select_multiple);
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
 
   if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
-    return;
+    {
+      _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), "");
+      return;
+    }
 
   gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
                                                  &child_iter,
@@ -4257,7 +5277,12 @@ update_chooser_entry (GtkFileChooserDefault *impl)
 
   info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
 
-  if (!gtk_file_info_get_is_folder (info))
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+    change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
+  else
+    change_entry = TRUE;                                /* ... unless we are in CREATE_FOLDER mode */
+
+  if (change_entry)
     _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
                                           gtk_file_info_get_display_name (info));
 }
@@ -4266,27 +5291,47 @@ static gboolean
 gtk_file_chooser_default_set_current_folder (GtkFileChooser    *chooser,
                                             const GtkFilePath *path,
                                             GError           **error)
+{
+  return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, error);
+}
+
+static gboolean
+gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
+                                               const GtkFilePath *path,
+                                               gboolean           keep_trail,
+                                               GError           **error)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
   gboolean result;
 
+  profile_start ("start", (char *) path);
+
+  g_assert (path != NULL);
+
   if (impl->local_only &&
       !gtk_file_system_path_is_local (impl->file_system, path))
     {
       g_set_error (error,
-                  GTK_FILE_SYSTEM_ERROR,
-                  GTK_FILE_SYSTEM_ERROR_FAILED,
+                  GTK_FILE_CHOOSER_ERROR,
+                  GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
                   _("Cannot change to folder because it is not local"));
 
+      profile_end ("end - not local", (char *) path);
       return FALSE;
     }
 
   /* Test validity of path here.  */
   if (!check_is_folder (impl->file_system, path, error))
-    return FALSE;
+    {
+      profile_end ("end - not a folder", (char *) path);
+      return FALSE;
+    }
 
-  if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, error))
-    return FALSE;
+  if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, keep_trail, error))
+    {
+      profile_end ("end - could not set path bar", (char *) path);
+      return FALSE;
+    }
 
   if (impl->current_folder != path)
     {
@@ -4329,6 +5374,7 @@ gtk_file_chooser_default_set_current_folder (GtkFileChooser    *chooser,
 
   g_signal_emit_by_name (impl, "selection-changed", 0);
 
+  profile_end ("end", NULL);
   return result;
 }
 
@@ -4349,6 +5395,7 @@ gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
   g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
                    || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
 
+  pending_select_paths_free (impl);
   _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), name);
 }
 
@@ -4359,13 +5406,13 @@ select_func (GtkFileSystemModel *model,
             gpointer            user_data)
 {
   GtkFileChooserDefault *impl = user_data;
-  GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
-  GtkTreePath *sorted_path;
+  GtkTreeSelection *selection;
+  GtkTreeIter sorted_iter;
 
-  sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model, path);
-  gtk_tree_view_set_cursor (tree_view, sorted_path, NULL, FALSE);
-  gtk_tree_view_scroll_to_cell (tree_view, sorted_path, NULL, FALSE, 0.0, 0.0);
-  gtk_tree_path_free (sorted_path);
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+
+  gtk_tree_model_sort_convert_child_iter_to_iter (impl->sort_model, &sorted_iter, iter);
+  gtk_tree_selection_select_iter (selection, &sorted_iter);
 }
 
 static gboolean
@@ -4375,57 +5422,45 @@ gtk_file_chooser_default_select_path (GtkFileChooser    *chooser,
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
   GtkFilePath *parent_path;
+  gboolean same_path;
 
   if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, error))
     return FALSE;
 
   if (!parent_path)
     return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
+
+  if (impl->load_state == LOAD_EMPTY)
+    same_path = FALSE;
   else
     {
-      gboolean result;
-      GtkFileFolder *folder;
-      GtkFileInfo *info;
-      gboolean is_hidden;
-
-      result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
-
-      if (!result)
-       {
-         gtk_file_path_free (parent_path);
-         return result;
-       }
+      g_assert (impl->current_folder != NULL);
 
-      folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_HIDDEN, error);
-      gtk_file_path_free (parent_path);
-
-      if (!folder)
-       return FALSE;
-
-      info = gtk_file_folder_get_info (folder, path, error);
-      g_object_unref (folder);
+      same_path = gtk_file_path_compare (parent_path, impl->current_folder) == 0;
+    }
 
-      if (!info)
-       return FALSE;
+  if (same_path && impl->load_state == LOAD_FINISHED)
+    {
+      gboolean result;
 
-      is_hidden = gtk_file_info_get_is_hidden (info);
-      gtk_file_info_free (info);
+      result = show_and_select_paths (impl, parent_path, path, NULL, error);
+      gtk_file_path_free (parent_path);
+      return result;
+    }
 
-      if (is_hidden)
-       g_object_set (impl, "show-hidden", TRUE, NULL);
+  pending_select_paths_add (impl, path);
 
-      result = _gtk_file_system_model_path_do (impl->browse_files_model, path,
-                                              select_func, impl);
-      if (!result)
-       g_set_error (error,
-                    GTK_FILE_CHOOSER_ERROR,
-                    GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
-                    _("Could not find the path"));
+  if (!same_path)
+    {
+      gboolean result;
 
+      result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
+      gtk_file_path_free (parent_path);
       return result;
     }
 
-  g_assert_not_reached ();
+  gtk_file_path_free (parent_path);
+  return TRUE;
 }
 
 static void
@@ -4499,13 +5534,24 @@ gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser)
   GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
 
   gtk_tree_selection_unselect_all (selection);
+  pending_select_paths_free (impl);
 }
 
-/* Checks whether the filename entry for the Save modes contains a valid filename */
-static GtkFilePath *
+/* Checks whether the filename entry for the Save modes contains a well-formed filename.
+ *
+ * is_well_formed_ret - whether what the user typed passes gkt_file_system_make_path()
+ *
+ * is_empty_ret - whether the file entry is totally empty
+ *
+ * is_file_part_empty_ret - whether the file part is empty (will be if user types "foobar/", and
+ *                          the path will be "$cwd/foobar")
+ */
+static void
 check_save_entry (GtkFileChooserDefault *impl,
-                 gboolean              *is_valid,
-                 gboolean              *is_empty)
+                 GtkFilePath          **path_ret,
+                 gboolean              *is_well_formed_ret,
+                 gboolean              *is_empty_ret,
+                 gboolean              *is_file_part_empty_ret)
 {
   GtkFileChooserEntry *chooser_entry;
   const GtkFilePath *current_folder;
@@ -4518,17 +5564,31 @@ check_save_entry (GtkFileChooserDefault *impl,
 
   chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
 
+  if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0)
+    {
+      *path_ret = NULL;
+      *is_well_formed_ret = TRUE;
+      *is_empty_ret = TRUE;
+      *is_file_part_empty_ret = TRUE;
+
+      return;
+    }
+
+  *is_empty_ret = FALSE;
+
   current_folder = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
   file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
 
   if (!file_part || file_part[0] == '\0')
     {
-      *is_valid = FALSE;
-      *is_empty = TRUE;
-      return NULL;
+      *path_ret = gtk_file_path_copy (current_folder);
+      *is_well_formed_ret = TRUE;
+      *is_file_part_empty_ret = TRUE;
+
+      return;
     }
 
-  *is_empty = FALSE;
+  *is_file_part_empty_ret = FALSE;
 
   error = NULL;
   path = gtk_file_system_make_path (impl->file_system, current_folder, file_part, &error);
@@ -4536,12 +5596,14 @@ check_save_entry (GtkFileChooserDefault *impl,
   if (!path)
     {
       error_building_filename_dialog (impl, current_folder, file_part, error);
-      *is_valid = FALSE;
-      return NULL;
+      *path_ret = NULL;
+      *is_well_formed_ret = FALSE;
+
+      return;
     }
 
-  *is_valid = TRUE;
-  return path;
+  *path_ret = path;
+  *is_well_formed_ret = TRUE;
 }
 
 struct get_paths_closure {
@@ -4587,11 +5649,21 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
   if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
       || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     {
-      gboolean is_valid, is_empty;
+      gboolean is_well_formed, is_empty, is_file_part_empty;
+
+      check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty);
 
-      info.path_from_entry = check_save_entry (impl, &is_valid, &is_empty);
-      if (!is_valid && !is_empty)
+      if (!is_well_formed)
        return NULL;
+
+      if (!is_empty)
+       {
+         if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+           {
+             gtk_file_path_free (info.path_from_entry);
+             return NULL;
+           }
+       }
     }
 
   if (!info.path_from_entry || impl->select_multiple)
@@ -4804,7 +5876,7 @@ gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
   g_set_error (error,
               GTK_FILE_CHOOSER_ERROR,
               GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
-              _("shortcut %s does not exist"),
+              _("Shortcut %s does not exist"),
               uri);
   g_free (uri);
 
@@ -4979,6 +6051,198 @@ switch_to_selected_folder (GtkFileChooserDefault *impl)
   change_folder_and_display_error (impl, closure.path);
 }
 
+/* Gets the GtkFileInfo for the selected row in the file list; assumes single
+ * selection mode.
+ */
+static const GtkFileInfo *
+get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
+                                      gboolean              *had_selection)
+{
+  GtkTreeSelection *selection;
+  GtkTreeIter iter, child_iter;
+  const GtkFileInfo *info;
+
+  g_assert (!impl->select_multiple);
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+    {
+      *had_selection = FALSE;
+      return NULL;
+    }
+
+  *had_selection = TRUE;
+
+  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+                                                 &child_iter,
+                                                 &iter);
+
+  info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+  return info;
+}
+
+/* Gets the display name of the selected file in the file list; assumes single
+ * selection mode and that something is selected.
+ */
+static const gchar *
+get_display_name_from_file_list (GtkFileChooserDefault *impl)
+{
+  const GtkFileInfo *info;
+  gboolean had_selection;
+
+  info = get_selected_file_info_from_file_list (impl, &had_selection);
+  g_assert (had_selection);
+  g_assert (info != NULL);
+
+  return gtk_file_info_get_display_name (info);
+}
+
+static void
+add_custom_button_to_dialog (GtkDialog   *dialog,
+                            const gchar *mnemonic_label,
+                            const gchar *stock_id,
+                            gint         response_id)
+{
+  GtkWidget *button;
+
+  button = gtk_button_new_with_mnemonic (mnemonic_label);
+  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+  gtk_button_set_image (GTK_BUTTON (button),
+                       gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON));
+  gtk_widget_show (button);
+
+  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
+}
+
+/* Presents an overwrite confirmation dialog; returns whether we should accept
+ * the filename.
+ */
+static gboolean
+confirm_dialog_should_accept_filename (GtkFileChooserDefault *impl,
+                                      const gchar           *file_part,
+                                      const gchar           *folder_display_name)
+{
+  GtkWindow *toplevel;
+  GtkWidget *dialog;
+  int response;
+
+  toplevel = get_toplevel (GTK_WIDGET (impl));
+
+  dialog = gtk_message_dialog_new (toplevel,
+                                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                  GTK_MESSAGE_QUESTION,
+                                  GTK_BUTTONS_NONE,
+                                  _("A file named \"%s\" already exists.  Do you want to replace it?"),
+                                  file_part);
+  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                           _("The file already exists in \"%s\".  Replacing it will "
+                                             "overwrite its contents."),
+                                           folder_display_name);
+
+  gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+  add_custom_button_to_dialog (GTK_DIALOG (dialog), _("_Replace"), GTK_STOCK_SAVE_AS, GTK_RESPONSE_ACCEPT);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+  
+  if (toplevel->group)
+    gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
+
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  gtk_widget_destroy (dialog);
+
+  return (response == GTK_RESPONSE_ACCEPT);
+}
+
+static char *
+get_display_name_for_folder (GtkFileChooserDefault *impl,
+                            const GtkFilePath     *path)
+{
+  char *display_name;
+  GtkFilePath *parent_path;
+  GtkFileFolder *parent_folder;
+  GtkFileInfo *info;
+
+  display_name = NULL;
+  parent_path = NULL;
+  parent_folder = NULL;
+  info = NULL;
+
+  if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, NULL))
+    goto out;
+
+  parent_folder = gtk_file_system_get_folder (impl->file_system,
+                                             parent_path ? parent_path : path,
+                                             GTK_FILE_INFO_DISPLAY_NAME,
+                                             NULL);
+  if (!parent_folder)
+    goto out;
+
+  info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, NULL);
+  if (!info)
+    goto out;
+
+  display_name = g_strdup (gtk_file_info_get_display_name (info));
+
+ out:
+
+  if (parent_path)
+    gtk_file_path_free (parent_path);
+
+  if (parent_folder)
+    g_object_unref (parent_folder);
+
+  if (info)
+    gtk_file_info_free (info);
+
+  return display_name;
+}
+
+/* Does overwrite confirmation if appropriate, and returns whether the dialog
+ * should respond.  Can get the file part from the file list or the save entry.
+ */
+static gboolean
+should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
+                                       const gchar           *file_part,
+                                       const GtkFilePath     *parent_path)
+{
+  GtkFileChooserConfirmation conf;
+
+  if (!impl->do_overwrite_confirmation)
+    return TRUE;
+
+  conf = GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
+
+  g_signal_emit_by_name (impl, "confirm-overwrite", &conf);
+
+  switch (conf)
+    {
+    case GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM:
+      {
+       char *parent_display_name;
+       gboolean retval;
+
+       g_assert (file_part != NULL);
+
+       parent_display_name = get_display_name_for_folder (impl, parent_path);
+       if (!parent_display_name)
+         return TRUE; /* Huh?  Did the folder disappear?  Let the caller deal with it */
+
+       retval = confirm_dialog_should_accept_filename (impl, file_part, parent_display_name);
+       g_free (parent_display_name);
+       return retval;
+      }
+
+    case GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME:
+      return TRUE;
+
+    case GTK_FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN:
+      return FALSE;
+
+    default:
+      g_assert_not_reached ();
+      return FALSE;
+    }
+}
+
 /* Implementation for GtkFileChooserEmbed::should_respond() */
 static gboolean
 gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
@@ -4996,48 +6260,88 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
 
   if (current_focus == impl->browse_files_tree_view)
     {
+      /* The following array encodes what we do based on the impl->action and the
+       * number of files selected.
+       */
+      typedef enum {
+       NOOP,                   /* Do nothing (don't respond) */
+       RESPOND,                /* Respond immediately */
+       RESPOND_OR_SWITCH,      /* Respond immediately if the selected item is a file; switch to it if it is a folder */
+       ALL_FILES,              /* Respond only if everything selected is a file */
+       ALL_FOLDERS,            /* Respond only if everything selected is a folder */
+       SAVE_ENTRY,             /* Go to the code for handling the save entry */
+       NOT_REACHED             /* Sanity check */
+      } ActionToTake;
+      static const ActionToTake what_to_do[4][3] = {
+       /*                                0 selected            1 selected              many selected */
+       /* ACTION_OPEN */               { NOOP,                 RESPOND_OR_SWITCH,      ALL_FILES   },
+       /* ACTION_SAVE */               { SAVE_ENTRY,           RESPOND_OR_SWITCH,      NOT_REACHED },
+       /* ACTION_SELECT_FOLDER */      { RESPOND,              ALL_FOLDERS,            ALL_FOLDERS },
+       /* ACTION_CREATE_FOLDER */      { SAVE_ENTRY,           ALL_FOLDERS,            NOT_REACHED }
+      };
+
       int num_selected;
       gboolean all_files, all_folders;
+      int k;
+      ActionToTake action;
 
     file_list:
 
+      g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+
       selection_check (impl, &num_selected, &all_files, &all_folders);
 
-      if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+      if (num_selected > 2)
+       k = 2;
+      else
+       k = num_selected;
+
+      action = what_to_do [impl->action] [k];
+
+      switch (action)
        {
-         if (num_selected != 1)
-           return TRUE; /* zero means current folder; more than one means use the whole selection */
-         else if (current_focus != impl->browse_files_tree_view)
+       case NOOP:
+         return FALSE;
+
+       case RESPOND:
+         return TRUE;
+
+       case RESPOND_OR_SWITCH:
+         g_assert (num_selected == 1);
+
+         if (all_folders)
            {
-             /* a single folder is selected and a button was clicked */
              switch_to_selected_folder (impl);
-             return TRUE;
+             return FALSE;
            }
-       }
-      if (num_selected == 0)
-       {
-         if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-             || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-           goto save_entry; /* it makes sense to use the typed name */
+         else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+           return should_respond_after_confirm_overwrite (impl,
+                                                          get_display_name_from_file_list (impl),
+                                                          impl->current_folder);
          else
-           return FALSE;
-       }
+           return TRUE;
 
-      if (num_selected == 1 && all_folders)
-       {
-         switch_to_selected_folder (impl);
-         return FALSE;
+       case ALL_FILES:
+         return all_files;
+
+       case ALL_FOLDERS:
+         return all_folders;
+
+       case SAVE_ENTRY:
+         goto save_entry;
+
+       default:
+         g_assert_not_reached ();
        }
-      else
-       return all_files;
     }
   else if (current_focus == impl->save_file_name_entry)
     {
       GtkFilePath *path;
-      gboolean is_valid, is_empty;
+      gboolean is_well_formed, is_empty, is_file_part_empty;
       gboolean is_folder;
       gboolean retval;
-      GtkFileChooserEntry *entry;  
+      GtkFileChooserEntry *entry;
+      GError *error;
 
     save_entry:
 
@@ -5045,23 +6349,94 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
                || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
 
       entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
-      path = check_save_entry (impl, &is_valid, &is_empty);
+      check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty);
 
-      if (!is_empty && !is_valid)
+      if (is_empty || !is_well_formed)
        return FALSE;
 
-      if (is_empty)
-       path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
-      
-      is_folder = check_is_folder (impl->file_system, path, NULL);
+      g_assert (path != NULL);
+
+      error = NULL;
+      is_folder = check_is_folder (impl->file_system, path, &error);
       if (is_folder)
        {
-         _gtk_file_chooser_entry_set_file_part (entry, "");
-         change_folder_and_display_error (impl, path);
-         retval = FALSE;
+         if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+           {
+             _gtk_file_chooser_entry_set_file_part (entry, "");
+             change_folder_and_display_error (impl, path);
+             retval = FALSE;
+           }
+         else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+           {
+             /* The folder already exists, so we do not need to create it.
+              * Just respond to terminate the dialog.
+              */
+             retval = TRUE;
+           }
        }
       else
-       retval = TRUE;
+       {
+         gboolean file_exists_and_is_not_folder;
+
+         file_exists_and_is_not_folder = g_error_matches (error, GTK_FILE_SYSTEM_ERROR, GTK_FILE_SYSTEM_ERROR_NOT_FOLDER);
+
+         if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER && file_exists_and_is_not_folder)
+           {
+             /* Oops, the user typed the name of an existing path which is not a folder */
+             error_creating_folder_over_existing_file_dialog (impl, path, error);
+             error = NULL; /* as it will be freed below for the general case */
+             retval = FALSE;
+           }
+         else
+           {
+             GtkFilePath *parent_path;
+             gboolean parent_is_folder;
+
+             /* check that everything up to the last component exists */
+
+             parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
+             parent_is_folder = check_is_folder (impl->file_system, parent_path, NULL);
+             if (parent_is_folder)
+               {
+                 if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+                   {
+                     if (file_exists_and_is_not_folder)
+                       {
+                         const char *file_part;
+
+                         file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry));
+                         retval = should_respond_after_confirm_overwrite (impl, file_part, parent_path);
+                       }
+                     else
+                       retval = TRUE;
+                   }
+                 else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+                   {
+                     GError *create_error;
+
+                     create_error = NULL;
+                     if (gtk_file_system_create_folder (impl->file_system, path, &create_error))
+                       retval = TRUE;
+                     else
+                       {
+                         error_creating_folder_dialog (impl, path, create_error);
+                         retval = FALSE;
+                       }
+                   }
+               }
+             else
+               {
+                 /* This will display an error, which is what we want */
+                 change_folder_and_display_error (impl, parent_path);
+                 retval = FALSE;
+               }
+
+             gtk_file_path_free (parent_path);
+           }
+
+         if (error != NULL)
+           g_error_free (error);
+       }
 
       gtk_file_path_free (path);
       return retval;
@@ -5115,15 +6490,7 @@ gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
 
   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
       || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
-    {
-      GtkTreePath *path;
-
-      path = gtk_tree_path_new_from_indices (0, -1);
-      gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
-      gtk_tree_path_free (path);
-
-      widget = impl->browse_files_tree_view;
-    }
+    widget = impl->browse_files_tree_view;
   else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
           || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     widget = impl->save_file_name_entry;
@@ -5144,10 +6511,10 @@ set_current_filter (GtkFileChooserDefault *impl,
     {
       int filter_index;
 
-      /* If we have filters, new filter must be one of them
+      /* NULL filters are allowed to reset to non-filtered status
        */
       filter_index = g_slist_index (impl->filters, filter);
-      if (impl->filters && filter_index < 0)
+      if (impl->filters && filter && filter_index < 0)
        return;
 
       if (impl->current_filter)
@@ -5263,10 +6630,9 @@ shortcuts_activate_volume (GtkFileChooserDefault *impl,
        {
          char *msg;
 
-         msg = g_strdup_printf ("Could not mount %s:\n%s",
-                                gtk_file_system_volume_get_display_name (impl->file_system, volume),
-                                error->message);
-         error_message (impl, msg);
+         msg = g_strdup_printf (_("Could not mount %s"),
+                                gtk_file_system_volume_get_display_name (impl->file_system, volume));
+         error_message (impl, msg, error->message);
          g_free (msg);
          g_error_free (error);
        }
@@ -5374,6 +6740,35 @@ shortcuts_select_func  (GtkTreeSelection  *selection,
   return (*gtk_tree_path_get_indices (path) != shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR));
 }
 
+static gboolean
+list_select_func  (GtkTreeSelection  *selection,
+                  GtkTreeModel      *model,
+                  GtkTreePath       *path,
+                  gboolean           path_currently_selected,
+                  gpointer           data)
+{
+  GtkFileChooserDefault *impl = data;
+
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+    {
+      GtkTreeIter iter, child_iter;
+      const GtkFileInfo *info;
+
+      if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
+       return FALSE;
+      
+      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
+
+      info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+
+      if (info && !gtk_file_info_get_is_folder (info))
+       return FALSE;
+    }
+    
+  return TRUE;
+}
+
 static void
 list_selection_changed (GtkTreeSelection      *selection,
                        GtkFileChooserDefault *impl)
@@ -5381,24 +6776,19 @@ list_selection_changed (GtkTreeSelection      *selection,
   /* See if we are in the new folder editable row for Save mode */
   if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
     {
-      GtkTreeSelection *selection;
-      GtkTreeIter iter, child_iter;
       const GtkFileInfo *info;
+      gboolean had_selection;
 
-      g_assert (!impl->select_multiple);
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-      if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
-       return;
-
-      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
-                                                     &child_iter,
-                                                     &iter);
+      info = get_selected_file_info_from_file_list (impl, &had_selection);
+      if (!had_selection)
+       goto out; /* normal processing */
 
-      info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
       if (!info)
        return; /* We are on the editable row for New Folder */
     }
 
+ out:
+
   update_chooser_entry (impl);
   check_preview_change (impl);
   bookmarks_check_add_sensitivity (impl);
@@ -5433,7 +6823,9 @@ list_row_activated (GtkTreeView           *tree_view,
       return;
     }
 
-  g_signal_emit_by_name (impl, "file-activated");
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+    g_signal_emit_by_name (impl, "file-activated");
 }
 
 static void
@@ -5477,23 +6869,43 @@ list_icon_data_func (GtkTreeViewColumn *tree_column,
   GtkTreeIter child_iter;
   const GtkFilePath *path;
   GdkPixbuf *pixbuf;
+  const GtkFileInfo *info; 
+  gboolean sensitive = TRUE;
+
+  profile_start ("start", NULL);
+  
+  info = get_list_file_info (impl, iter);
 
   gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
                                                  &child_iter,
                                                  iter);
   path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
-  if (!path)
-    return;
 
-  /* FIXME: NULL GError */
-  pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
-                                       impl->icon_size, NULL);
+  if (path)
+    {
+      /* FIXME: NULL GError */
+      pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
+                                           impl->icon_size, NULL);
+    }
+  else
+    {
+      /* We are on the editable row */
+      pixbuf = NULL;
+    }
+
+  if (info && (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+              impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
+    sensitive =  gtk_file_info_get_is_folder (info);    
+    
   g_object_set (cell,
                "pixbuf", pixbuf,
+               "sensitive", sensitive,
                NULL);
-
+    
   if (pixbuf)
     g_object_unref (pixbuf);
+
+  profile_end ("end", NULL);
 }
 
 static void
@@ -5505,17 +6917,27 @@ list_name_data_func (GtkTreeViewColumn *tree_column,
 {
   GtkFileChooserDefault *impl = data;
   const GtkFileInfo *info = get_list_file_info (impl, iter);
+  gboolean sensitive = TRUE;
 
   if (!info)
     {
       g_object_set (cell,
                    "text", _("Type name of new folder"),
                    NULL);
+
       return;
     }
 
+
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
+        || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+    {
+      sensitive = gtk_file_info_get_is_folder (info);
+    } 
+    
   g_object_set (cell,
                "text", gtk_file_info_get_display_name (info),
+               "sensitive", sensitive,
                NULL);
 }
 
@@ -5531,9 +6953,13 @@ list_size_data_func (GtkTreeViewColumn *tree_column,
   const GtkFileInfo *info = get_list_file_info (impl, iter);
   gint64 size;
   gchar *str;
+  gboolean sensitive = TRUE;
 
-  if (!info || gtk_file_info_get_is_folder (info))
-    return;
+  if (!info || gtk_file_info_get_is_folder (info)) 
+    {
+      g_object_set (cell,"sensitive", sensitive, NULL);
+      return;
+    }
 
   size = gtk_file_info_get_size (info);
 
@@ -5546,8 +6972,13 @@ list_size_data_func (GtkTreeViewColumn *tree_column,
   else
     str = g_strdup_printf (_("%.1f G"), size / (1024.*1024.*1024.));
 
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+    sensitive = FALSE;
+
   g_object_set (cell,
-               "text", str,
+               "text", str,
+               "sensitive", sensitive,
                NULL);
 
   g_free (str);
@@ -5568,6 +6999,7 @@ list_mtime_data_func (GtkTreeViewColumn *tree_column,
   GDate mtime, now;
   int days_diff;
   char buf[256];
+  gboolean sensitive = TRUE;
 
   impl = data;
 
@@ -5576,37 +7008,49 @@ list_mtime_data_func (GtkTreeViewColumn *tree_column,
     {
       g_object_set (cell,
                    "text", "",
+                   "sensitive", TRUE,
                    NULL);
       return;
     }
 
   time_mtime = gtk_file_info_get_modification_time (info);
-  g_date_set_time (&mtime, (GTime) time_mtime);
-
-  time_now = (GTime ) time (NULL);
-  g_date_set_time (&now, (GTime) time_now);
 
-  days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
-
-  if (days_diff == 0)
-    strcpy (buf, _("Today"));
-  else if (days_diff == 1)
-    strcpy (buf, _("Yesterday"));
+  if (time_mtime == 0)
+    strcpy (buf, _("Unknown"));
   else
     {
-      char *format;
+      g_date_set_time (&mtime, (GTime) time_mtime);
+
+      time_now = (GTime ) time (NULL);
+      g_date_set_time (&now, (GTime) time_now);
 
-      if (days_diff > 1 && days_diff < 7)
-       format = "%A"; /* Days from last week */
+      days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
+
+      if (days_diff == 0)
+       strcpy (buf, _("Today"));
+      else if (days_diff == 1)
+       strcpy (buf, _("Yesterday"));
       else
-       format = "%x"; /* Any other date */
+       {
+         char *format;
 
-      if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
-       strcpy (buf, _("Unknown"));
+         if (days_diff > 1 && days_diff < 7)
+           format = "%A"; /* Days from last week */
+         else
+           format = "%x"; /* Any other date */
+
+         if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
+           strcpy (buf, _("Unknown"));
+       }
     }
 
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+    sensitive = gtk_file_info_get_is_folder (info);
+
   g_object_set (cell,
                "text", buf,
+               "sensitive", sensitive,
                NULL);
 }
 
@@ -5667,7 +7111,8 @@ update_from_entry (GtkFileChooserDefault *impl,
   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN && !folder_path)
     {
       error_message_with_parent (parent,
-                                _("Cannot change to the folder you specified as it is an invalid path."));
+                                _("Cannot change folder"),
+                                _("The folder you specified is an invalid path."));
       return FALSE;
     }
 
@@ -5706,10 +7151,9 @@ update_from_entry (GtkFileChooserDefault *impl,
          char *uri;
 
          uri = gtk_file_system_path_to_uri (impl->file_system, folder_path);
-         msg = g_strdup_printf (_("Could not build file name from '%s' and '%s':\n%s"),
-                                uri, file_part,
-                                error->message);
-         error_message (impl, msg);
+         msg = g_strdup_printf (_("Could not build file name from '%s' and '%s'"),
+                                uri, file_part);
+         error_message (impl, msg, error->message);
          g_free (uri);
          g_free (msg);
          goto out;
@@ -5743,8 +7187,7 @@ update_from_entry (GtkFileChooserDefault *impl,
          error = NULL;
          result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (impl), subfolder_path, &error);
          if (!result)
-           error_dialog (impl,
-                         _("Could not select %s:\n%s"),
+           error_dialog (impl, _("Could not select item"),
                          subfolder_path, error);
        }
 
@@ -5801,6 +7244,9 @@ location_popup_handler (GtkFileChooserDefault *impl,
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                        accept_stock, GTK_RESPONSE_ACCEPT,
                                        NULL);
+  if (toplevel->group)
+    gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
+  
   gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
   gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
@@ -5870,6 +7316,7 @@ location_popup_handler (GtkFileChooserDefault *impl,
 static void
 up_folder_handler (GtkFileChooserDefault *impl)
 {
+  pending_select_paths_add (impl, impl->current_folder);
   _gtk_path_bar_up (GTK_PATH_BAR (impl->browse_path_bar));
 }
 
@@ -5970,11 +7417,14 @@ shortcuts_model_filter_new (GtkFileChooserDefault *impl,
   ShortcutsModelFilter *model;
 
   model = g_object_new (SHORTCUTS_MODEL_FILTER_TYPE,
-                       "child_model", child_model,
-                       "virtual_root", root,
+                       "child-model", child_model,
+                       "virtual-root", root,
                        NULL);
 
   model->impl = impl;
 
   return GTK_TREE_MODEL (model);
 }
+
+#define __GTK_FILE_CHOOSER_DEFAULT_C__
+#include "gtkaliasdef.c"