]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilechooserdefault.c
Display an error when we come to the root.
[~andy/gtk] / gtk / gtkfilechooserdefault.c
index 8e5a45c627de28dd64b15bcd3ec062045182637f..c5338b9b69ef938d9d21ae5188e07bc943c09c88 100644 (file)
 #include "gtkcellrenderertext.h"
 #include "gtkcellrenderertext.h"
 #include "gtkcheckmenuitem.h"
+#include "gtkclipboard.h"
 #include "gtkcombobox.h"
 #include "gtkentry.h"
 #include "gtkeventbox.h"
 #include "gtkexpander.h"
+#include "gtkfilechooserprivate.h"
 #include "gtkfilechooserdefault.h"
 #include "gtkfilechooserembed.h"
 #include "gtkfilechooserentry.h"
+#include "gtkfilechoosersettings.h"
 #include "gtkfilechooserutils.h"
 #include "gtkfilechooser.h"
 #include "gtkfilesystemmodel.h"
@@ -52,6 +55,7 @@
 #include "gtkmessagedialog.h"
 #include "gtkpathbar.h"
 #include "gtkprivate.h"
+#include "gtkradiobutton.h"
 #include "gtkscrolledwindow.h"
 #include "gtkseparatormenuitem.h"
 #include "gtksizegroup.h"
 #include "gtktable.h"
 #include "gtktreednd.h"
 #include "gtktreeprivate.h"
-#include "gtktreeview.h"
-#include "gtktreemodelsort.h"
 #include "gtktreeselection.h"
-#include "gtktreestore.h"
-#include "gtktooltips.h"
 #include "gtktypebuiltins.h"
 #include "gtkvbox.h"
 
 #include <string.h>
 #include <time.h>
 
-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
-{
-  GtkVBoxClass parent_class;
-};
-
-struct _GtkFileChooserDefault
-{
-  GtkVBox parent_instance;
-
-  GtkFileChooserAction action;
-
-  GtkFileSystem *file_system;
-
-  /* Save mode widgets */
-  GtkWidget *save_widgets;
-
-  GtkWidget *save_file_name_entry;
-  GtkWidget *save_folder_label;
-  GtkWidget *save_folder_combo;
-  GtkWidget *save_expander;
-
-  /* The file browsing widgets */
-  GtkWidget *browse_widgets;
-  GtkWidget *browse_shortcuts_tree_view;
-  GtkWidget *browse_shortcuts_add_button;
-  GtkWidget *browse_shortcuts_remove_button;
-  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;
-
-  GtkFileSystemModel *browse_files_model;
-
-  GtkWidget *filter_combo_hbox;
-  GtkWidget *filter_combo;
-  GtkWidget *preview_box;
-  GtkWidget *preview_label;
-  GtkWidget *preview_widget;
-  GtkWidget *extra_align;
-  GtkWidget *extra_widget;
-
-  GtkListStore *shortcuts_model;
-  GtkTreeModel *shortcuts_filter_model;
+\f
 
-  GtkTreeModelSort *sort_model;
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef G_OS_WIN32
+#include <io.h>
+#endif
 
-  LoadState load_state;
-  guint load_timeout_id;
+/* Profiling stuff */
+#undef PROFILE_FILE_CHOOSER
+#ifdef PROFILE_FILE_CHOOSER
 
-  GSList *pending_select_paths;
 
-  GtkFileFilter *current_filter;
-  GSList *filters;
+#ifndef F_OK 
+#define F_OK 0
+#endif
 
-  GtkTooltips *tooltips;
+#define PROFILE_INDENT 4
+static int profile_indent;
 
-  gboolean has_home;
-  gboolean has_desktop;
+static void
+profile_add_indent (int indent)
+{
+  profile_indent += indent;
+  if (profile_indent < 0)
+    g_error ("You screwed up your indentation");
+}
 
-  int num_volumes;
-  int num_shortcuts;
-  int num_bookmarks;
+void
+_gtk_file_chooser_profile_log (const char *func, int indent, const char *msg1, const char *msg2)
+{
+  char *str;
 
-  gulong volumes_changed_id;
-  gulong bookmarks_changed_id;
+  if (indent < 0)
+    profile_add_indent (indent);
 
-  GtkFilePath *current_volume_path;
-  GtkFilePath *current_folder;
-  GtkFilePath *preview_path;
-  char *preview_display_name;
+  if (profile_indent == 0)
+    str = g_strdup_printf ("MARK: %s %s %s", func ? func : "", msg1 ? msg1 : "", msg2 ? msg2 : "");
+  else
+    str = g_strdup_printf ("MARK: %*c %s %s %s", profile_indent - 1, ' ', func ? func : "", msg1 ? msg1 : "", msg2 ? msg2 : "");
 
-  GtkTreeViewColumn *list_name_column;
-  GtkCellRenderer *list_name_renderer;
+  access (str, F_OK);
+  g_free (str);
 
-  GSource *edited_idle;
-  char *edited_new_text;
+  if (indent > 0)
+    profile_add_indent (indent);
+}
 
-  gulong settings_signal_id;
-  int icon_size;
+#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
 
-  gulong toplevel_set_focus_id;
-  GtkWidget *toplevel_last_focus_widget;
+\f
 
-#if 0
-  GdkDragContext *shortcuts_drag_context;
-  GSource *shortcuts_drag_outside_idle;
-#endif
+typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
 
-  /* Flags */
+#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))
 
-  guint local_only : 1;
-  guint preview_widget_active : 1;
-  guint use_preview_label : 1;
-  guint select_multiple : 1;
-  guint show_hidden : 1;
-  guint list_sort_ascending : 1;
-  guint changing_folder : 1;
-  guint shortcuts_current_folder_active : 1;
+#define MAX_LOADING_TIME 500
 
-#if 0
-  guint shortcuts_drag_outside : 1;
-#endif
+struct _GtkFileChooserDefaultClass
+{
+  GtkVBoxClass parent_class;
 };
 
 /* Signal IDs */
 enum {
   LOCATION_POPUP,
+  LOCATION_POPUP_ON_PASTE,
   UP_FOLDER,
   DOWN_FOLDER,
   HOME_FOLDER,
+  DESKTOP_FOLDER,
+  QUICK_BOOKMARK,
   LAST_SIGNAL
 };
 
@@ -219,6 +174,7 @@ enum {
   SHORTCUTS_COL_IS_VOLUME,
   SHORTCUTS_COL_REMOVABLE,
   SHORTCUTS_COL_PIXBUF_VISIBLE,
+  SHORTCUTS_COL_HANDLE,
   SHORTCUTS_COL_NUM_COLUMNS
 };
 
@@ -261,6 +217,15 @@ static const GtkTargetEntry file_list_source_targets[] = {
 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,
@@ -280,10 +245,8 @@ typedef enum {
 #define NUM_LINES 40
 #define NUM_CHARS 60
 
-static void gtk_file_chooser_default_class_init       (GtkFileChooserDefaultClass *class);
 static void gtk_file_chooser_default_iface_init       (GtkFileChooserIface        *iface);
 static void gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface   *iface);
-static void gtk_file_chooser_default_init             (GtkFileChooserDefault      *impl);
 
 static GObject* gtk_file_chooser_default_constructor  (GType                  type,
                                                       guint                  n_construct_properties,
@@ -300,6 +263,7 @@ static void     gtk_file_chooser_default_get_property (GObject               *ob
 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_unmap          (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,
@@ -310,6 +274,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);
@@ -347,9 +315,13 @@ static void           gtk_file_chooser_default_initial_focus          (GtkFileCh
 
 static void location_popup_handler (GtkFileChooserDefault *impl,
                                    const gchar           *path);
+static void location_popup_on_paste_handler (GtkFileChooserDefault *impl);
 static void up_folder_handler      (GtkFileChooserDefault *impl);
 static void down_folder_handler    (GtkFileChooserDefault *impl);
 static void home_folder_handler    (GtkFileChooserDefault *impl);
+static void desktop_folder_handler (GtkFileChooserDefault *impl);
+static void quick_bookmark_handler (GtkFileChooserDefault *impl,
+                                   gint                   bookmark_index);
 static void update_appearance      (GtkFileChooserDefault *impl);
 
 static void set_current_filter   (GtkFileChooserDefault *impl,
@@ -403,6 +375,7 @@ static void select_func (GtkFileSystemModel *model,
 
 static void path_bar_clicked           (GtkPathBar            *path_bar,
                                        GtkFilePath           *file_path,
+                                       GtkFilePath           *child_path,
                                        gboolean               child_is_hidden,
                                        GtkFileChooserDefault *impl);
 
@@ -410,6 +383,8 @@ static void add_bookmark_button_clicked_cb    (GtkButton             *button,
                                               GtkFileChooserDefault *impl);
 static void remove_bookmark_button_clicked_cb (GtkButton             *button,
                                               GtkFileChooserDefault *impl);
+static void save_folder_combo_changed_cb      (GtkComboBox           *combo,
+                                              GtkFileChooserDefault *impl);
 
 static void list_icon_data_func (GtkTreeViewColumn *tree_column,
                                 GtkCellRenderer   *cell,
@@ -438,8 +413,12 @@ 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 void location_button_toggled_cb (GtkToggleButton *toggle,
+                                       GtkFileChooserDefault *impl);
+static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
 
-static GObjectClass *parent_class;
 
 \f
 
@@ -464,7 +443,7 @@ G_DEFINE_TYPE_WITH_CODE (ShortcutsModelFilter,
                         _shortcuts_model_filter,
                         GTK_TYPE_TREE_MODEL_FILTER,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
-                                               shortcuts_model_filter_drag_source_iface_init));
+                                               shortcuts_model_filter_drag_source_iface_init))
 
 static GtkTreeModel *shortcuts_model_filter_new (GtkFileChooserDefault *impl,
                                                 GtkTreeModel          *child_model,
@@ -472,62 +451,22 @@ static GtkTreeModel *shortcuts_model_filter_new (GtkFileChooserDefault *impl,
 
 \f
 
-GType
-_gtk_file_chooser_default_get_type (void)
-{
-  static GType file_chooser_default_type = 0;
-
-  if (!file_chooser_default_type)
-    {
-      static const GTypeInfo file_chooser_default_info =
-      {
-       sizeof (GtkFileChooserDefaultClass),
-       NULL,           /* base_init */
-       NULL,           /* base_finalize */
-       (GClassInitFunc) gtk_file_chooser_default_class_init,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-       sizeof (GtkFileChooserDefault),
-       0,              /* n_preallocs */
-       (GInstanceInitFunc) gtk_file_chooser_default_init,
-      };
-
-      static const GInterfaceInfo file_chooser_info =
-      {
-       (GInterfaceInitFunc) gtk_file_chooser_default_iface_init, /* interface_init */
-       NULL,                                                          /* interface_finalize */
-       NULL                                                           /* interface_data */
-      };
-
-      static const GInterfaceInfo file_chooser_embed_info =
-      {
-       (GInterfaceInitFunc) gtk_file_chooser_embed_default_iface_init, /* interface_init */
-       NULL,                                                          /* interface_finalize */
-       NULL                                                           /* interface_data */
-      };
-
-      file_chooser_default_type = g_type_register_static (GTK_TYPE_VBOX, "GtkFileChooserDefault",
-                                                        &file_chooser_default_info, 0);
-
-      g_type_add_interface_static (file_chooser_default_type,
-                                  GTK_TYPE_FILE_CHOOSER,
-                                  &file_chooser_info);
-      g_type_add_interface_static (file_chooser_default_type,
-                                  GTK_TYPE_FILE_CHOOSER_EMBED,
-                                  &file_chooser_embed_info);
-    }
-
-  return file_chooser_default_type;
-}
+G_DEFINE_TYPE_WITH_CODE (GtkFileChooserDefault, _gtk_file_chooser_default, GTK_TYPE_VBOX,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
+                                               gtk_file_chooser_default_iface_init)
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER_EMBED,
+                                               gtk_file_chooser_embed_default_iface_init));                                            
 
 static void
-gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
+_gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
 {
+  static const guint quick_bookmark_keyvals[10] = {
+    GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
+  };
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
   GtkBindingSet *binding_set;
-
-  parent_class = g_type_class_peek_parent (class);
+  int i;
 
   gobject_class->finalize = gtk_file_chooser_default_finalize;
   gobject_class->constructor = gtk_file_chooser_default_constructor;
@@ -537,20 +476,29 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
 
   widget_class->show_all = gtk_file_chooser_default_show_all;
   widget_class->map = gtk_file_chooser_default_map;
+  widget_class->unmap = gtk_file_chooser_default_unmap;
   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;
 
   signals[LOCATION_POPUP] =
-    _gtk_binding_signal_new ("location-popup",
+    _gtk_binding_signal_new (I_("location-popup"),
                             G_OBJECT_CLASS_TYPE (class),
                             G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                             G_CALLBACK (location_popup_handler),
                             NULL, NULL,
                             _gtk_marshal_VOID__STRING,
                             G_TYPE_NONE, 1, G_TYPE_STRING);
+  signals[LOCATION_POPUP_ON_PASTE] =
+    _gtk_binding_signal_new ("location-popup-on-paste",
+                            G_OBJECT_CLASS_TYPE (class),
+                            G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                            G_CALLBACK (location_popup_on_paste_handler),
+                            NULL, NULL,
+                            _gtk_marshal_VOID__VOID,
+                            G_TYPE_NONE, 0);
   signals[UP_FOLDER] =
-    _gtk_binding_signal_new ("up-folder",
+    _gtk_binding_signal_new (I_("up-folder"),
                             G_OBJECT_CLASS_TYPE (class),
                             G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                             G_CALLBACK (up_folder_handler),
@@ -558,7 +506,7 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                             _gtk_marshal_VOID__VOID,
                             G_TYPE_NONE, 0);
   signals[DOWN_FOLDER] =
-    _gtk_binding_signal_new ("down-folder",
+    _gtk_binding_signal_new (I_("down-folder"),
                             G_OBJECT_CLASS_TYPE (class),
                             G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                             G_CALLBACK (down_folder_handler),
@@ -566,13 +514,29 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                             _gtk_marshal_VOID__VOID,
                             G_TYPE_NONE, 0);
   signals[HOME_FOLDER] =
-    _gtk_binding_signal_new ("home-folder",
+    _gtk_binding_signal_new (I_("home-folder"),
                             G_OBJECT_CLASS_TYPE (class),
                             G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                             G_CALLBACK (home_folder_handler),
                             NULL, NULL,
                             _gtk_marshal_VOID__VOID,
                             G_TYPE_NONE, 0);
+  signals[DESKTOP_FOLDER] =
+    _gtk_binding_signal_new (I_("desktop-folder"),
+                            G_OBJECT_CLASS_TYPE (class),
+                            G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                            G_CALLBACK (desktop_folder_handler),
+                            NULL, NULL,
+                            _gtk_marshal_VOID__VOID,
+                            G_TYPE_NONE, 0);
+  signals[QUICK_BOOKMARK] =
+    _gtk_binding_signal_new (I_("quick-bookmark"),
+                            G_OBJECT_CLASS_TYPE (class),
+                            G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                            G_CALLBACK (quick_bookmark_handler),
+                            NULL, NULL,
+                            _gtk_marshal_VOID__INT,
+                            G_TYPE_NONE, 1, G_TYPE_INT);
 
   binding_set = gtk_binding_set_by_class (class);
 
@@ -585,6 +549,22 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                GDK_slash, 0,
                                "location-popup",
                                1, G_TYPE_STRING, "/");
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_KP_Divide, 0,
+                               "location-popup",
+                               1, G_TYPE_STRING, "/");
+
+#ifdef G_OS_UNIX
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_asciitilde, 0,
+                               "location-popup",
+                               1, G_TYPE_STRING, "~");
+#endif
+
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_v, GDK_CONTROL_MASK,
+                               "location-popup-on-paste",
+                               0);
 
   gtk_binding_entry_add_signal (binding_set,
                                GDK_Up, GDK_MOD1_MASK,
@@ -616,6 +596,16 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                GDK_KP_Home, GDK_MOD1_MASK,
                                "home-folder",
                                0);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_d, GDK_MOD1_MASK,
+                               "desktop-folder",
+                               0);
+
+  for (i = 0; i < 10; i++)
+    gtk_binding_entry_add_signal (binding_set,
+                                 quick_bookmark_keyvals[i], GDK_MOD1_MASK,
+                                 "quick-bookmark",
+                                 1, G_TYPE_INT, i);
 
   _gtk_file_chooser_install_properties (gobject_class);
 
@@ -623,7 +613,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
@@ -655,9 +645,14 @@ gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface *iface)
   iface->should_respond = gtk_file_chooser_default_should_respond;
   iface->initial_focus = gtk_file_chooser_default_initial_focus;
 }
+
 static void
-gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
+_gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
 {
+  profile_start ("start", NULL);
+#ifdef PROFILE_FILE_CHOOSER
+  access ("MARK: *** CREATE FILE CHOOSER", F_OK);
+#endif
   impl->local_only = TRUE;
   impl->preview_widget_active = TRUE;
   impl->use_preview_label = TRUE;
@@ -665,14 +660,16 @@ gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
   impl->show_hidden = FALSE;
   impl->icon_size = FALLBACK_ICON_SIZE;
   impl->load_state = LOAD_EMPTY;
+  impl->reload_state = RELOAD_EMPTY;
   impl->pending_select_paths = NULL;
+  impl->location_mode = LOCATION_MODE_PATH_BAR;
 
-  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));
+  g_object_ref_sink (impl->tooltips);
+
+  profile_end ("end", NULL);
 }
 
 /* Frees the data columns for the specified iter in the shortcuts model*/
@@ -682,11 +679,17 @@ shortcuts_free_row_data (GtkFileChooserDefault *impl,
 {
   gpointer col_data;
   gboolean is_volume;
+  GtkFileSystemHandle *handle;
 
   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
                      SHORTCUTS_COL_DATA, &col_data,
                      SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                     SHORTCUTS_COL_HANDLE, &handle,
                      -1);
+
+  if (handle)
+    gtk_file_system_cancel_operation (handle);
+
   if (!col_data)
     return;
 
@@ -792,12 +795,10 @@ gtk_file_chooser_default_finalize (GObject *object)
 
   shortcuts_free (impl);
 
-  g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
-  impl->volumes_changed_id = 0;
-  g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
-  impl->bookmarks_changed_id = 0;
   g_object_unref (impl->file_system);
 
+  g_free (impl->browse_files_last_selected_name);
+
   for (l = impl->filters; l; l = l->next)
     {
       GtkFileFilter *filter;
@@ -819,8 +820,6 @@ 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 */
@@ -836,7 +835,7 @@ gtk_file_chooser_default_finalize (GObject *object)
 
   g_object_unref (impl->tooltips);
 
-  G_OBJECT_CLASS (parent_class)->finalize (object);
+  G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->finalize (object);
 }
 
 /* Shows an error dialog set as transient for the specified window */
@@ -855,6 +854,10 @@ error_message_with_parent (GtkWindow  *parent,
                                   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);
 }
@@ -949,6 +952,21 @@ error_creating_folder_dialog (GtkFileChooserDefault *impl,
                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,
+               _("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 create a filename */
 static void
 error_building_filename_dialog (GtkFileChooserDefault *impl,
@@ -979,6 +997,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()
@@ -991,13 +1013,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;
 }
 
@@ -1011,6 +1035,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);
        }
     }
@@ -1056,52 +1081,130 @@ set_preview_widget (GtkFileChooserDefault *impl,
 }
 
 /* Re-reads all the icons for the shortcuts, used when the theme changes */
+struct ReloadIconsData
+{
+  GtkFileChooserDefault *impl;
+  GtkTreeRowReference *row_ref;
+};
+
+static void
+shortcuts_reload_icons_get_info_cb (GtkFileSystemHandle *handle,
+                                   const GtkFileInfo   *info,
+                                   const GError        *error,
+                                   gpointer             user_data)
+{
+  GdkPixbuf *pixbuf;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  gboolean cancelled = handle->cancelled;
+  struct ReloadIconsData *data = user_data;
+
+  if (!g_slist_find (data->impl->reload_icon_handles, handle))
+    goto out;
+
+  data->impl->reload_icon_handles = g_slist_remove (data->impl->reload_icon_handles, handle);
+
+  if (cancelled || error)
+    goto out;
+
+  pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->impl),
+                                     data->impl->icon_size, NULL);
+
+  path = gtk_tree_row_reference_get_path (data->row_ref);
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (data->impl->shortcuts_model), &iter, path);
+  gtk_list_store_set (data->impl->shortcuts_model, &iter,
+                     SHORTCUTS_COL_PIXBUF, pixbuf,
+                     -1);
+  gtk_tree_path_free (path);
+
+  if (pixbuf)
+    g_object_unref (pixbuf);
+
+out:
+  gtk_tree_row_reference_free (data->row_ref);
+  g_object_unref (data->impl);
+  g_free (data);
+
+  g_object_unref (handle);
+}
+
 static void
 shortcuts_reload_icons (GtkFileChooserDefault *impl)
 {
+  GSList *l;
   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;
-    gboolean is_volume;
-    gboolean pixbuf_visible;
-    GdkPixbuf *pixbuf;
+  for (l = impl->reload_icon_handles; l; l = l->next)
+    {
+      GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data);
+      gtk_file_system_cancel_operation (handle);
+    }
+  g_slist_free (impl->reload_icon_handles);
+  impl->reload_icon_handles = NULL;
 
-    gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
-                       SHORTCUTS_COL_DATA, &data,
-                       SHORTCUTS_COL_IS_VOLUME, &is_volume,
-                       SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
-                       -1);
+  do
+    {
+      gpointer data;
+      gboolean is_volume;
+      gboolean pixbuf_visible;
+      GdkPixbuf *pixbuf;
 
-    if (pixbuf_visible && data)
-      {
-       if (is_volume)
-         {
-           GtkFileSystemVolume *volume;
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+                         SHORTCUTS_COL_DATA, &data,
+                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
+                         -1);
 
-           volume = data;
-           pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
-                                                        impl->icon_size, NULL);
-         }
-       else
-         {
-           const GtkFilePath *path;
+      if (pixbuf_visible && data)
+        {
+         if (is_volume)
+           {
+             GtkFileSystemVolume *volume;
 
-           path = data;
-           pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
-                                                 impl->icon_size, NULL);
-         }
+             volume = data;
+             pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
+                                                          impl->icon_size, NULL);
 
-       gtk_list_store_set (impl->shortcuts_model, &iter,
-                           SHORTCUTS_COL_PIXBUF, pixbuf,
-                           -1);
-       if (pixbuf)
-         g_object_unref (pixbuf);
-      }
-  } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
+             gtk_list_store_set (impl->shortcuts_model, &iter,
+                                 SHORTCUTS_COL_PIXBUF, pixbuf,
+                                 -1);
+
+             if (pixbuf)
+               g_object_unref (pixbuf);
+           }
+         else
+           {
+             const GtkFilePath *path;
+             struct ReloadIconsData *info;
+             GtkTreePath *tree_path;
+             GtkFileSystemHandle *handle;
+
+             path = data;
+
+             info = g_new0 (struct ReloadIconsData, 1);
+             info->impl = g_object_ref (impl);
+             tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+             info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
+             gtk_tree_path_free (tree_path);
+
+             handle = gtk_file_system_get_info (impl->file_system, path,
+                                                GTK_FILE_INFO_ICON,
+                                                shortcuts_reload_icons_get_info_cb,
+                                                info);
+             impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
+           }
+       }
+    }
+  while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
+
+ out:
+
+  profile_end ("end", NULL);
 }
 
 static void 
@@ -1134,121 +1237,276 @@ 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)
+/* Removes the specified number of rows from the shortcuts list */
+static void
+shortcuts_remove_rows (GtkFileChooserDefault *impl,
+                      int                    start_row,
+                      int                    n_rows)
 {
-  GtkFilePath *parent_path;
-  GtkFileFolder *parent_folder;
-  GtkFileInfo *info;
-  GError *tmp = NULL;
-
-  parent_path = NULL;
-  info = NULL;
-
-  if (!gtk_file_system_get_parent (file_system, path, &parent_path, &tmp))
-    goto out;
+  GtkTreePath *path;
 
-  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),
-                                             &tmp);
-  if (!parent_folder)
-    goto out;
+  path = gtk_tree_path_new_from_indices (start_row, -1);
 
-  info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, &tmp);
-  g_object_unref (parent_folder);
+  for (; n_rows; n_rows--)
+    {
+      GtkTreeIter iter;
 
- out:
-  if (parent_path)
-    gtk_file_path_free (parent_path);
+      if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
+       g_assert_not_reached ();
 
-  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);
+      shortcuts_free_row_data (impl, &iter);
+      gtk_list_store_remove (impl->shortcuts_model, &iter);
     }
 
-  return info;
+  gtk_tree_path_free (path);
 }
 
-/* Returns whether a path is a folder */
-static gboolean
-check_is_folder (GtkFileSystem      *file_system, 
-                const GtkFilePath  *path, 
-                GError            **error)
+static void
+shortcuts_update_count (GtkFileChooserDefault *impl,
+                       ShortcutsIndex         type,
+                       gint                   value)
 {
-  GtkFileFolder *folder;
+  switch (type)
+    {
+      case SHORTCUTS_HOME:
+       if (value < 0)
+         impl->has_home = FALSE;
+       else
+         impl->has_home = TRUE;
+       break;
 
-  folder = gtk_file_system_get_folder (file_system, path, 0, error);
-  if (!folder)
-    return FALSE;
+      case SHORTCUTS_DESKTOP:
+       if (value < 0)
+         impl->has_desktop = FALSE;
+       else
+         impl->has_desktop = TRUE;
+       break;
 
-  g_object_unref (folder);
-  return TRUE;
+      case SHORTCUTS_VOLUMES:
+       impl->num_volumes += value;
+       break;
+
+      case SHORTCUTS_SHORTCUTS:
+       impl->num_shortcuts += value;
+       break;
+
+      case SHORTCUTS_BOOKMARKS:
+       impl->num_bookmarks += value;
+       break;
+
+      case SHORTCUTS_CURRENT_FOLDER:
+       if (value < 0)
+         impl->shortcuts_current_folder_active = FALSE;
+       else
+         impl->shortcuts_current_folder_active = TRUE;
+       break;
+
+      default:
+       /* nothing */
+       break;
+    }
 }
 
-/* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
- * inserts a volume.  A position of -1 indicates the end of the tree.
- */
-static gboolean
-shortcuts_insert_path (GtkFileChooserDefault *impl,
-                      int                    pos,
-                      gboolean               is_volume,
-                      GtkFileSystemVolume   *volume,
-                      const GtkFilePath     *path,
-                      const char            *label,
-                      gboolean               removable,
-                      GError               **error)
+struct ShortcutsInsertRequest
 {
+  GtkFileChooserDefault *impl;
+  GtkFilePath *parent_path;
+  GtkFilePath *path;
+  int pos;
   char *label_copy;
+  GtkTreeRowReference *row_ref;
+  ShortcutsIndex type;
+  gboolean name_only;
+  gboolean removable;
+};
+
+static void
+get_file_info_finished (GtkFileSystemHandle *handle,
+                       const GtkFileInfo   *info,
+                       const GError        *error,
+                       gpointer             data)
+{
+  gint pos = -1;
+  gboolean cancelled = handle->cancelled;
+  gboolean is_volume = FALSE;
   GdkPixbuf *pixbuf;
-  gpointer data;
+  GtkTreePath *path;
   GtkTreeIter iter;
+  GtkFileSystemHandle *model_handle;
+  struct ShortcutsInsertRequest *request = data;
 
-  if (is_volume)
-    {
-      data = volume;
-      label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
-      pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
-                                                  impl->icon_size, NULL);
-    }
-  else
+  path = gtk_tree_row_reference_get_path (request->row_ref);
+  if (!path)
+    /* Handle doesn't exist anymore in the model */
+    goto out;
+
+  pos = gtk_tree_path_get_indices (path)[0];
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->shortcuts_model),
+                          &iter, path);
+  gtk_tree_path_free (path);
+
+  /* validate handle, else goto out */
+  gtk_tree_model_get (GTK_TREE_MODEL (request->impl->shortcuts_model), &iter,
+                     SHORTCUTS_COL_HANDLE, &model_handle,
+                     -1);
+  if (handle != model_handle)
+    goto out;
+
+  /* set the handle to NULL in the model (we unref later on) */
+  gtk_list_store_set (request->impl->shortcuts_model, &iter,
+                     SHORTCUTS_COL_HANDLE, NULL,
+                     -1);
+
+  if (cancelled)
+    goto out;
+
+  if (!info)
     {
-      if (!check_is_folder (impl->file_system, path, error))
-       return FALSE;
+      gtk_list_store_remove (request->impl->shortcuts_model, &iter);
+      shortcuts_update_count (request->impl, request->type, -1);
+
+      if (request->type == SHORTCUTS_HOME)
+        {
+         const char *home = g_get_home_dir ();
+         GtkFilePath *home_path;
+
+         home_path = gtk_file_system_filename_to_path (request->impl->file_system, home);
+         error_getting_info_dialog (request->impl, home_path, g_error_copy (error));
+         gtk_file_path_free (home_path);
+       }
+      else if (request->type == SHORTCUTS_CURRENT_FOLDER)
+        {
+         /* Remove the current folder separator */
+         gint separator_pos = shortcuts_get_index (request->impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
+         shortcuts_remove_rows (request->impl, separator_pos, 1);
+        }
+
+      goto out;
+    }
+  
+  if (!request->label_copy)
+    request->label_copy = g_strdup (gtk_file_info_get_display_name (info));
+  pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
+                                     request->impl->icon_size, NULL);
+
+  gtk_list_store_set (request->impl->shortcuts_model, &iter,
+                     SHORTCUTS_COL_PIXBUF, pixbuf,
+                     SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
+                     SHORTCUTS_COL_NAME, request->label_copy,
+                     SHORTCUTS_COL_IS_VOLUME, is_volume,
+                     SHORTCUTS_COL_REMOVABLE, request->removable,
+                     -1);
+
+  if (request->impl->shortcuts_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_filter_model));
+
+  if (request->type == SHORTCUTS_CURRENT_FOLDER
+      && request->impl->save_folder_combo != NULL)
+    {
+      /* The current folder is updated via _activate_iter(), don't
+       * have save_folder_combo_changed_cb() call _activate_iter()
+       * again.
+       */
+      g_signal_handlers_block_by_func (request->impl->save_folder_combo,
+                                      G_CALLBACK (save_folder_combo_changed_cb),
+                                      request->impl);
+      gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos);
+      g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
+                                        G_CALLBACK (save_folder_combo_changed_cb),
+                                        request->impl);
+    }
+
+  if (pixbuf)
+    g_object_unref (pixbuf);
+
+out:
+  g_object_unref (request->impl);
+  gtk_file_path_free (request->parent_path);
+  gtk_file_path_free (request->path);
+  gtk_tree_row_reference_free (request->row_ref);
+  g_free (request->label_copy);
+  g_free (request);
+
+  g_object_unref (handle);
+}
+
+/* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
+ * inserts a volume.  A position of -1 indicates the end of the tree.
+ */
+static void
+shortcuts_insert_path (GtkFileChooserDefault *impl,
+                      int                    pos,
+                      gboolean               is_volume,
+                      GtkFileSystemVolume   *volume,
+                      const GtkFilePath     *path,
+                      const char            *label,
+                      gboolean               removable,
+                      ShortcutsIndex         type)
+{
+  char *label_copy;
+  GdkPixbuf *pixbuf = NULL;
+  gpointer data = NULL;
+  GtkTreeIter iter;
 
+  profile_start ("start", is_volume ? "volume" : (char *) path);
+
+  if (is_volume)
+    {
+      data = volume;
+      label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
+      pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
+                                                  impl->icon_size, NULL);
+    }
+  else
+    {
+      struct ShortcutsInsertRequest *request;
+      GtkFileSystemHandle *handle;
+      GtkTreePath *p;
+
+      request = g_new0 (struct ShortcutsInsertRequest, 1);
+      request->impl = g_object_ref (impl);
+      request->path = gtk_file_path_copy (path);
+      request->name_only = TRUE;
+      request->removable = removable;
+      request->pos = pos;
+      request->type = type;
       if (label)
-       label_copy = g_strdup (label);
+       request->label_copy = g_strdup (label);
+
+      if (pos == -1)
+       gtk_list_store_append (impl->shortcuts_model, &iter);
       else
-       {
-         GtkFileInfo *info = get_file_info (impl->file_system, path, TRUE, error);
+       gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
 
-         if (!info)
-           return FALSE;
+      p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+      request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
+      gtk_tree_path_free (p);
 
-         label_copy = g_strdup (gtk_file_info_get_display_name (info));
-         gtk_file_info_free (info);
-       }
+      handle = gtk_file_system_get_info (request->impl->file_system, request->path,
+                                        GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
+                                        get_file_info_finished, request);
 
-      data = gtk_file_path_copy (path);
-      pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
-                                           impl->icon_size, NULL);
+      gtk_list_store_set (impl->shortcuts_model, &iter,
+                         SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
+                         SHORTCUTS_COL_IS_VOLUME, is_volume,
+                         SHORTCUTS_COL_HANDLE, handle,
+                         -1);
+
+      shortcuts_update_count (impl, type, 1);
+
+      return;
     }
 
+  if (!data)
+    data = gtk_file_path_copy (path);
+
   if (pos == -1)
     gtk_list_store_append (impl->shortcuts_model, &iter);
   else
     gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
 
+  shortcuts_update_count (impl, type, 1);
+
   gtk_list_store_set (impl->shortcuts_model, &iter,
                      SHORTCUTS_COL_PIXBUF, pixbuf,
                      SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
@@ -1256,14 +1514,34 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
                      SHORTCUTS_COL_DATA, data,
                      SHORTCUTS_COL_IS_VOLUME, is_volume,
                      SHORTCUTS_COL_REMOVABLE, removable,
+                     SHORTCUTS_COL_HANDLE, NULL,
                      -1);
 
+  if (impl->shortcuts_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+
+  if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
+    {
+      /* The current folder is updated via _activate_iter(), don't
+       * have save_folder_combo_changed_cb() call _activate_iter()
+       * again.
+       */
+      gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
+      g_signal_handlers_block_by_func (impl->save_folder_combo,
+                                      G_CALLBACK (save_folder_combo_changed_cb),
+                                      impl);
+      gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos);
+      g_signal_handlers_unblock_by_func (impl->save_folder_combo,
+                                        G_CALLBACK (save_folder_combo_changed_cb),
+                                        impl);
+    }
+
   g_free (label_copy);
 
   if (pixbuf)
     g_object_unref (pixbuf);
 
-  return TRUE;
+  profile_end ("end", NULL);
 }
 
 /* Appends an item for the user's home directory to the shortcuts model */
@@ -1272,20 +1550,23 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
 {
   const char *home;
   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);
 
-  error = NULL;
-  impl->has_home = shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, _("Home"), FALSE, &error);
-  if (!impl->has_home)
-    error_getting_info_dialog (impl, home_path, error);
+  shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
 
   gtk_file_path_free (home_path);
+
+  profile_end ("end", NULL);
 }
 
 /* Appends the ~/Desktop directory to the shortcuts model */
@@ -1293,14 +1574,20 @@ static void
 shortcuts_append_desktop (GtkFileChooserDefault *impl)
 {
   char *name;
+  const char *home;
   GtkFilePath *path;
 
+  profile_start ("start", NULL);
+
 #ifdef G_OS_WIN32
   name = _gtk_file_system_win32_get_desktop ();
 #else
-  const char *home = g_get_home_dir ();
+  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
@@ -1308,12 +1595,14 @@ shortcuts_append_desktop (GtkFileChooserDefault *impl)
   path = gtk_file_system_filename_to_path (impl->file_system, name);
   g_free (name);
 
-  impl->has_desktop = shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, NULL);
+  shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
   /* We do not actually pop up an error dialog if there is no desktop directory
    * because some people may really not want to have one.
    */
 
   gtk_file_path_free (path);
+
+  profile_end ("end", NULL);
 }
 
 /* Appends a list of GtkFilePath to the shortcuts model; returns how many were inserted */
@@ -1323,6 +1612,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.
    */
@@ -1332,20 +1624,24 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
   for (; paths; paths = paths->next)
     {
       GtkFilePath *path;
-      GError *error;
 
       path = paths->data;
-      error = NULL;
 
       if (impl->local_only &&
          !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))
-       num_inserted++;
+      shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
+      num_inserted++;
+
+      g_free (label);
     }
 
+  profile_end ("end", NULL);
+
   return num_inserted;
 }
 
@@ -1404,30 +1700,6 @@ shortcuts_get_index (GtkFileChooserDefault *impl,
   return n;
 }
 
-/* Removes the specified number of rows from the shortcuts list */
-static void
-shortcuts_remove_rows (GtkFileChooserDefault *impl,
-                      int                    start_row,
-                      int                    n_rows)
-{
-  GtkTreePath *path;
-
-  path = gtk_tree_path_new_from_indices (start_row, -1);
-
-  for (; n_rows; n_rows--)
-    {
-      GtkTreeIter iter;
-
-      if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
-       g_assert_not_reached ();
-
-      shortcuts_free_row_data (impl, &iter);
-      gtk_list_store_remove (impl->shortcuts_model, &iter);
-    }
-
-  gtk_tree_path_free (path);
-}
-
 /* Adds all the file system volumes to the shortcuts model */
 static void
 shortcuts_add_volumes (GtkFileChooserDefault *impl)
@@ -1437,6 +1709,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;
 
@@ -1456,21 +1730,27 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
 
       if (impl->local_only)
        {
-         GtkFilePath *base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
-         gboolean is_local = gtk_file_system_path_is_local (impl->file_system, base_path);
-         gtk_file_path_free (base_path);
-
-         if (!is_local)
+         if (gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
            {
-             gtk_file_system_volume_free (impl->file_system, volume);
-             continue;
+             GtkFilePath *base_path;
+
+             base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+             if (base_path != NULL)
+               {
+                 gboolean is_local = gtk_file_system_path_is_local (impl->file_system, base_path);
+                 gtk_file_path_free (base_path);
+
+                 if (!is_local)
+                   {
+                     gtk_file_system_volume_free (impl->file_system, volume);
+                     continue;
+                   }
+               }
            }
        }
 
-      if (shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, NULL))
-       n++;
-      else
-       gtk_file_system_volume_free (impl->file_system, volume);
+      shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
+      n++;
     }
 
   impl->num_volumes = n;
@@ -1480,6 +1760,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 */
@@ -1512,7 +1794,10 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
   GtkFilePath *combo_selected = NULL;
   gboolean is_volume;
   gpointer col_data;
+
+  profile_start ("start", NULL);
         
+
   old_changing_folders = impl->changing_folder;
   impl->changing_folder = TRUE;
 
@@ -1547,8 +1832,10 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
                           shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
                           impl->num_bookmarks + 1);
 
+  impl->num_bookmarks = 0;
+
   bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
-  impl->num_bookmarks = shortcuts_append_paths (impl, bookmarks);
+  shortcuts_append_paths (impl, bookmarks);
   gtk_file_paths_free (bookmarks);
 
   if (impl->num_bookmarks > 0)
@@ -1575,6 +1862,8 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
     }
   
   impl->changing_folder = old_changing_folders;
+
+  profile_end ("end", NULL);
 }
 
 /* Appends a separator and a row to the shortcuts list for the current folder */
@@ -1613,26 +1902,19 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
       if (base_path &&
          strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
        {
-         success = shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, NULL);
-         if (success)
-           volume = NULL;
+         shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
        }
       else
-       success = shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, NULL);
-
-      if (volume)
-       gtk_file_system_volume_free (impl->file_system, volume);
+        {
+         shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
+         if (volume)
+           gtk_file_system_volume_free (impl->file_system, volume);
+       }
 
       if (base_path)
        gtk_file_path_free (base_path);
-
-      if (!success)
-       shortcuts_remove_rows (impl, pos - 1, 1); /* remove the separator */
-
-      impl->shortcuts_current_folder_active = success;
     }
-
-  if (success)
+  else if (impl->save_folder_combo != NULL)
     gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
 }
 
@@ -1686,14 +1968,14 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
                                              G_TYPE_POINTER,   /* path or volume */
                                              G_TYPE_BOOLEAN,   /* is the previous column a volume? */
                                              G_TYPE_BOOLEAN,   /* removable */
-                                             G_TYPE_BOOLEAN);  /* pixbuf cell visibility */
+                                             G_TYPE_BOOLEAN,   /* pixbuf cell visibility */
+                                             G_TYPE_POINTER);   /* GtkFileSystemHandle */
 
   if (impl->file_system)
     {
       shortcuts_append_home (impl);
       shortcuts_append_desktop (impl);
       shortcuts_add_volumes (impl);
-      shortcuts_add_bookmarks (impl);
     }
 
   impl->shortcuts_filter_model = shortcuts_model_filter_new (impl,
@@ -1736,6 +2018,33 @@ new_folder_button_clicked (GtkButton             *button,
   gtk_tree_path_free (path);
 }
 
+static void
+edited_idle_create_folder_cb (GtkFileSystemHandle *handle,
+                             const GtkFilePath   *path,
+                             const GError        *error,
+                             gpointer             data)
+{
+  gboolean cancelled = handle->cancelled;
+  GtkFileChooserDefault *impl = data;
+
+  if (!g_slist_find (impl->pending_handles, handle))
+    goto out;
+
+  impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
+
+  if (cancelled)
+    goto out;
+
+  if (!error)
+    change_folder_and_display_error (impl, path);
+  else
+    error_creating_folder_dialog (impl, path, g_error_copy (error));
+
+ out:
+  g_object_unref (impl);
+  g_object_unref (handle);
+}
+
 /* Idle handler for creating a new folder after editing its name cell, or for
  * canceling the editing.
  */
@@ -1758,15 +2067,18 @@ edited_idle_cb (GtkFileChooserDefault *impl)
       GtkFilePath *file_path;
 
       error = NULL;
-      file_path = gtk_file_system_make_path (impl->file_system, impl->current_folder, impl->edited_new_text,
+      file_path = gtk_file_system_make_path (impl->file_system,
+                                            impl->current_folder,
+                                            impl->edited_new_text,
                                             &error);
       if (file_path)
        {
-         error = NULL;
-         if (gtk_file_system_create_folder (impl->file_system, file_path, &error))
-           change_folder_and_display_error (impl, file_path);
-         else
-           error_creating_folder_dialog (impl, file_path, error);
+         GtkFileSystemHandle *handle;
+
+         handle = gtk_file_system_create_folder (impl->file_system, file_path,
+                                                 edited_idle_create_folder_cb,
+                                                 g_object_ref (impl));
+         impl->pending_handles = g_slist_append (impl->pending_handles, handle);
 
          gtk_file_path_free (file_path);
        }
@@ -1790,17 +2102,17 @@ queue_edited_idle (GtkFileChooserDefault *impl,
    * just now.
    */
 
-  g_assert (!impl->edited_idle);
-  g_assert (!impl->edited_new_text);
-
-  impl->edited_idle = g_idle_source_new ();
-  g_source_set_closure (impl->edited_idle,
-                       g_cclosure_new_object (G_CALLBACK (edited_idle_cb),
-                                              G_OBJECT (impl)));
-  g_source_attach (impl->edited_idle, NULL);
+  if (!impl->edited_idle)
+    {
+      impl->edited_idle = g_idle_source_new ();
+      g_source_set_closure (impl->edited_idle,
+                           g_cclosure_new_object (G_CALLBACK (edited_idle_cb),
+                                                  G_OBJECT (impl)));
+      g_source_attach (impl->edited_idle, NULL);
+    }
 
-  if (new_text)
-    impl->edited_new_text = g_strdup (new_text);
+  g_free (impl->edited_new_text);
+  impl->edited_new_text = g_strdup (new_text);
 }
 
 /* Callback used from the text cell renderer when the new folder is named */
@@ -1834,6 +2146,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);
 
@@ -1849,29 +2163,15 @@ button_new (GtkFileChooserDefault *impl,
            GCallback   callback)
 {
   GtkWidget *button;
-  GtkWidget *hbox;
-  GtkWidget *widget;
-  GtkWidget *align;
-
-  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);
+  GtkWidget *image;
 
-  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);
 
@@ -1892,6 +2192,12 @@ shortcut_find_position (GtkFileChooserDefault *impl,
 
   current_folder_separator_idx = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
 
+#if 0
+  /* FIXME: is this still needed? */
+  if (current_folder_separator_idx >= impl->shortcuts_model->length)
+    return -1;
+#endif
+
   for (i = 0; i < current_folder_separator_idx; i++)
     {
       gpointer col_data;
@@ -1913,8 +2219,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)
@@ -1931,7 +2237,11 @@ shortcut_find_position (GtkFileChooserDefault *impl,
            }
        }
 
-      gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+      if (i < current_folder_separator_idx - 1)
+       {
+         if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
+           g_assert_not_reached ();
+       }
     }
 
   return -1;
@@ -1945,17 +2255,11 @@ 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;
 
-  /* FIXME: this check really belongs in gtk_file_system_insert_bookmark.  */
-  error = NULL;
-  if (!check_is_folder (impl->file_system, 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))
     {
@@ -2040,7 +2344,6 @@ remove_selected_bookmarks (GtkFileChooserDefault *impl)
 {
   GtkTreeIter iter;
   gpointer col_data;
-  gboolean is_volume;
   GtkFilePath *path;
   gboolean removable;
   GError *error;
@@ -2050,11 +2353,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;
@@ -2289,6 +2590,24 @@ bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
   g_free (name);
 }
 
+static void
+shortcuts_check_popup_sensitivity (GtkFileChooserDefault *impl)
+{
+  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,
@@ -2339,7 +2658,7 @@ shortcuts_drag_data_delete_cb (GtkWidget             *widget,
                               GdkDragContext        *context,
                               GtkFileChooserDefault *impl)
 {
-  g_signal_stop_emission_by_name (widget, "drag-data-delete");
+  g_signal_stop_emission_by_name (widget, "drag_data_delete");
 }
 
 #if 0
@@ -2526,7 +2845,7 @@ shortcuts_drag_leave_cb (GtkWidget             *widget,
                                   NULL,
                                   GTK_TREE_VIEW_DROP_BEFORE);
 
-  g_signal_stop_emission_by_name (widget, "drag-leave");
+  g_signal_stop_emission_by_name (widget, "drag_leave");
 }
 
 /* Computes the appropriate row and position for dropping */
@@ -2632,7 +2951,7 @@ shortcuts_drag_motion_cb (GtkWidget             *widget,
 
  out:
 
-  g_signal_stop_emission_by_name (widget, "drag-motion");
+  g_signal_stop_emission_by_name (widget, "drag_motion");
 
   if (action != 0)
     {
@@ -2656,7 +2975,7 @@ shortcuts_drag_drop_cb (GtkWidget             *widget,
   shortcuts_cancel_drag_outside_idle (impl);
 #endif
 
-  g_signal_stop_emission_by_name (widget, "drag-drop");
+  g_signal_stop_emission_by_name (widget, "drag_drop");
   return TRUE;
 }
 
@@ -2717,6 +3036,7 @@ shortcuts_reorder (GtkFileChooserDefault *impl,
   const GtkFilePath *file_path;
   GtkFilePath *file_path_copy;
   GError *error;
+  gchar *name;
 
   /* Get the selected path */
 
@@ -2732,12 +3052,13 @@ shortcuts_reorder (GtkFileChooserDefault *impl,
   g_assert (old_position >= 0 && old_position < impl->num_bookmarks);
 
   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+                     SHORTCUTS_COL_NAME, &name,
                      SHORTCUTS_COL_DATA, &col_data,
                      SHORTCUTS_COL_IS_VOLUME, &is_volume,
                      -1);
   g_assert (col_data != NULL);
   g_assert (!is_volume);
-
+  
   file_path = col_data;
   file_path_copy = gtk_file_path_copy (file_path); /* removal below will free file_path, so we need a copy */
 
@@ -2751,7 +3072,10 @@ shortcuts_reorder (GtkFileChooserDefault *impl,
 
   error = NULL;
   if (gtk_file_system_remove_bookmark (impl->file_system, file_path_copy, &error))
-    shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
+    {
+      shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
+      gtk_file_system_set_bookmark_label (impl->file_system, file_path_copy, name);
+    }
   else
     error_adding_bookmark_dialog (impl, file_path_copy, error);
 
@@ -2795,12 +3119,12 @@ shortcuts_drag_data_received_cb (GtkWidget          *widget,
   g_assert (position >= bookmarks_index);
   position -= bookmarks_index;
 
-  if (selection_data->target == gdk_atom_intern ("text/uri-list", FALSE))
-    shortcuts_drop_uris (impl, selection_data->data, position);
-  else if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
+  if (selection_data->target == gdk_atom_intern_static_string ("text/uri-list"))
+    shortcuts_drop_uris (impl, (const char *) selection_data->data, position);
+  else if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
     shortcuts_reorder (impl, position);
 
-  g_signal_stop_emission_by_name (widget, "drag-data-received");
+  g_signal_stop_emission_by_name (widget, "drag_data_received");
 }
 
 /* Callback used when the selection in the shortcuts tree changes */
@@ -2809,6 +3133,7 @@ shortcuts_selection_changed_cb (GtkTreeSelection      *selection,
                                GtkFileChooserDefault *impl)
 {
   bookmarks_check_remove_sensitivity (impl);
+  shortcuts_check_popup_sensitivity (impl);
 }
 
 static gboolean
@@ -2837,47 +3162,244 @@ tree_view_keybinding_cb (GtkWidget             *tree_view,
                         GdkEventKey           *event,
                         GtkFileChooserDefault *impl)
 {
-  if (event->keyval == GDK_slash &&
-      ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+  if ((event->keyval == GDK_slash
+       || event->keyval == GDK_KP_Divide
+#ifdef G_OS_UNIX
+       || event->keyval == GDK_asciitilde
+#endif
+       ) && ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
     {
-      location_popup_handler (impl, "/");
+      location_popup_handler (impl, event->string);
       return TRUE;
     }
-  
+
   return FALSE;
 }
 
-
-/* Creates the widgets for the shortcuts and bookmarks tree */
-static GtkWidget *
-shortcuts_list_create (GtkFileChooserDefault *impl)
+/* Callback used when the file list's popup menu is detached */
+static void
+shortcuts_popup_menu_detach_cb (GtkWidget *attach_widget,
+                               GtkMenu   *menu)
 {
-  GtkWidget *swin;
-  GtkTreeSelection *selection;
-  GtkTreeViewColumn *column;
-  GtkCellRenderer *renderer;
-
-  /* Scrolled window */
+  GtkFileChooserDefault *impl;
+  
+  impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
+  g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
 
-  swin = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
-                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
-                                      GTK_SHADOW_IN);
-  gtk_widget_show (swin);
+  impl->browse_shortcuts_popup_menu = NULL;
+  impl->browse_shortcuts_popup_menu_remove_item = NULL;
+  impl->browse_shortcuts_popup_menu_rename_item = NULL;
+}
 
-  /* Tree */
+static void
+remove_shortcut_cb (GtkMenuItem           *item,
+                   GtkFileChooserDefault *impl)
+{
+  remove_selected_bookmarks (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);
-  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);
+/* Rename the selected bookmark */
+static void
+rename_selected_bookmark (GtkFileChooserDefault *impl)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *cell;
+  GList *renderers;
 
-  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_filter_model);
+  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);
+    }
+}
 
-  gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
-                                         GDK_BUTTON1_MASK,
+static void
+rename_shortcut_cb (GtkMenuItem           *item,
+                   GtkFileChooserDefault *impl)
+{
+  rename_selected_bookmark (impl);
+}
+
+/* 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)
+{
+  static gboolean in_press = FALSE;
+  gboolean handled;
+
+  if (in_press)
+    return FALSE;
+
+  if (event->button != 3)
+    return FALSE;
+
+  in_press = TRUE;
+  handled = gtk_widget_event (impl->browse_shortcuts_tree_view, (GdkEvent *) event);
+  in_press = FALSE;
+
+  if (!handled)
+    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);
+  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
+    g_assert_not_reached ();
+
+  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 *
+shortcuts_list_create (GtkFileChooserDefault *impl)
+{
+  GtkWidget *swin;
+  GtkTreeSelection *selection;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+
+  /* Scrolled window */
+
+  swin = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
+                                      GTK_SHADOW_IN);
+  gtk_widget_show (swin);
+
+  /* Tree */
+
+  impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
+#ifdef PROFILE_FILE_CHOOSER
+  g_object_set_data (G_OBJECT (impl->browse_shortcuts_tree_view), "fmq-name", "shortcuts");
+#endif
+  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);
+  /* Accessible object name for the file chooser's shortcuts pane */
+  atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Places"));
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_filter_model);
+
+  gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
+                                         GDK_BUTTON1_MASK,
                                          shortcuts_source_targets,
                                          num_shortcuts_source_targets,
                                          GDK_ACTION_MOVE);
@@ -2897,26 +3419,26 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
   g_signal_connect (selection, "changed",
                    G_CALLBACK (shortcuts_selection_changed_cb), impl);
 
-  g_signal_connect (impl->browse_shortcuts_tree_view, "row-activated",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "row_activated",
                    G_CALLBACK (shortcuts_row_activated_cb), impl);
 
-  g_signal_connect (impl->browse_shortcuts_tree_view, "key-press-event",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
                    G_CALLBACK (shortcuts_key_press_event_cb), impl);
 
-  g_signal_connect (impl->browse_shortcuts_tree_view, "drag-begin",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "drag_begin",
                    G_CALLBACK (shortcuts_drag_begin_cb), impl);
-  g_signal_connect (impl->browse_shortcuts_tree_view, "drag-end",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "drag_end",
                    G_CALLBACK (shortcuts_drag_end_cb), impl);
-  g_signal_connect (impl->browse_shortcuts_tree_view, "drag-data-delete",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_delete",
                    G_CALLBACK (shortcuts_drag_data_delete_cb), impl);
 
-  g_signal_connect (impl->browse_shortcuts_tree_view, "drag-leave",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "drag_leave",
                    G_CALLBACK (shortcuts_drag_leave_cb), impl);
-  g_signal_connect (impl->browse_shortcuts_tree_view, "drag-motion",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "drag_motion",
                    G_CALLBACK (shortcuts_drag_motion_cb), impl);
-  g_signal_connect (impl->browse_shortcuts_tree_view, "drag-drop",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "drag_drop",
                    G_CALLBACK (shortcuts_drag_drop_cb), impl);
-  g_signal_connect (impl->browse_shortcuts_tree_view, "drag-data-received",
+  g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_received",
                    G_CALLBACK (shortcuts_drag_data_received_cb), impl);
 
   gtk_container_add (GTK_CONTAINER (swin), impl->browse_shortcuts_tree_view);
@@ -2925,7 +3447,8 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
   /* Column */
 
   column = gtk_tree_view_column_new ();
-  gtk_tree_view_column_set_title (column, _("Folder"));
+  /* Column header for the file chooser's shortcuts pane */
+  gtk_tree_view_column_set_title (column, _("_Places"));
 
   renderer = gtk_cell_renderer_pixbuf_new ();
   gtk_tree_view_column_pack_start (column, renderer, FALSE);
@@ -2935,6 +3458,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,
@@ -2984,7 +3511,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 */
 
@@ -3011,13 +3538,20 @@ trap_activate_cb (GtkWidget   *widget,
                  gpointer     data)
 {
   GtkFileChooserDefault *impl;
+  int modifiers;
 
   impl = (GtkFileChooserDefault *) data;
-  
-  if (event->keyval == GDK_slash &&
-      ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+
+  modifiers = gtk_accelerator_get_default_mod_mask ();
+
+  if ((event->keyval == GDK_slash
+       || event->keyval == GDK_KP_Divide
+#ifdef G_OS_UNIX
+       || event->keyval == GDK_asciitilde
+#endif
+       ) && ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
     {
-      location_popup_handler (impl, "/");
+      location_popup_handler (impl, event->string);
       return TRUE;
     }
 
@@ -3025,6 +3559,7 @@ trap_activate_cb (GtkWidget   *widget,
        || 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))
     {
@@ -3059,7 +3594,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)
@@ -3067,14 +3602,6 @@ 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,
@@ -3085,6 +3612,193 @@ 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_select_uris (GtkFileChooserDefault  *impl,
+                                gchar                 **uris)
+{
+  int i;
+  char *uri;
+  GtkFileChooser *chooser = GTK_FILE_CHOOSER (impl);
+
+  for (i = 1; uris[i]; i++)
+    {
+      GtkFilePath *path;
+
+      uri = uris[i];
+      path = gtk_file_system_uri_to_path (impl->file_system, uri);
+
+      if (path)
+        {
+         GError *error = NULL;
+
+         gtk_file_chooser_default_select_path (chooser, path, &error);
+         if (error)
+           error_selecting_dragged_file_dialog (impl, path, error);
+
+         gtk_file_path_free (path);
+       }
+    }
+}
+
+struct FileListDragData
+{
+  GtkFileChooserDefault *impl;
+  gchar **uris;
+  GtkFilePath *path;
+};
+
+static void
+file_list_drag_data_received_get_info_cb (GtkFileSystemHandle *handle,
+                                         const GtkFileInfo   *info,
+                                         const GError        *error,
+                                         gpointer             user_data)
+{
+  gboolean cancelled = handle->cancelled;
+  struct FileListDragData *data = user_data;
+  GtkFileChooser *chooser = GTK_FILE_CHOOSER (data->impl);
+
+  if (handle != data->impl->file_list_drag_data_received_handle)
+    goto out;
+
+  data->impl->file_list_drag_data_received_handle = NULL;
+
+  if (cancelled || error)
+    goto out;
+
+  if ((data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+       data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
+      data->uris[1] == 0 && !error &&
+      gtk_file_info_get_is_folder (info))
+    change_folder_and_display_error (data->impl, data->path);
+  else
+    {
+      GError *error = NULL;
+
+      gtk_file_chooser_default_unselect_all (chooser);
+      gtk_file_chooser_default_select_path (chooser, data->path, &error);
+      if (error)
+       error_selecting_dragged_file_dialog (data->impl, data->path, error);
+      else
+       browse_files_center_selected_row (data->impl);
+    }
+
+  if (data->impl->select_multiple)
+    file_list_drag_data_select_uris (data->impl, data->uris);
+
+out:
+  g_object_unref (data->impl);
+  g_strfreev (data->uris);
+  gtk_file_path_free (data->path);
+  g_free (data);
+
+  g_object_unref (handle);
+}
+
+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;
+  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 ((const char *) selection_data->data);
+  if (uris[0]) 
+    {
+      uri = uris[0];
+      path = gtk_file_system_uri_to_path (impl->file_system, uri);
+      
+      if (path)
+       {
+         struct FileListDragData *data;
+
+         data = g_new0 (struct FileListDragData, 1);
+         data->impl = g_object_ref (impl);
+         data->uris = uris;
+         data->path = path;
+
+         if (impl->file_list_drag_data_received_handle)
+           gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
+
+         impl->file_list_drag_data_received_handle =
+           gtk_file_system_get_info (impl->file_system, path,
+                                     GTK_FILE_INFO_IS_FOLDER,
+                                     file_list_drag_data_received_get_info_cb,
+                                     data);
+         goto out;
+       }
+      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)
+       file_list_drag_data_select_uris (impl, uris);
+    }
+
+  g_strfreev (uris);
+
+out:
+  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)
@@ -3099,7 +3813,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));
@@ -3109,14 +3823,6 @@ 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);
@@ -3135,7 +3841,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()
    */
 
@@ -3217,9 +3923,19 @@ list_button_press_event_cb (GtkWidget             *widget,
                            GdkEventButton        *event,
                            GtkFileChooserDefault *impl)
 {
+  static gboolean in_press = FALSE;
+  gboolean handled;
+
+  if (in_press)
+    return FALSE;
+
   if (event->button != 3)
     return FALSE;
 
+  in_press = TRUE;
+  handled = gtk_widget_event (impl->browse_files_tree_view, (GdkEvent *) event);
+  in_press = FALSE;
+
   file_list_popup_menu (impl, event);
   return TRUE;
 }
@@ -3244,20 +3960,37 @@ create_file_list (GtkFileChooserDefault *impl)
   /* Tree/list view */
 
   impl->browse_files_tree_view = gtk_tree_view_new ();
-  g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "GtkFileChooserDefault", impl);
+#ifdef PROFILE_FILE_CHOOSER
+  g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "fmq-name", "file_list");
+#endif
+  g_object_set_data (G_OBJECT (impl->browse_files_tree_view), I_("GtkFileChooserDefault"), impl);
   atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files"));
 
   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);
-  g_signal_connect (impl->browse_files_tree_view, "row-activated",
+
+  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",
+  g_signal_connect (impl->browse_files_tree_view, "key_press_event",
                    G_CALLBACK (trap_activate_cb), impl);
-  g_signal_connect (impl->browse_files_tree_view, "popup-menu",
+  g_signal_connect (impl->browse_files_tree_view, "popup_menu",
                    G_CALLBACK (list_popup_menu_cb), impl);
-  g_signal_connect (impl->browse_files_tree_view, "button-press-event",
+  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,
@@ -3290,7 +4023,7 @@ create_file_list (GtkFileChooserDefault *impl)
                NULL);
   g_signal_connect (impl->list_name_renderer, "edited",
                    G_CALLBACK (renderer_edited_cb), impl);
-  g_signal_connect (impl->list_name_renderer, "editing-canceled",
+  g_signal_connect (impl->list_name_renderer, "editing_canceled",
                    G_CALLBACK (renderer_editing_canceled_cb), impl);
   gtk_tree_view_column_pack_start (impl->list_name_column, impl->list_name_renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (impl->list_name_column, impl->list_name_renderer,
@@ -3304,7 +4037,7 @@ create_file_list (GtkFileChooserDefault *impl)
   gtk_tree_view_column_set_title (column, _("Size"));
 
   renderer = gtk_cell_renderer_text_new ();
-  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+  gtk_tree_view_column_pack_start (column, renderer, TRUE); /* bug: it doesn't expand */
   gtk_tree_view_column_set_cell_data_func (column, renderer,
                                           list_size_data_func, impl, NULL);
   gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
@@ -3373,21 +4106,6 @@ file_pane_create (GtkFileChooserDefault *impl,
   vbox = gtk_vbox_new (FALSE, 6);
   gtk_widget_show (vbox);
 
-  /* The path bar and 'Create Folder' button */
-  hbox = gtk_hbox_new (FALSE, 12);
-  gtk_widget_show (hbox);
-  impl->browse_path_bar = create_path_bar (impl);
-  g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
-  gtk_widget_show_all (impl->browse_path_bar);
-  gtk_box_pack_start (GTK_BOX (hbox), impl->browse_path_bar, TRUE, TRUE, 0);
-
-  /* Create Folder */
-  impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
-  g_signal_connect (impl->browse_new_folder_button, "clicked",
-                   G_CALLBACK (new_folder_button_clicked), impl);
-  gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
   /* Box for lists and preview */
 
   hbox = gtk_hbox_new (FALSE, PREVIEW_HBOX_SPACING);
@@ -3422,6 +4140,7 @@ file_pane_create (GtkFileChooserDefault *impl,
 
   return vbox;
 }
+
 /* Callback used when the "Browse for more folders" expander is toggled */
 static void
 expander_changed_cb (GtkExpander           *expander,
@@ -3485,7 +4204,7 @@ save_folder_combo_create (GtkFileChooserDefault *impl)
 }
 
 /* Creates the widgets specific to Save mode */
-static GtkWidget *
+static void
 save_widgets_create (GtkFileChooserDefault *impl)
 {
   GtkWidget *vbox;
@@ -3493,7 +4212,12 @@ save_widgets_create (GtkFileChooserDefault *impl)
   GtkWidget *widget;
   GtkWidget *alignment;
 
-  vbox = gtk_vbox_new (FALSE, 12);
+  if (impl->save_widgets != NULL)
+    return;
+
+  location_switch_to_path_bar (impl);
+
+  vbox = gtk_vbox_new (FALSE, 12);
 
   table = gtk_table_new (2, 2, FALSE);
   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
@@ -3501,7 +4225,7 @@ save_widgets_create (GtkFileChooserDefault *impl)
   gtk_table_set_row_spacings (GTK_TABLE (table), 12);
   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
 
-  /* Name entry */
+  /* Label */
 
   widget = gtk_label_new_with_mnemonic (_("_Name:"));
   gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
@@ -3511,17 +4235,19 @@ save_widgets_create (GtkFileChooserDefault *impl)
                    0, 0);
   gtk_widget_show (widget);
 
-  impl->save_file_name_entry = _gtk_file_chooser_entry_new (TRUE);
-  _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
+  /* Location entry */
+
+  impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
+  _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
                                           impl->file_system);
-  gtk_entry_set_width_chars (GTK_ENTRY (impl->save_file_name_entry), 45);
-  gtk_entry_set_activates_default (GTK_ENTRY (impl->save_file_name_entry), TRUE);
-  gtk_table_attach (GTK_TABLE (table), impl->save_file_name_entry,
+  gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
+  gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
+  gtk_table_attach (GTK_TABLE (table), impl->location_entry,
                    1, 2, 0, 1,
                    GTK_EXPAND | GTK_FILL, 0,
                    0, 0);
-  gtk_widget_show (impl->save_file_name_entry);
-  gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->save_file_name_entry);
+  gtk_widget_show (impl->location_entry);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->location_entry);
 
   /* Folder combo */
   impl->save_folder_label = gtk_label_new (NULL);
@@ -3550,7 +4276,238 @@ save_widgets_create (GtkFileChooserDefault *impl)
                    impl);
   gtk_widget_show_all (alignment);
 
-  return vbox;
+  impl->save_widgets = vbox;
+  gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
+  gtk_box_reorder_child (GTK_BOX (impl), impl->save_widgets, 0);
+  gtk_widget_show (impl->save_widgets);
+}
+
+/* Destroys the widgets specific to Save mode */
+static void
+save_widgets_destroy (GtkFileChooserDefault *impl)
+{
+  if (impl->save_widgets == NULL)
+    return;
+
+  gtk_widget_destroy (impl->save_widgets);
+  impl->save_widgets = NULL;
+  impl->location_entry = NULL;
+  impl->save_folder_label = NULL;
+  impl->save_folder_combo = NULL;
+  impl->save_expander = NULL;
+}
+
+/* Turns on the path bar widget.  Can be called even if we are already in that
+ * mode.
+ */
+static void
+location_switch_to_path_bar (GtkFileChooserDefault *impl)
+{
+  if (impl->location_entry)
+    {
+      gtk_widget_destroy (impl->location_entry);
+      impl->location_entry = NULL;
+    }
+
+  gtk_widget_hide (impl->location_entry_box);
+}
+
+/* Sets the full path of the current folder as the text in the location entry. */
+static void
+location_entry_set_initial_text (GtkFileChooserDefault *impl)
+{
+  char *text;
+
+  if (!impl->current_folder)
+    return;
+
+  if (gtk_file_system_path_is_local (impl->file_system, impl->current_folder))
+    {
+      char *filename;
+
+      filename = gtk_file_system_path_to_filename (impl->file_system, impl->current_folder);
+      if (filename)
+       {
+         text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+         g_free (filename);
+       }
+      else
+       text = NULL;
+    }
+  else
+    text = gtk_file_system_path_to_uri (impl->file_system, impl->current_folder);
+
+  if (text)
+    {
+      gboolean need_slash;
+      int len;
+
+      len = strlen (text);
+      need_slash = (text[len - 1] != G_DIR_SEPARATOR);
+
+      if (need_slash)
+       {
+         char *slash_text;
+
+         slash_text = g_new (char, len + 2);
+         strcpy (slash_text, text);
+         slash_text[len] = G_DIR_SEPARATOR;
+         slash_text[len + 1] = 0;
+
+         g_free (text);
+         text = slash_text;
+       }
+
+      _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), text);
+      g_free (text);
+    }
+}
+
+/* Turns on the location entry.  Can be called even if we are already in that
+ * mode.
+ */
+static void
+location_switch_to_filename_entry (GtkFileChooserDefault *impl)
+{
+  if (impl->location_entry)
+    gtk_widget_destroy (impl->location_entry);
+
+  /* Box */
+
+  gtk_widget_show (impl->location_entry_box);
+
+  /* Entry */
+
+  impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
+  _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+                                          impl->file_system);
+  gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
+  _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
+
+  gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_entry, TRUE, TRUE, 0);
+  gtk_label_set_mnemonic_widget (GTK_LABEL (impl->location_label), impl->location_entry);
+
+  /* Configure the entry */
+
+  _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder);
+
+  /* Done */
+
+  gtk_widget_show (impl->location_entry);
+  gtk_widget_grab_focus (impl->location_entry);
+}
+
+/* Sets a new location mode.  set_buttons determines whether the toggle button
+ * for the mode will also be changed.
+ */
+static void
+location_mode_set (GtkFileChooserDefault *impl,
+                  LocationMode new_mode,
+                  gboolean set_button)
+{
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+      || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+    {
+      GtkWindow *toplevel;
+      GtkWidget *current_focus;
+      gboolean button_active;
+      gboolean switch_to_file_list;
+
+      switch (new_mode)
+       {
+       case LOCATION_MODE_PATH_BAR:
+         button_active = FALSE;
+
+         /* The location_entry will disappear when we switch to path bar mode.  So,
+          * we'll focus the file list in that case, to avoid having a window with
+          * no focused widget.
+          */
+         toplevel = get_toplevel (GTK_WIDGET (impl));
+         switch_to_file_list = FALSE;
+         if (toplevel)
+           {
+             current_focus = gtk_window_get_focus (toplevel);
+             if (!current_focus || current_focus == impl->location_entry)
+               switch_to_file_list = TRUE;
+           }
+
+         location_switch_to_path_bar (impl);
+
+         if (switch_to_file_list)
+           gtk_widget_grab_focus (impl->browse_files_tree_view);
+
+         break;
+
+       case LOCATION_MODE_FILENAME_ENTRY:
+         button_active = TRUE;
+         location_switch_to_filename_entry (impl);
+         break;
+
+       default:
+         g_assert_not_reached ();
+         return;
+       }
+
+      if (set_button)
+       {
+         g_signal_handlers_block_by_func (impl->location_button,
+                                          G_CALLBACK (location_button_toggled_cb), impl);
+
+         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->location_button), button_active);
+
+         g_signal_handlers_unblock_by_func (impl->location_button,
+                                            G_CALLBACK (location_button_toggled_cb), impl);
+       }
+    }
+
+  impl->location_mode = new_mode;
+}
+
+/* Callback used when one of the location mode buttons is toggled */
+static void
+location_button_toggled_cb (GtkToggleButton *toggle,
+                           GtkFileChooserDefault *impl)
+{
+  gboolean is_active;
+  LocationMode new_mode;
+
+  is_active = gtk_toggle_button_get_active (toggle);
+
+  if (is_active)
+    {
+      g_assert (impl->location_mode == LOCATION_MODE_PATH_BAR);
+      new_mode = LOCATION_MODE_FILENAME_ENTRY;
+    }
+  else
+    {
+      g_assert (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY);
+      new_mode = LOCATION_MODE_PATH_BAR;
+    }
+
+  location_mode_set (impl, new_mode, FALSE);
+}
+
+/* Creates a toggle button for the location entry. */
+static void
+location_button_create (GtkFileChooserDefault *impl)
+{
+  GtkWidget *image;
+  const char *str;
+
+  image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON);
+  gtk_widget_show (image);
+
+  impl->location_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
+                                       "image", image,
+                                       NULL);
+
+  g_signal_connect (impl->location_button, "toggled",
+                   G_CALLBACK (location_button_toggled_cb), impl);
+
+  str = _("Type a file name");
+
+  gtk_tooltips_set_tip (impl->tooltips, impl->location_button, str, NULL);
+  atk_object_set_name (gtk_widget_get_accessible (impl->location_button), str);
 }
 
 /* Creates the main hpaned with the widgets shared by Open and Save mode */
@@ -3558,14 +4515,49 @@ static GtkWidget *
 browse_widgets_create (GtkFileChooserDefault *impl)
 {
   GtkWidget *vbox;
+  GtkWidget *hbox;
   GtkWidget *hpaned;
   GtkWidget *widget;
   GtkSizeGroup *size_group;
+  gchar *text;
 
   /* size group is used by the [+][-] buttons and the filter combo */
   size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
   vbox = gtk_vbox_new (FALSE, 12);
 
+  /* Location widgets */
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  location_button_create (impl);
+  gtk_box_pack_start (GTK_BOX (hbox), impl->location_button, FALSE, FALSE, 0);
+
+  /* Path bar */
+
+  impl->browse_path_bar = create_path_bar (impl);
+  g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
+  gtk_widget_show_all (impl->browse_path_bar);
+  gtk_box_pack_start (GTK_BOX (hbox), impl->browse_path_bar, TRUE, TRUE, 0);
+
+  /* Create Folder */
+  impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
+  g_signal_connect (impl->browse_new_folder_button, "clicked",
+                   G_CALLBACK (new_folder_button_clicked), impl);
+  gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
+
+  /* Box for the location label and entry */
+
+  impl->location_entry_box = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), impl->location_entry_box, FALSE, FALSE, 0);
+  
+  text = g_strconcat ("<b>", _("_Location:"), "</b>", NULL);
+  impl->location_label = gtk_label_new_with_mnemonic (text);
+  g_free (text);
+  gtk_label_set_use_markup (GTK_LABEL (impl->location_label), TRUE);
+  gtk_widget_show (impl->location_label);
+  gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_label, FALSE, FALSE, 0);
+
   /* Paned widget */
   hpaned = gtk_hpaned_new ();
   gtk_widget_show (hpaned);
@@ -3590,9 +4582,11 @@ gtk_file_chooser_default_constructor (GType                  type,
   GtkFileChooserDefault *impl;
   GObject *object;
 
-  object = parent_class->constructor (type,
-                                     n_construct_properties,
-                                     construct_params);
+  profile_start ("start", NULL);
+
+  object = G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->constructor (type,
+                                                                               n_construct_properties,
+                                                                               construct_params);
   impl = GTK_FILE_CHOOSER_DEFAULT (object);
 
   g_assert (impl->file_system);
@@ -3603,10 +4597,6 @@ gtk_file_chooser_default_constructor (GType                  type,
 
   shortcuts_model_create (impl);
 
-  /* Widgets for Save mode */
-  impl->save_widgets = save_widgets_create (impl);
-  gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
-
   /* The browse widgets */
   impl->browse_widgets = browse_widgets_create (impl);
   gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
@@ -3618,6 +4608,8 @@ gtk_file_chooser_default_constructor (GType                  type,
   gtk_widget_pop_composite_child ();
   update_appearance (impl);
 
+  profile_end ("end", NULL);
+
   return object;
 }
 
@@ -3701,6 +4693,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 */
@@ -3730,6 +4723,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);
@@ -3775,6 +4770,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.
@@ -3790,7 +4787,8 @@ update_appearance (GtkFileChooserDefault *impl)
     {
       const char *text;
 
-      gtk_widget_show (impl->save_widgets);
+      gtk_widget_hide (impl->location_button);
+      save_widgets_create (impl);
 
       if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
        text = _("Save in _folder:");
@@ -3824,15 +4822,23 @@ update_appearance (GtkFileChooserDefault *impl)
   else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
           impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
     {
-      gtk_widget_hide (impl->save_widgets);
+      gtk_widget_show (impl->location_button);
+      save_widgets_destroy (impl);
       gtk_widget_show (impl->browse_widgets);
+      location_mode_set (impl, impl->location_mode, TRUE);
     }
 
+  if (impl->location_entry)
+    _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
+
   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);
 
+  /* This *is* needed; we need to redraw the file list because the "sensitivity"
+   * of files may change depending whether we are in a file or folder-only mode.
+   */
   gtk_widget_queue_draw (impl->browse_files_tree_view);
 
   g_signal_emit_by_name (impl, "default-size-changed");
@@ -3857,55 +4863,66 @@ gtk_file_chooser_default_set_property (GObject      *object,
          {
            gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
            
-           if (action == GTK_FILE_CHOOSER_ACTION_SAVE && impl->select_multiple)
+           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;
            update_appearance (impl);
          }
-       
-       if (impl->save_file_name_entry)
-         _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
-                                             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));
       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);
@@ -3918,6 +4935,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;
@@ -3937,30 +4962,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;
@@ -3986,6 +5024,7 @@ remove_settings_signal (GtkFileChooserDefault *impl,
 static void
 gtk_file_chooser_default_dispose (GObject *object)
 {
+  GSList *l;
   GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
 
   if (impl->extra_widget)
@@ -3994,9 +5033,93 @@ gtk_file_chooser_default_dispose (GObject *object)
       impl->extra_widget = NULL;
     }
 
+  if (impl->volumes_changed_id > 0)
+    {
+      g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
+      impl->volumes_changed_id = 0;
+    }
+
+  if (impl->bookmarks_changed_id > 0)
+    {
+      g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
+      impl->bookmarks_changed_id = 0;
+    }
+
+  pending_select_paths_free (impl);
+
+  /* cancel all pending operations */
+  if (impl->pending_handles)
+    {
+      for (l = impl->pending_handles; l; l = l->next)
+        {
+         GtkFileSystemHandle *handle =l->data;
+         gtk_file_system_cancel_operation (handle);
+        }
+      g_slist_free (impl->pending_handles);
+      impl->pending_handles = NULL;
+    }
+
+  if (impl->reload_icon_handles)
+    {
+      for (l = impl->reload_icon_handles; l; l = l->next)
+        {
+         GtkFileSystemHandle *handle =l->data;
+         gtk_file_system_cancel_operation (handle);
+        }
+      g_slist_free (impl->reload_icon_handles);
+      impl->reload_icon_handles = NULL;
+    }
+
+  if (impl->loading_shortcuts)
+    {
+      for (l = impl->loading_shortcuts; l; l = l->next)
+        {
+         GtkFileSystemHandle *handle =l->data;
+         gtk_file_system_cancel_operation (handle);
+        }
+      g_slist_free (impl->loading_shortcuts);
+      impl->loading_shortcuts = NULL;
+    }
+
+  if (impl->file_list_drag_data_received_handle)
+    {
+      gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
+      impl->file_list_drag_data_received_handle = NULL;
+    }
+
+  if (impl->update_current_folder_handle)
+    {
+      gtk_file_system_cancel_operation (impl->update_current_folder_handle);
+      impl->update_current_folder_handle = NULL;
+    }
+
+  if (impl->show_and_select_paths_handle)
+    {
+      gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
+      impl->show_and_select_paths_handle = NULL;
+    }
+
+  if (impl->should_respond_get_info_handle)
+    {
+      gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+      impl->should_respond_get_info_handle = NULL;
+    }
+
+  if (impl->update_from_entry_handle)
+    {
+      gtk_file_system_cancel_operation (impl->update_from_entry_handle);
+      impl->update_from_entry_handle = NULL;
+    }
+
+  if (impl->shortcuts_activate_iter_handle)
+    {
+      gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
+      impl->shortcuts_activate_iter_handle = NULL;
+    }
+
   remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
 
-  G_OBJECT_CLASS (parent_class)->dispose (object);
+  G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->dispose (object);
 }
 
 /* We override show-all since we have internal widgets that
@@ -4050,7 +5173,7 @@ gtk_file_chooser_default_hierarchy_changed (GtkWidget *widget,
   toplevel = gtk_widget_get_toplevel (widget);
   if (GTK_IS_WINDOW (toplevel))
     {
-      impl->toplevel_set_focus_id = g_signal_connect (toplevel, "set-focus",
+      impl->toplevel_set_focus_id = g_signal_connect (toplevel, "set_focus",
                                                      G_CALLBACK (toplevel_set_focus_cb), impl);
       impl->toplevel_last_focus_widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
     }
@@ -4063,6 +5186,8 @@ change_icon_theme (GtkFileChooserDefault *impl)
   GtkSettings *settings;
   gint width, height;
 
+  profile_start ("start", NULL);
+
   settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
 
   if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
@@ -4072,6 +5197,8 @@ change_icon_theme (GtkFileChooserDefault *impl)
 
   shortcuts_reload_icons (impl);
   gtk_widget_queue_resize (impl->browse_files_tree_view);
+
+  profile_end ("end", NULL);
 }
 
 /* Callback used when a GtkSettings value changes */
@@ -4082,11 +5209,15 @@ settings_notify_cb (GObject               *object,
 {
   const char *name;
 
+  profile_start ("start", NULL);
+
   name = g_param_spec_get_name (pspec);
 
   if (strcmp (name, "gtk-icon-theme-name") == 0
       || strcmp (name, "gtk-icon-sizes") == 0)
     change_icon_theme (impl);
+
+  profile_end ("end", NULL);
 }
 
 /* Installs a signal handler for GtkSettings so that we can monitor changes in
@@ -4097,8 +5228,13 @@ check_icon_theme (GtkFileChooserDefault *impl)
 {
   GtkSettings *settings;
 
+  profile_start ("start", NULL);
+
   if (impl->settings_signal_id)
-    return;
+    {
+      profile_end ("end", NULL);
+      return;
+    }
 
   if (gtk_widget_has_screen (GTK_WIDGET (impl)))
     {
@@ -4108,6 +5244,8 @@ check_icon_theme (GtkFileChooserDefault *impl)
 
       change_icon_theme (impl);
     }
+
+  profile_end ("end", NULL);
 }
 
 static void
@@ -4116,15 +5254,23 @@ 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)
-    GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
+  profile_msg ("    parent class style_set start", NULL);
+  if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set)
+    GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set (widget, previous_style);
+  profile_msg ("    parent class style_set end", NULL);
 
   if (gtk_widget_has_screen (GTK_WIDGET (impl)))
     change_icon_theme (impl);
 
+  profile_msg ("    emit default-size-changed start", NULL);
   g_signal_emit_by_name (widget, "default-size-changed");
+  profile_msg ("    emit default-size-changed end", NULL);
+
+  profile_end ("end", NULL);
 }
 
 static void
@@ -4133,15 +5279,19 @@ gtk_file_chooser_default_screen_changed (GtkWidget *widget,
 {
   GtkFileChooserDefault *impl;
 
+  profile_start ("start", NULL);
+
   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
 
-  if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
-    GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous_screen);
+  if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed)
+    GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed (widget, previous_screen);
 
   remove_settings_signal (impl, previous_screen);
   check_icon_theme (impl);
 
   g_signal_emit_by_name (widget, "default-size-changed");
+
+  profile_end ("end", NULL);
 }
 
 static gboolean
@@ -4191,54 +5341,130 @@ get_is_file_filtered (GtkFileChooserDefault *impl,
   return !result;
 }
 
-/* GtkWidget::map method */
 static void
-gtk_file_chooser_default_map (GtkWidget *widget)
+settings_load (GtkFileChooserDefault *impl)
 {
-  GtkFileChooserDefault *impl;
+  GtkFileChooserSettings *settings;
+  LocationMode location_mode;
+  gboolean show_hidden;
 
-  impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+  settings = _gtk_file_chooser_settings_new ();
 
-  GTK_WIDGET_CLASS (parent_class)->map (widget);
+  location_mode = _gtk_file_chooser_settings_get_location_mode (settings);
+  show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings);
 
-  if (impl->current_folder)
-    {
-      pending_select_paths_store_selection (impl);
-      change_folder_and_display_error (impl, impl->current_folder);
-    }
+  g_object_unref (settings);
 
-  bookmarks_changed_cb (impl->file_system, impl);
+  location_mode_set (impl, location_mode, TRUE);
+  gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
 }
 
-static gboolean
-list_model_filter_func (GtkFileSystemModel *model,
-                       GtkFilePath        *path,
-                       const GtkFileInfo  *file_info,
-                       gpointer            user_data)
+static void
+settings_save (GtkFileChooserDefault *impl)
 {
-  GtkFileChooserDefault *impl = user_data;
+  GtkFileChooserSettings *settings;
 
-  if (!impl->current_filter)
-    return TRUE;
+  settings = _gtk_file_chooser_settings_new ();
 
-  if (gtk_file_info_get_is_folder (file_info))
-    return TRUE;
+  _gtk_file_chooser_settings_set_location_mode (settings, impl->location_mode);
+  _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl)));
 
-  return !get_is_file_filtered (impl, path, (GtkFileInfo *) file_info);
+  /* NULL GError */
+  _gtk_file_chooser_settings_save (settings, NULL);
+
+  g_object_unref (settings);
 }
 
+/* GtkWidget::map method */
 static void
-install_list_model_filter (GtkFileChooserDefault *impl)
+gtk_file_chooser_default_map (GtkWidget *widget)
 {
-  GtkFileSystemModelFilter filter;
-  gpointer data;
+  GtkFileChooserDefault *impl;
+  char *current_working_dir;
 
-  g_assert (impl->browse_files_model != NULL);
+  profile_start ("start", NULL);
 
-  if (impl->current_filter)
+  impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+  GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->map (widget);
+
+  switch (impl->reload_state)
     {
-      filter = list_model_filter_func;
-      data   = impl;
+    case RELOAD_EMPTY:
+      /* The user didn't explicitly give us a folder to display, so we'll use the cwd */
+      current_working_dir = g_get_current_dir ();
+      gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl), current_working_dir);
+      g_free (current_working_dir);
+      break;
+
+    case RELOAD_HAS_FOLDER:
+      /* Nothing; we are already loading or loaded, so we don't need to reload */
+      break;
+
+    case RELOAD_WAS_UNMAPPED:
+      /* Just reload the current folder; else continue the pending load. */
+      if (impl->current_folder)
+        {
+          pending_select_paths_store_selection (impl);
+          change_folder_and_display_error (impl, impl->current_folder);
+       }
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  bookmarks_changed_cb (impl->file_system, impl);
+
+  settings_load (impl);
+
+  profile_end ("end", NULL);
+}
+
+/* GtkWidget::unmap method */
+static void
+gtk_file_chooser_default_unmap (GtkWidget *widget)
+{
+  GtkFileChooserDefault *impl;
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+  settings_save (impl);
+
+  GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->unmap (widget);
+
+  impl->reload_state = RELOAD_WAS_UNMAPPED;
+}
+
+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)
+    {
+      filter = list_model_filter_func;
+      data   = impl;
     }
   else
     {
@@ -4359,9 +5585,12 @@ set_busy_cursor (GtkFileChooserDefault *impl,
 static void
 load_set_model (GtkFileChooserDefault *impl)
 {
+  profile_start ("start", NULL);
+
   g_assert (impl->browse_files_model != NULL);
   g_assert (impl->sort_model == NULL);
 
+  profile_msg ("    gtk_tree_model_sort_new_with_model start", 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);
@@ -4369,15 +5598,20 @@ load_set_model (GtkFileChooserDefault *impl)
   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;
+  profile_msg ("    gtk_tree_model_sort_new_with_model end", NULL);
 
-  g_signal_connect (impl->sort_model, "sort-column-changed",
+  g_signal_connect (impl->sort_model, "sort_column_changed",
                    G_CALLBACK (list_sort_column_changed_cb), impl);
 
+  profile_msg ("    gtk_tree_view_set_model start", NULL);
   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_msg ("    gtk_tree_view_set_model end", NULL);
+
+  profile_end ("end", NULL);
 }
 
 /* Timeout callback used when the loading timer expires */
@@ -4386,6 +5620,8 @@ load_timeout_cb (gpointer data)
 {
   GtkFileChooserDefault *impl;
 
+  profile_start ("start", NULL);
+
   GDK_THREADS_ENTER ();
 
   impl = GTK_FILE_CHOOSER_DEFAULT (data);
@@ -4400,10 +5636,12 @@ load_timeout_cb (gpointer data)
 
   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 */
+/* Sets up a new load timer for the model and switches to the LOAD_PRELOAD state */
 static void
 load_setup_timer (GtkFileChooserDefault *impl)
 {
@@ -4484,99 +5722,141 @@ browse_files_center_selected_row (GtkFileChooserDefault *impl)
   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)
+struct ShowAndSelectPathsData
+{
+  GtkFileChooserDefault *impl;
+  GSList *paths;
+};
+
+static void
+show_and_select_paths_finished_loading (GtkFileFolder *folder,
+                                       gpointer user_data)
 {
-  GtkFileFolder *folder;
-  gboolean success;
   gboolean have_hidden;
   gboolean have_filtered;
+  GSList *l;
+  struct ShowAndSelectPathsData *data = user_data;
 
-  if (!only_one_path && !paths)
-    return TRUE;
-
-  folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_HIDDEN, error);
-  if (!folder)
-    return FALSE;
-
-  success = FALSE;
   have_hidden = FALSE;
   have_filtered = FALSE;
 
-  if (only_one_path)
+  for (l = data->paths; l; l = l->next)
     {
+      const GtkFilePath *path;
       GtkFileInfo *info;
 
-      info = gtk_file_folder_get_info (folder, only_one_path, error);
+      path = l->data;
+
+      /* NULL GError */
+      info = gtk_file_folder_get_info (folder, path, NULL);
       if (info)
        {
-         success = TRUE;
-         have_hidden = gtk_file_info_get_is_hidden (info);
-         have_filtered = get_is_file_filtered (impl, only_one_path, info);
+         if (!have_hidden)
+           have_hidden = gtk_file_info_get_is_hidden (info);
+
+         if (!have_filtered)
+           have_filtered = !gtk_file_info_get_is_folder (info) && get_is_file_filtered (data->impl, path, info);
+
          gtk_file_info_free (info);
+
+         if (have_hidden && have_filtered)
+           break; /* we now have all the information we need */
        }
     }
-  else
-    {
-      GSList *l;
 
-      for (l = paths; l; l = l->next)
-       {
-         const GtkFilePath *path;
-         GtkFileInfo *info;
-
-         path = l->data;
+  g_signal_handlers_disconnect_by_func (folder,
+                                       show_and_select_paths_finished_loading,
+                                       user_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);
+  g_object_unref (folder);
 
-             if (!have_filtered)
-               have_filtered = get_is_file_filtered (impl, path, info);
+  if (have_hidden)
+    g_object_set (data->impl, "show-hidden", TRUE, NULL);
 
-             gtk_file_info_free (info);
+  if (have_filtered)
+    set_current_filter (data->impl, NULL);
 
-             if (have_hidden && have_filtered)
-               break; /* we now have all the information we need */
-           }
-       }
+  for (l = data->paths; l; l = l->next)
+    {
+      const GtkFilePath *path;
 
-      success = TRUE;
+      path = l->data;
+      _gtk_file_system_model_path_do (data->impl->browse_files_model, path,
+                                     select_func, data->impl);
     }
 
-  g_object_unref (folder);
+  browse_files_center_selected_row (data->impl);
 
-  if (!success)
-    return FALSE;
+  g_object_unref (data->impl);
+  gtk_file_paths_free (data->paths);
+  g_free (data);
+}
 
-  if (have_hidden)
-    g_object_set (impl, "show-hidden", TRUE, NULL);
+static void
+show_and_select_paths_get_folder_cb (GtkFileSystemHandle   *handle,
+                                    GtkFileFolder         *folder,
+                                    const GError          *error,
+                                    gpointer               user_data)
+{
+  gboolean cancelled = handle->cancelled;
+  struct ShowAndSelectPathsData *data = user_data;
 
-  if (have_filtered)
-    set_current_filter (impl, NULL);
+  if (data->impl->show_and_select_paths_handle != handle)
+    goto out;
 
-  if (only_one_path)
-    _gtk_file_system_model_path_do (impl->browse_files_model, only_one_path, select_func, impl);
+  data->impl->show_and_select_paths_handle = NULL;
+
+  if (cancelled || error)
+    goto out;
+
+  g_object_unref (handle);
+
+  if (gtk_file_folder_is_finished_loading (folder))
+    show_and_select_paths_finished_loading (folder, user_data);
   else
-    {
-      GSList *l;
+    g_signal_connect (folder, "finished-loading",
+                     G_CALLBACK (show_and_select_paths_finished_loading),
+                     user_data);
 
-      for (l = paths; l; l = l->next)
-       {
-         const GtkFilePath *path;
+  return;
 
-         path = l->data;
-         _gtk_file_system_model_path_do (impl->browse_files_model, path, select_func, impl);
-       }
+out:
+  g_object_unref (data->impl);
+  gtk_file_paths_free (data->paths);
+  g_free (data);
+
+  g_object_unref (handle);
+}
+
+static gboolean
+show_and_select_paths (GtkFileChooserDefault *impl,
+                      const GtkFilePath     *parent_path,
+                      GSList                *paths,
+                      GError                **error)
+{
+  struct ShowAndSelectPathsData *info;
+
+  profile_start ("start", NULL);
+
+  if (!paths)
+    {
+      profile_end ("end", NULL);
+      return TRUE;
     }
 
+  info = g_new (struct ShowAndSelectPathsData, 1);
+  info->impl = g_object_ref (impl);
+  info->paths = gtk_file_paths_copy (paths);
+
+  if (impl->show_and_select_paths_handle)
+    gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
+
+  impl->show_and_select_paths_handle =
+    gtk_file_system_get_folder (impl->file_system, parent_path,
+                               GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN,
+                               show_and_select_paths_get_folder_cb, info);
+
+  profile_end ("end", NULL);
   return TRUE;
 }
 
@@ -4591,7 +5871,7 @@ pending_select_paths_process (GtkFileChooserDefault *impl)
   if (impl->pending_select_paths)
     {
       /* NULL GError */
-      show_and_select_paths (impl, impl->current_folder, NULL, impl->pending_select_paths, NULL);
+      show_and_select_paths (impl, impl->current_folder, impl->pending_select_paths, NULL);
       pending_select_paths_free (impl);
       browse_files_center_selected_row (impl);
     }
@@ -4604,11 +5884,13 @@ pending_select_paths_process (GtkFileChooserDefault *impl)
        * 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 in SAVE or CREATE_FOLDER
-       * modes.  Doing so would change the contents of the filename entry.
+       * 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_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
+      if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
        browse_files_select_first_row (impl);
     }
 
@@ -4620,6 +5902,8 @@ 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);
@@ -4634,6 +5918,7 @@ browse_files_model_finished_loading_cb (GtkFileSystemModel    *model,
       /* 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;
     }
 
@@ -4643,6 +5928,11 @@ browse_files_model_finished_loading_cb (GtkFileSystemModel    *model,
 
   pending_select_paths_process (impl);
   set_busy_cursor (impl, FALSE);
+#ifdef PROFILE_FILE_CHOOSER
+  access ("MARK: *** FINISHED LOADING", F_OK);
+#endif
+
+  profile_end ("end", NULL);
 }
 
 /* Gets rid of the old list model and creates a new one for the current folder */
@@ -4652,6 +5942,8 @@ set_list_model (GtkFileChooserDefault *impl,
 {
   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)
@@ -4676,6 +5968,7 @@ set_list_model (GtkFileChooserDefault *impl,
   if (!impl->browse_files_model)
     {
       set_busy_cursor (impl, FALSE);
+      profile_end ("end", NULL);
       return FALSE;
     }
 
@@ -4688,35 +5981,147 @@ set_list_model (GtkFileChooserDefault *impl,
 
   install_list_model_filter (impl);
 
+  profile_end ("end", NULL);
+
   return TRUE;
 }
 
+struct update_chooser_entry_selected_foreach_closure {
+  int num_selected;
+  GtkTreeIter first_selected_iter;
+};
+
+static gint
+compare_utf8_filenames (const gchar *a,
+                       const gchar *b)
+{
+  gchar *a_folded, *b_folded;
+  gint retval;
+
+  a_folded = g_utf8_strdown (a, -1);
+  b_folded = g_utf8_strdown (b, -1);
+
+  retval = strcmp (a_folded, b_folded);
+
+  g_free (a_folded);
+  g_free (b_folded);
+
+  return retval;
+}
+
+static void
+update_chooser_entry_selected_foreach (GtkTreeModel *model,
+                                      GtkTreePath *path,
+                                      GtkTreeIter *iter,
+                                      gpointer data)
+{
+  struct update_chooser_entry_selected_foreach_closure *closure;
+
+  closure = data;
+  closure->num_selected++;
+
+  if (closure->num_selected == 1)
+    closure->first_selected_iter = *iter;
+}
+
 static void
 update_chooser_entry (GtkFileChooserDefault *impl)
 {
   GtkTreeSelection *selection;
-  const GtkFileInfo *info;
-  GtkTreeIter iter;
-  GtkTreeIter child_iter;
+  struct update_chooser_entry_selected_foreach_closure closure;
+  const char *file_part;
 
-  if (impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
+  if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+       || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+       || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+            || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+           && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)))
     return;
 
-  g_assert (!impl->select_multiple);
+  g_assert (impl->location_entry != NULL);
+
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  closure.num_selected = 0;
+  gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure);
 
-  if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
-    return;
+  file_part = NULL;
 
-  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
-                                                 &child_iter,
-                                                 &iter);
+  if (closure.num_selected == 0)
+    {
+      goto maybe_clear_entry;
+    }
+  else if (closure.num_selected == 1)
+    {
+      GtkTreeIter child_iter;
+      const GtkFileInfo *info;
+      gboolean change_entry;
 
-  info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+                                                     &child_iter,
+                                                     &closure.first_selected_iter);
 
-  if (!gtk_file_info_get_is_folder (info))
-    _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
-                                          gtk_file_info_get_display_name (info));
+      info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+
+      g_free (impl->browse_files_last_selected_name);
+      impl->browse_files_last_selected_name = g_strdup (gtk_file_info_get_display_name (info));
+
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+         || 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 one of the folder modes */
+
+      if (change_entry)
+       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->browse_files_last_selected_name);
+
+      return;
+    }
+  else
+    {
+      g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+                 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
+
+      /* Multiple selection, so just clear the entry. */
+
+      g_free (impl->browse_files_last_selected_name);
+      impl->browse_files_last_selected_name = NULL;
+
+      _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+      return;
+    }
+
+ maybe_clear_entry:
+
+  if (impl->browse_files_last_selected_name)
+    {
+      const char *entry_text;
+      int len;
+      gboolean clear_entry;
+
+      entry_text = gtk_entry_get_text (GTK_ENTRY (impl->location_entry));
+      len = strlen (entry_text);
+      if (len != 0)
+       {
+         /* The file chooser entry may have appended a "/" to its text.  So
+          * take it out, and compare the result to the old selection.
+          */
+         if (entry_text[len - 1] == G_DIR_SEPARATOR)
+           {
+             char *tmp;
+
+             tmp = g_strndup (entry_text, len - 1);
+             clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, tmp) == 0);
+             g_free (tmp);
+           }
+         else
+           clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, entry_text) == 0);
+       }
+      else
+       clear_entry = FALSE;
+
+      if (clear_entry)
+       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+    }
 }
 
 static gboolean
@@ -4724,35 +6129,104 @@ gtk_file_chooser_default_set_current_folder (GtkFileChooser    *chooser,
                                             const GtkFilePath *path,
                                             GError           **error)
 {
-  GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
-  gboolean result;
+  return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, error);
+}
 
-  g_assert (path != NULL);
 
-  if (impl->local_only &&
-      !gtk_file_system_path_is_local (impl->file_system, path))
+struct UpdateCurrentFolderData
+{
+  GtkFileChooserDefault *impl;
+  GtkFilePath *path;
+  gboolean keep_trail;
+  GtkFilePath *original_path;
+  GError *original_error;
+};
+
+static void
+update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
+                                  const GtkFileInfo   *info,
+                                  const GError        *error,
+                                  gpointer             user_data)
+{
+  gboolean cancelled = handle->cancelled;
+  struct UpdateCurrentFolderData *data = user_data;
+  GtkFileChooserDefault *impl = data->impl;
+
+  if (handle != impl->update_current_folder_handle)
+    goto out;
+
+  impl->update_current_folder_handle = NULL;
+  impl->reload_state = RELOAD_EMPTY;
+
+  set_busy_cursor (impl, FALSE);
+
+  if (cancelled)
+    goto out;
+
+  if (error)
     {
-      g_set_error (error,
-                  GTK_FILE_CHOOSER_ERROR,
-                  GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
-                  _("Cannot change to folder because it is not local"));
+      GtkFilePath *parent_path;
 
-      return FALSE;
+      if (!data->original_path)
+        {
+         data->original_path = gtk_file_path_copy (data->path);
+         data->original_error = g_error_copy (error);
+       }
+
+      /* get parent path and try to change the folder to that */
+      if (gtk_file_system_get_parent (impl->file_system, data->path, &parent_path, NULL) &&
+         parent_path != NULL)
+        {
+         gtk_file_path_free (data->path);
+         data->path = parent_path;
+
+         g_object_unref (handle);
+
+         /* restart the update current folder operation */
+         impl->reload_state = RELOAD_HAS_FOLDER;
+
+         impl->update_current_folder_handle =
+           gtk_file_system_get_info (impl->file_system, data->path,
+                                     GTK_FILE_INFO_IS_FOLDER,
+                                     update_current_folder_get_info_cb,
+                                     data);
+
+         set_busy_cursor (impl, TRUE);
+
+         return;
+       }
+      else
+        {
+         /* error and bail out */
+         error_changing_folder_dialog (impl, data->original_path, data->original_error);
+
+         gtk_file_path_free (data->original_path);
+
+         goto out;
+       }
     }
 
-  /* Test validity of path here.  */
-  if (!check_is_folder (impl->file_system, path, error))
-    return FALSE;
+  if (data->original_path)
+    {
+      error_changing_folder_dialog (impl, data->original_path, data->original_error);
 
-  if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, error))
-    return FALSE;
+      gtk_file_path_free (data->original_path);
+    }
+
+  if (!gtk_file_info_get_is_folder (info))
+    goto out;
+
+  if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), data->path, data->keep_trail, NULL))
+    goto out;
 
-  if (impl->current_folder != path)
+  if (impl->current_folder != data->path)
     {
       if (impl->current_folder)
        gtk_file_path_free (impl->current_folder);
 
-      impl->current_folder = gtk_file_path_copy (path);
+      impl->current_folder = gtk_file_path_copy (data->path);
+
+      impl->reload_state = RELOAD_HAS_FOLDER;
     }
 
   /* Update the widgets that may trigger a folder change themselves.  */
@@ -4768,14 +6242,15 @@ gtk_file_chooser_default_set_current_folder (GtkFileChooser    *chooser,
 
   /* Set the folder on the save entry */
 
-  _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
-                                          impl->current_folder);
+  if (impl->location_entry)
+    _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+                                            impl->current_folder);
 
   /* Create a new list model.  This is slightly evil; we store the result value
    * but perform more actions rather than returning immediately even if it
    * generates an error.
    */
-  result = set_list_model (impl, error);
+  set_list_model (impl, NULL);
 
   /* Refresh controls */
 
@@ -4788,14 +6263,80 @@ gtk_file_chooser_default_set_current_folder (GtkFileChooser    *chooser,
 
   g_signal_emit_by_name (impl, "selection-changed", 0);
 
-  return result;
+out:
+  gtk_file_path_free (data->path);
+  g_free (data);
+
+  g_object_unref (handle);
 }
 
-static GtkFilePath *
-gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
+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);
+  struct UpdateCurrentFolderData *data;
+
+  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_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;
+    }
+
+  if (impl->update_current_folder_handle)
+    gtk_file_system_cancel_operation (impl->update_current_folder_handle);
+
+  /* Test validity of path here.  */
+  data = g_new0 (struct UpdateCurrentFolderData, 1);
+  data->impl = impl;
+  data->path = gtk_file_path_copy (path);
+  data->keep_trail = keep_trail;
+
+  impl->reload_state = RELOAD_HAS_FOLDER;
+
+  impl->update_current_folder_handle =
+    gtk_file_system_get_info (impl->file_system, path, GTK_FILE_INFO_IS_FOLDER,
+                             update_current_folder_get_info_cb,
+                             data);
+
+  set_busy_cursor (impl, TRUE);
+
+  profile_end ("end", NULL);
+  return TRUE;
+}
+
+static GtkFilePath *
+gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
 
+  if (impl->reload_state == RELOAD_EMPTY)
+    {
+      char *current_working_dir;
+      GtkFilePath *path;
+
+      /* We are unmapped, or we had an error while loading the last folder.  We'll return
+       * the $cwd since once we get (re)mapped, we'll load $cwd anyway unless the caller
+       * explicitly calls set_current_folder() on us.
+       */
+      current_working_dir = g_get_current_dir ();
+      path = gtk_file_system_filename_to_path (impl->file_system, current_working_dir);
+      g_free (current_working_dir);
+      return path;
+    }
+
   return gtk_file_path_copy (impl->current_folder);
 }
 
@@ -4808,7 +6349,8 @@ 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);
 
-  _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), name);
+  pending_select_paths_free (impl);
+  _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
 }
 
 static void
@@ -4854,8 +6396,12 @@ gtk_file_chooser_default_select_path (GtkFileChooser    *chooser,
   if (same_path && impl->load_state == LOAD_FINISHED)
     {
       gboolean result;
+      GSList paths;
+
+      paths.data = (gpointer) path;
+      paths.next = NULL;
 
-      result = show_and_select_paths (impl, parent_path, path, NULL, error);
+      result = show_and_select_paths (impl, parent_path, &paths, error);
       gtk_file_path_free (parent_path);
       return result;
     }
@@ -4946,13 +6492,25 @@ 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,
+                 gboolean              *is_folder)
 {
   GtkFileChooserEntry *chooser_entry;
   const GtkFilePath *current_folder;
@@ -4961,21 +6519,40 @@ check_save_entry (GtkFileChooserDefault *impl,
   GError *error;
 
   g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-           || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+           || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+           || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+                || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+               && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
+
+  chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->location_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;
+      *is_folder = FALSE;
 
-  chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
+      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;
+      *is_folder = 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);
@@ -4983,12 +6560,16 @@ 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;
+      *is_folder = FALSE;
+
+      return;
     }
 
-  *is_valid = TRUE;
-  return path;
+  *path_ret = path;
+  *is_well_formed_ret = TRUE;
+  *is_folder = _gtk_file_chooser_entry_get_is_folder (chooser_entry, path);
 }
 
 struct get_paths_closure {
@@ -5026,38 +6607,84 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
   struct get_paths_closure info;
+  GtkWindow *toplevel;
+  GtkWidget *current_focus;
 
   info.impl = impl;
   info.result = NULL;
   info.path_from_entry = NULL;
 
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-      || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-    {
-      gboolean is_valid, is_empty;
-
-      info.path_from_entry = check_save_entry (impl, &is_valid, &is_empty);
-      if (!is_valid && !is_empty)
-       return NULL;
-    }
+  toplevel = get_toplevel (GTK_WIDGET (impl));
+  if (toplevel)
+    current_focus = gtk_window_get_focus (toplevel);
+  else
+    current_focus = NULL;
 
-  if (!info.path_from_entry || impl->select_multiple)
+  if (current_focus == impl->browse_files_tree_view)
     {
       GtkTreeSelection *selection;
 
+    file_list:
+
       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
       gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
+
+      /* If there is no selection in the file list, we probably have this situation:
+       *
+       * 1. The user typed a filename in the SAVE filename entry ("foo.txt").
+       * 2. He then double-clicked on a folder ("bar") in the file list
+       *
+       * So we want the selection to be "bar/foo.txt".  Jump to the case for the
+       * filename entry to see if that is the case.
+       */
+      if (info.result == NULL && impl->location_entry)
+       goto file_entry;
     }
+  else if (impl->location_entry && current_focus == impl->location_entry)
+    {
+      gboolean is_well_formed, is_empty, is_file_part_empty, is_folder;
+
+    file_entry:
 
-  if (info.path_from_entry)
-    info.result = g_slist_prepend (info.result, info.path_from_entry);
+      check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
+
+      if (is_empty)
+       goto out;
+
+      if (!is_well_formed)
+       return NULL;
+
+      if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+       {
+         gtk_file_path_free (info.path_from_entry);
+         return NULL;
+       }
+
+      g_assert (info.path_from_entry != NULL);
+      info.result = g_slist_prepend (info.result, info.path_from_entry);
+    }
+  else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
+    goto file_list;
+  else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
+    goto file_entry;
+  else
+    {
+    /* The focus is on a dialog's action area button or something else */
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+         || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+       goto file_entry;
+      else
+       goto file_list; 
+    }
+
+ out:
 
   /* If there's no folder selected, and we're in SELECT_FOLDER mode, then we
    * fall back to the current directory */
   if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
       info.result == NULL)
     {
-      info.result = g_slist_prepend (info.result, gtk_file_path_copy (impl->current_folder));
+      info.result = g_slist_prepend (info.result, _gtk_file_chooser_get_current_folder_path (chooser));
     }
 
   return g_slist_reverse (info.result);
@@ -5106,8 +6733,7 @@ gtk_file_chooser_default_add_filter (GtkFileChooser *chooser,
       return;
     }
 
-  g_object_ref (filter);
-  gtk_object_sink (GTK_OBJECT (filter));
+  g_object_ref_sink (filter);
   impl->filters = g_slist_append (impl->filters, filter);
 
   name = gtk_file_filter_get_name (filter);
@@ -5151,7 +6777,9 @@ gtk_file_chooser_default_remove_filter (GtkFileChooser *chooser,
 
   /* Remove row from the combo box */
   model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
-  gtk_tree_model_iter_nth_child  (model, &iter, NULL, filter_index);
+  if (!gtk_tree_model_iter_nth_child  (model, &iter, NULL, filter_index))
+    g_assert_not_reached ();
+
   gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
 
   g_object_unref (filter);
@@ -5176,30 +6804,108 @@ shortcuts_get_pos_for_shortcut_folder (GtkFileChooserDefault *impl,
   return pos + shortcuts_get_index (impl, SHORTCUTS_SHORTCUTS);
 }
 
+struct AddShortcutData
+{
+  GtkFileChooserDefault *impl;
+  GtkFilePath *path;
+};
+
+static void
+add_shortcut_get_info_cb (GtkFileSystemHandle *handle,
+                         const GtkFileInfo   *info,
+                         const GError        *error,
+                         gpointer             user_data)
+{
+  int pos;
+  gboolean cancelled = handle->cancelled;
+  struct AddShortcutData *data = user_data;
+
+  if (!g_slist_find (data->impl->loading_shortcuts, handle))
+    goto out;
+
+  data->impl->loading_shortcuts = g_slist_remove (data->impl->loading_shortcuts, handle);
+
+  if (cancelled || error || !gtk_file_info_get_is_folder (info))
+    goto out;
+
+  pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
+
+  shortcuts_insert_path (data->impl, pos, FALSE, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
+
+out:
+  g_object_unref (data->impl);
+  gtk_file_path_free (data->path);
+  g_free (data);
+
+  g_object_unref (handle);
+}
+
 static gboolean
 gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser    *chooser,
                                              const GtkFilePath *path,
                                              GError           **error)
 {
+  GtkFileSystemHandle *handle;
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
-  gboolean result;
+  struct AddShortcutData *data;
+  GSList *l;
   int pos;
 
-  /* Test validity of path here.  */
-  if (!check_is_folder (impl->file_system, path, error))
-    return FALSE;
+  /* Avoid adding duplicates */
+  pos = shortcut_find_position (impl, path);
+  if (pos >= 0 && pos < shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR))
+    {
+      gchar *uri;
 
-  pos = shortcuts_get_pos_for_shortcut_folder (impl, impl->num_shortcuts);
+      uri = gtk_file_system_path_to_uri (impl->file_system, path);
+      /* translators, "Shortcut" means "Bookmark" here */
+      g_set_error (error,
+                  GTK_FILE_CHOOSER_ERROR,
+                  GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
+                  _("Shortcut %s already exists"),
+                  uri);
+      g_free (uri);
 
-  result = shortcuts_insert_path (impl, pos, FALSE, NULL, path, NULL, FALSE, error);
+      return FALSE;
+    }
 
-  if (result)
-    impl->num_shortcuts++;
+  for (l = impl->loading_shortcuts; l; l = l->next)
+    {
+      GtkFileSystemHandle *h = l->data;
+      GtkFilePath *p;
 
-  if (impl->shortcuts_filter_model)
-    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+      p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
+      if (p && !gtk_file_path_compare (path, p))
+        {
+         gchar *uri;
 
-  return result;
+          uri = gtk_file_system_path_to_uri (impl->file_system, path);
+          g_set_error (error,
+                      GTK_FILE_CHOOSER_ERROR,
+                      GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
+                      _("Shortcut %s already exists"),
+                      uri);
+          g_free (uri);
+
+          return FALSE;
+       }
+    }
+
+  data = g_new0 (struct AddShortcutData, 1);
+  data->impl = g_object_ref (impl);
+  data->path = gtk_file_path_copy (path);
+
+  handle = gtk_file_system_get_info (impl->file_system, path,
+                                    GTK_FILE_INFO_IS_FOLDER,
+                                    add_shortcut_get_info_cb, data);
+
+  if (!handle)
+    return FALSE;
+
+  impl->loading_shortcuts = g_slist_append (impl->loading_shortcuts, handle);
+  g_object_set_data (G_OBJECT (handle), "add-shortcut-path-key", data->path);
+
+  return TRUE;
 }
 
 static gboolean
@@ -5210,9 +6916,24 @@ gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
   int pos;
   GtkTreeIter iter;
+  GSList *l;
   char *uri;
   int i;
 
+  for (l = impl->loading_shortcuts; l; l = l->next)
+    {
+      GtkFileSystemHandle *h = l->data;
+      GtkFilePath *p;
+
+      p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
+      if (p && !gtk_file_path_compare (path, p))
+        {
+         impl->loading_shortcuts = g_slist_remove (impl->loading_shortcuts, h);
+         gtk_file_system_cancel_operation (h);
+          return TRUE;
+       }
+    }
+
   if (impl->num_shortcuts == 0)
     goto out;
 
@@ -5248,6 +6969,7 @@ gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
  out:
 
   uri = gtk_file_system_path_to_uri (impl->file_system, path);
+  /* translators, "Shortcut" means "Bookmark" here */
   g_set_error (error,
               GTK_FILE_CHOOSER_ERROR,
               GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
@@ -5426,6 +7148,421 @@ 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);
+}
+
+struct GetDisplayNameData
+{
+  GtkFileChooserDefault *impl;
+  gchar *file_part;
+};
+
+static void
+confirmation_confirm_get_info_cb (GtkFileSystemHandle *handle,
+                                 const GtkFileInfo   *info,
+                                 const GError        *error,
+                                 gpointer             user_data)
+{
+  gboolean cancelled = handle->cancelled;
+  gboolean should_respond = FALSE;
+  struct GetDisplayNameData *data = user_data;
+
+  if (handle != data->impl->should_respond_get_info_handle)
+    goto out;
+
+  data->impl->should_respond_get_info_handle = NULL;
+
+  if (cancelled)
+    goto out;
+
+  if (error)
+    /* Huh?  Did the folder disappear?  Let the caller deal with it */
+    should_respond = TRUE;
+  else
+    should_respond = confirm_dialog_should_accept_filename (data->impl, data->file_part, gtk_file_info_get_display_name (info));
+
+  set_busy_cursor (data->impl, FALSE);
+  if (should_respond)
+    g_signal_emit_by_name (data->impl, "response-requested");
+
+out:
+  g_object_unref (data->impl);
+  g_free (data->file_part);
+  g_free (data);
+
+  g_object_unref (handle);
+}
+
+/* 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:
+      {
+       struct GetDisplayNameData *data;
+
+       g_assert (file_part != NULL);
+
+       data = g_new0 (struct GetDisplayNameData, 1);
+       data->impl = g_object_ref (impl);
+       data->file_part = g_strdup (file_part);
+
+       if (impl->should_respond_get_info_handle)
+         gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+
+       impl->should_respond_get_info_handle =
+         gtk_file_system_get_info (impl->file_system, parent_path,
+                                   GTK_FILE_INFO_DISPLAY_NAME,
+                                   confirmation_confirm_get_info_cb,
+                                   data);
+       set_busy_cursor (data->impl, TRUE);
+       return FALSE;
+      }
+
+    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;
+    }
+}
+
+static void
+action_create_folder_cb (GtkFileSystemHandle *handle,
+                        const GtkFilePath   *path,
+                        const GError        *error,
+                        gpointer             user_data)
+{
+  gboolean cancelled = handle->cancelled;
+  GtkFileChooserDefault *impl = user_data;
+
+  if (!g_slist_find (impl->pending_handles, handle))
+    goto out;
+
+  impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
+
+  set_busy_cursor (impl, FALSE);
+
+  if (cancelled)
+    goto out;
+
+  if (error)
+    error_creating_folder_dialog (impl, path, g_error_copy (error));
+  else
+    g_signal_emit_by_name (impl, "response-requested");
+
+out:
+  g_object_unref (impl);
+  g_object_unref (handle);
+}
+
+struct FileExistsData
+{
+  GtkFileChooserDefault *impl;
+  gboolean file_exists_and_is_not_folder;
+  GtkFilePath *parent_path;
+  GtkFilePath *path;
+};
+
+static void
+save_entry_get_info_cb (GtkFileSystemHandle *handle,
+                       const GtkFileInfo   *info,
+                       const GError        *error,
+                       gpointer             user_data)
+{
+  gboolean parent_is_folder;
+  gboolean cancelled = handle->cancelled;
+  struct FileExistsData *data = user_data;
+
+  if (handle != data->impl->should_respond_get_info_handle)
+    goto out;
+
+  data->impl->should_respond_get_info_handle = NULL;
+
+  set_busy_cursor (data->impl, FALSE);
+
+  if (cancelled)
+    goto out;
+
+  if (!info)
+    parent_is_folder = FALSE;
+  else
+    parent_is_folder = gtk_file_info_get_is_folder (info);
+
+  if (parent_is_folder)
+    {
+      if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+        {
+          if (data->file_exists_and_is_not_folder)
+           {
+             gboolean retval;
+             const char *file_part;
+
+             file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->location_entry));
+             retval = should_respond_after_confirm_overwrite (data->impl, file_part, data->parent_path);
+
+             if (retval)
+               g_signal_emit_by_name (data->impl, "response-requested");
+           }
+         else
+           g_signal_emit_by_name (data->impl, "response-requested");
+       }
+      else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+        {
+         GtkFileSystemHandle *handle;
+
+         g_object_ref (data->impl);
+         handle = gtk_file_system_create_folder (data->impl->file_system,
+                                                 data->path,
+                                                 action_create_folder_cb,
+                                                 data->impl);
+         data->impl->pending_handles = g_slist_append (data->impl->pending_handles, handle);
+         set_busy_cursor (data->impl, TRUE);
+        }
+    }
+  else
+    {
+      /* This will display an error, which is what we want */
+      change_folder_and_display_error (data->impl, data->parent_path);
+    }
+
+out:
+  g_object_unref (data->impl);
+  gtk_file_path_free (data->path);
+  gtk_file_path_free (data->parent_path);
+  g_free (data);
+
+  g_object_unref (handle);
+}
+
+static void
+file_exists_get_info_cb (GtkFileSystemHandle *handle,
+                        const GtkFileInfo   *info,
+                        const GError        *error,
+                        gpointer             user_data)
+{
+  gboolean data_ownership_taken = FALSE;
+  gboolean cancelled = handle->cancelled;
+  gboolean file_exists_and_is_not_folder;
+  struct FileExistsData *data = user_data;
+
+  if (handle != data->impl->file_exists_get_info_handle)
+    goto out;
+
+  data->impl->file_exists_get_info_handle = NULL;
+
+  set_busy_cursor (data->impl, FALSE);
+
+  if (cancelled)
+    goto out;
+
+  file_exists_and_is_not_folder = info && !gtk_file_info_get_is_folder (info);
+
+  if (data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+    /* user typed a filename; we are done */
+    g_signal_emit_by_name (data->impl, "response-requested");
+  else if (data->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 (data->impl, data->path,
+                                                      g_error_copy (error));
+    }
+  else
+    {
+      /* check that everything up to the last component exists */
+
+      data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
+      data_ownership_taken = TRUE;
+
+      if (data->impl->should_respond_get_info_handle)
+       gtk_file_system_cancel_operation (data->impl->should_respond_get_info_handle);
+
+      data->impl->should_respond_get_info_handle =
+       gtk_file_system_get_info (data->impl->file_system,
+                                 data->parent_path,
+                                 GTK_FILE_INFO_IS_FOLDER,
+                                 save_entry_get_info_cb,
+                                 data);
+      set_busy_cursor (data->impl, TRUE);
+    }
+
+out:
+  if (!data_ownership_taken)
+    {
+      g_object_unref (data->impl);
+      gtk_file_path_free (data->path);
+      gtk_file_path_free (data->parent_path);
+      g_free (data);
+    }
+
+  g_object_unref (handle);
+}
+
+static void
+paste_text_received (GtkClipboard          *clipboard,
+                    const gchar           *text,
+                    GtkFileChooserDefault *impl)
+{
+  GtkFilePath *path;
+
+  if (!text)
+    return;
+
+  path = gtk_file_system_uri_to_path (impl->file_system, text);
+  if (!path) 
+    {
+      if (!g_path_is_absolute (text)) 
+       {
+         location_popup_handler (impl, text);
+         return;
+       }
+
+      path = gtk_file_system_filename_to_path (impl->file_system, text);
+      if (!path) 
+       {
+         location_popup_handler (impl, text);
+         return;
+       }
+    }
+
+  if (!gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (impl), path, NULL))
+    location_popup_handler (impl, text);
+
+  gtk_file_path_free (path);
+}
+
+/* Handler for the "location-popup-on-paste" keybinding signal */
+static void
+location_popup_on_paste_handler (GtkFileChooserDefault *impl)
+{
+  GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (impl),
+                                                     GDK_SELECTION_CLIPBOARD);
+  gtk_clipboard_request_text (clipboard,
+                             (GtkClipboardTextReceivedFunc) paste_text_received,
+                             impl);
+}
+
+
 /* Implementation for GtkFileChooserEmbed::should_respond() */
 static gboolean
 gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
@@ -5443,84 +7580,154 @@ 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;
+             switch_to_selected_folder (impl);
+             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)
+  else if ((impl->location_entry != NULL) && (current_focus == impl->location_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:
 
       g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-               || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+               || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+               || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+                    || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+                   && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
 
-      entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
-      path = check_save_entry (impl, &is_valid, &is_empty);
+      entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
+      check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
 
-      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;
       if (is_folder)
        {
-         _gtk_file_chooser_entry_set_file_part (entry, "");
-         change_folder_and_display_error (impl, path);
-         retval = FALSE;
-       }
-      else
-       {
-         /* check that everything up to the last component exists */
-         gtk_file_path_free (path);
-         path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
-         is_folder = check_is_folder (impl->file_system, path, NULL);
-         if (!is_folder)
+         if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+             || 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 if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
+                  || 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;
+           {
+             g_assert_not_reached ();
+             retval = FALSE;
+           }
+       }
+      else
+       {
+         struct FileExistsData *data;
+
+         /* We need to check whether path exists and is not a folder */
+
+         data = g_new0 (struct FileExistsData, 1);
+         data->impl = g_object_ref (impl);
+         data->path = gtk_file_path_copy (path);
+         data->parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
+
+         if (impl->file_exists_get_info_handle)
+           gtk_file_system_cancel_operation (impl->file_exists_get_info_handle);
+
+         impl->file_exists_get_info_handle =
+           gtk_file_system_get_info (impl->file_system, path,
+                                     GTK_FILE_INFO_IS_FOLDER,
+                                     file_exists_get_info_cb,
+                                     data);
+
+         set_busy_cursor (impl, TRUE);
+         retval = FALSE;
+
+         if (error != NULL)
+           g_error_free (error);
        }
 
       gtk_file_path_free (path);
@@ -5552,6 +7759,13 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
        */
       goto file_list;
     }
+  else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
+    {
+      /* The focus is on a dialog's action area button, *and* the widget that
+       * was focused immediately before it is the location entry.
+       */
+      goto save_entry;
+    }
   else
     /* The focus is on a dialog's action area button or something else */
     if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
@@ -5575,16 +7789,22 @@ 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)
-    widget = impl->browse_files_tree_view;
+    {
+      if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+       widget = impl->browse_files_tree_view;
+      else
+       widget = impl->location_entry;
+    }
   else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
           || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-    widget = impl->save_file_name_entry;
+    widget = impl->location_entry;
   else
     {
       g_assert_not_reached ();
       widget = NULL;
     }
 
+  g_assert (widget != NULL);
   gtk_widget_grab_focus (widget);
 }
 
@@ -5607,8 +7827,7 @@ set_current_filter (GtkFileChooserDefault *impl,
       impl->current_filter = filter;
       if (impl->current_filter)
        {
-         g_object_ref (impl->current_filter);
-         gtk_object_sink (GTK_OBJECT (filter));
+         g_object_ref_sink (impl->current_filter);
        }
 
       if (impl->filters)
@@ -5645,7 +7864,9 @@ check_preview_change (GtkFileChooserDefault *impl)
       GtkTreeIter iter;
       GtkTreeIter child_iter;
 
-      gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
+      if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path))
+       g_assert_not_reached ();
+
       gtk_tree_path_free (cursor_path);
 
       gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
@@ -5687,6 +7908,51 @@ check_preview_change (GtkFileChooserDefault *impl)
     }
 }
 
+static void
+shortcuts_activate_volume_mount_cb (GtkFileSystemHandle *handle,
+                                   GtkFileSystemVolume *volume,
+                                   const GError        *error,
+                                   gpointer             data)
+{
+  GtkFilePath *path;
+  gboolean cancelled = handle->cancelled;
+  GtkFileChooserDefault *impl = data;
+
+  if (handle != impl->shortcuts_activate_iter_handle)
+    goto out;
+
+  impl->shortcuts_activate_iter_handle = NULL;
+
+  set_busy_cursor (impl, FALSE);
+
+  if (cancelled)
+    goto out;
+
+  if (error)
+    {
+      char *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);
+
+      goto out;
+    }
+
+  path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+  if (path != NULL)
+    {
+      change_folder_and_display_error (impl, path);
+      gtk_file_path_free (path);
+    }
+
+out:
+  g_object_unref (impl);
+  g_object_unref (handle);
+}
+
+
 /* Activates a volume by mounting it if necessary and then switching to its
  * base path.
  */
@@ -5703,41 +7969,63 @@ shortcuts_activate_volume (GtkFileChooserDefault *impl,
 
   if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
     {
-      GError *error;
-      gboolean result;
-
       set_busy_cursor (impl, TRUE);
 
-      error = NULL;
-      result = gtk_file_system_volume_mount (impl->file_system, volume, &error);
+      impl->shortcuts_activate_iter_handle =
+        gtk_file_system_volume_mount (impl->file_system, volume,
+                                     shortcuts_activate_volume_mount_cb,
+                                     g_object_ref (impl));
+    }
+  else
+    {
+      path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+      if (path != NULL)
+        {
+          change_folder_and_display_error (impl, path);
+          gtk_file_path_free (path);
+        }
+    }
 
-      if (!result)
-       {
-         char *msg;
+  g_object_unref (impl);
+}
 
-         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);
-       }
+/* Opens the folder or volume at the specified iter in the shortcuts model */
+struct ShortcutsActivateData
+{
+  GtkFileChooserDefault *impl;
+  GtkFilePath *path;
+};
 
-      set_busy_cursor (impl, FALSE);
+static void
+shortcuts_activate_get_info_cb (GtkFileSystemHandle *handle,
+                               const GtkFileInfo   *info,
+                               const GError        *error,
+                               gpointer             user_data)
+{
+  gboolean cancelled = handle->cancelled;
+  struct ShortcutsActivateData *data = user_data;
 
-      if (!result)
-       goto out;
-    }
+  if (handle != data->impl->shortcuts_activate_iter_handle)
+    goto out;
 
-  path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
-  change_folder_and_display_error (impl, path);
-  gtk_file_path_free (path);
+  data->impl->shortcuts_activate_iter_handle = NULL;
 
- out:
+  if (cancelled)
+    goto out;
 
-  g_object_unref (impl);
+  if (!error && gtk_file_info_get_is_folder (info))
+    change_folder_and_display_error (data->impl, data->path);
+  else
+    gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl), data->path, NULL);
+
+out:
+  g_object_unref (data->impl);
+  gtk_file_path_free (data->path);
+  g_free (data);
+
+  g_object_unref (handle);
 }
 
-/* Opens the folder or volume at the specified iter in the shortcuts model */
 static void
 shortcuts_activate_iter (GtkFileChooserDefault *impl,
                         GtkTreeIter           *iter)
@@ -5745,6 +8033,9 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
   gpointer col_data;
   gboolean is_volume;
 
+  if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY && impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
+    _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+
   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
                      SHORTCUTS_COL_DATA, &col_data,
                      SHORTCUTS_COL_IS_VOLUME, &is_volume,
@@ -5753,6 +8044,12 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
   if (!col_data)
     return; /* We are on a separator */
 
+  if (impl->shortcuts_activate_iter_handle)
+    {
+      gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
+      impl->shortcuts_activate_iter_handle = NULL;
+    }
+
   if (is_volume)
     {
       GtkFileSystemVolume *volume;
@@ -5763,10 +8060,16 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
     }
   else
     {
-      const GtkFilePath *file_path;
+      struct ShortcutsActivateData *data;
 
-      file_path = col_data;
-      change_folder_and_display_error (impl, file_path);
+      data = g_new0 (struct ShortcutsActivateData, 1);
+      data->impl = g_object_ref (impl);
+      data->path = gtk_file_path_copy (col_data);
+
+      impl->shortcuts_activate_iter_handle =
+        gtk_file_system_get_info (impl->file_system, data->path,
+                                 GTK_FILE_INFO_IS_FOLDER,
+                                 shortcuts_activate_get_info_cb, data);
     }
 }
 
@@ -5810,6 +8113,13 @@ shortcuts_key_press_event_cb (GtkWidget             *widget,
       return TRUE;
     }
 
+  if ((event->keyval == GDK_F2)
+      && (event->state & modifiers) == 0)
+    {
+      rename_selected_bookmark (impl);
+      return TRUE;
+    }
+
   return FALSE;
 }
 
@@ -5861,24 +8171,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);
@@ -5921,9 +8226,13 @@ list_row_activated (GtkTreeView           *tree_view,
 static void
 path_bar_clicked (GtkPathBar            *path_bar,
                  GtkFilePath           *file_path,
+                 GtkFilePath           *child_path,
                  gboolean               child_is_hidden,
                  GtkFileChooserDefault *impl)
 {
+  if (child_path)
+    pending_select_paths_add (impl, child_path);
+
   if (!change_folder_and_display_error (impl, file_path))
     return;
 
@@ -5961,6 +8270,8 @@ list_icon_data_func (GtkTreeViewColumn *tree_column,
   GdkPixbuf *pixbuf;
   const GtkFileInfo *info; 
   gboolean sensitive = TRUE;
+
+  profile_start ("start", NULL);
   
   info = get_list_file_info (impl, iter);
 
@@ -5971,9 +8282,14 @@ list_icon_data_func (GtkTreeViewColumn *tree_column,
 
   if (path)
     {
-      /* FIXME: NULL GError */
-      pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
-                                           impl->icon_size, NULL);
+      pixbuf = NULL;
+
+      if (info)
+        {
+          /* FIXME: NULL GError */
+         pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
+                                             impl->icon_size, NULL);
+       }
     }
   else
     {
@@ -5992,6 +8308,8 @@ list_icon_data_func (GtkTreeViewColumn *tree_column,
     
   if (pixbuf)
     g_object_unref (pixbuf);
+
+  profile_end ("end", NULL);
 }
 
 static void
@@ -6043,21 +8361,25 @@ list_size_data_func (GtkTreeViewColumn *tree_column,
 
   if (!info || gtk_file_info_get_is_folder (info)) 
     {
-      g_object_set (cell,"sensitive", sensitive, NULL);
+      g_object_set (cell,
+                   "text", NULL,
+                   "sensitive", sensitive,
+                   NULL);
       return;
     }
 
   size = gtk_file_info_get_size (info);
-
+#if 0
   if (size < (gint64)1024)
     str = g_strdup_printf (ngettext ("%d byte", "%d bytes", (gint)size), (gint)size);
   else if (size < (gint64)1024*1024)
-    str = g_strdup_printf (_("%.1f K"), size / (1024.));
+    str = g_strdup_printf (_("%.1f KB"), size / (1024.));
   else if (size < (gint64)1024*1024*1024)
-    str = g_strdup_printf (_("%.1f M"), size / (1024.*1024.));
+    str = g_strdup_printf (_("%.1f MB"), size / (1024.*1024.));
   else
-    str = g_strdup_printf (_("%.1f G"), size / (1024.*1024.*1024.));
-
+    str = g_strdup_printf (_("%.1f GB"), size / (1024.*1024.*1024.));
+#endif
+  str = g_strdup_printf ("%" G_GINT64_FORMAT, size);
   if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     sensitive = FALSE;
@@ -6065,6 +8387,7 @@ list_size_data_func (GtkTreeViewColumn *tree_column,
   g_object_set (cell,
                "text", str,
                "sensitive", sensitive,
+               "alignment", PANGO_ALIGN_RIGHT,
                NULL);
 
   g_free (str);
@@ -6081,7 +8404,7 @@ list_mtime_data_func (GtkTreeViewColumn *tree_column,
 {
   GtkFileChooserDefault *impl;
   const GtkFileInfo *info;
-  GtkFileTime time_mtime, time_now;
+  GtkFileTime time_mtime;
   GDate mtime, now;
   int days_diff;
   char buf[256];
@@ -6100,28 +8423,34 @@ list_mtime_data_func (GtkTreeViewColumn *tree_column,
     }
 
   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;
+      time_t time_now;
+      g_date_set_time_t (&mtime, time_mtime);
+      time_now = time (NULL);
+      g_date_set_time_t (&now, 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 ||
@@ -6142,258 +8471,65 @@ _gtk_file_chooser_default_new (const char *file_system)
                        NULL);
 }
 
-static GtkWidget *
-location_entry_create (GtkFileChooserDefault *impl,
-                      const gchar           *path)
-{
-  GtkWidget *entry;
-
-  entry = _gtk_file_chooser_entry_new (TRUE);
-  /* Pick a good width for the entry */
-  gtk_entry_set_width_chars (GTK_ENTRY (entry), 30);
-  gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
-  _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (entry), impl->file_system);
-  _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (entry), impl->action);
-  if (path[0])
-    {
-      _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry), 
-                                              gtk_file_path_new_steal ((gchar *)path));
-      _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry), path);
-    }
-  else
-    {
-      _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry), impl->current_folder);
-      if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
-         || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
-       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry), "");
-      else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-              || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry),
-                                              gtk_entry_get_text (GTK_ENTRY (impl->save_file_name_entry)));
-      else
-       g_assert_not_reached ();
-    }
-
-  return GTK_WIDGET (entry);
-}
-
-static gboolean
-update_from_entry (GtkFileChooserDefault *impl,
-                  GtkWindow             *parent,
-                  GtkFileChooserEntry   *chooser_entry)
+static void
+location_set_user_text (GtkFileChooserDefault *impl,
+                       const gchar           *path)
 {
-  const GtkFilePath *folder_path;
-  const char *file_part;
-
-  folder_path = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
-  file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
-
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN && !folder_path)
-    {
-      error_message_with_parent (parent,
-                                _("Cannot change folder"),
-                                _("The folder you specified is an invalid path."));
-      return FALSE;
-    }
-
-  if (file_part[0] == '\0')
-    return change_folder_and_display_error (impl, folder_path);
-  else
-    {
-      GtkFileFolder *folder = NULL;
-      GtkFilePath *subfolder_path = NULL;
-      GtkFileInfo *info = NULL;
-      GError *error;
-      gboolean result;
-
-      result = FALSE;
-
-      /* If the file part is non-empty, we need to figure out if it refers to a
-       * folder within folder. We could optimize the case here where the folder
-       * is already loaded for one of our tree models.
-       */
-
-      error = NULL;
-      folder = gtk_file_system_get_folder (impl->file_system, folder_path, GTK_FILE_INFO_IS_FOLDER, &error);
-
-      if (!folder)
-       {
-         error_getting_info_dialog (impl, folder_path, error);
-         goto out;
-       }
-
-      error = NULL;
-      subfolder_path = gtk_file_system_make_path (impl->file_system, folder_path, file_part, &error);
-
-      if (!subfolder_path)
-       {
-         char *msg;
-         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'"),
-                                uri, file_part);
-         error_message (impl, msg, error->message);
-         g_free (uri);
-         g_free (msg);
-         goto out;
-       }
-
-      error = NULL;
-      info = gtk_file_folder_get_info (folder, subfolder_path, &error);
-
-      if (!info)
-       {
-         if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-             || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-           {
-             if (!change_folder_and_display_error (impl, folder_path))
-               goto out;
-
-             gtk_file_chooser_default_set_current_name (GTK_FILE_CHOOSER (impl), file_part);
-           }
-         else
-           error_getting_info_dialog (impl, subfolder_path, error);
-
-         goto out;
-       }
-
-      if (gtk_file_info_get_is_folder (info))
-       result = change_folder_and_display_error (impl, subfolder_path);
-      else
-       {
-         GError *error;
-
-         error = NULL;
-         result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (impl), subfolder_path, &error);
-         if (!result)
-           error_dialog (impl, _("Could not select item"),
-                         subfolder_path, error);
-       }
-
-    out:
-
-      if (folder)
-       g_object_unref (folder);
-
-      gtk_file_path_free (subfolder_path);
-
-      if (info)
-       gtk_file_info_free (info);
-
-      return result;
-    }
-
-  g_assert_not_reached ();
+  _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), path);
+  gtk_editable_set_position (GTK_EDITABLE (impl->location_entry), -1);
 }
 
 static void
 location_popup_handler (GtkFileChooserDefault *impl,
                        const gchar           *path)
 {
-  GtkWidget *dialog;
-  GtkWindow *toplevel;
-  GtkWidget *hbox;
-  GtkWidget *label;
-  GtkWidget *entry;
-  gboolean refocus;
-  const char *title;
-  const char *accept_stock;
-
-  /* Create dialog */
-
-  toplevel = get_toplevel (GTK_WIDGET (impl));
-
   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
       || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
     {
-      title = _("Open Location");
-      accept_stock = GTK_STOCK_OPEN;
-    }
-  else
-    {
-      g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-               || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
-      title = _("Save in Location");
-      accept_stock = GTK_STOCK_SAVE;
-    }
-
-  dialog = gtk_dialog_new_with_buttons (title,
-                                       toplevel,
-                                       GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
-                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                       accept_stock, GTK_RESPONSE_ACCEPT,
-                                       NULL);
-  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);
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
-
-  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
-                                          GTK_RESPONSE_ACCEPT,
-                                          GTK_RESPONSE_CANCEL,
-                                          -1);
-
-  hbox = gtk_hbox_new (FALSE, 12);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
-  gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
-
-  label = gtk_label_new_with_mnemonic (_("_Location:"));
-  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
-  entry = location_entry_create (impl, path);
-
-  gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
-  gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+      LocationMode new_mode;
 
-  /* Run */
-
-  gtk_widget_show_all (dialog);
-  /* If the dialog is brought up by typing the first characters
-   * of a path, unselect the text in the entry, so that you can
-   * just type on without erasing the initial part.
-   */
-  if (path[0])
-    gtk_editable_select_region (GTK_EDITABLE (entry), -1, -1);
-
-  refocus = TRUE;
+      if (path != NULL)
+       {
+         /* since the user typed something, we unconditionally want to turn on the entry */
+         new_mode = LOCATION_MODE_FILENAME_ENTRY;
+       }
+      else if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+       new_mode = LOCATION_MODE_FILENAME_ENTRY;
+      else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+       new_mode = LOCATION_MODE_PATH_BAR;
+      else
+       {
+         g_assert_not_reached ();
+         return;
+       }
 
-  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
-    {
-      if (update_from_entry (impl, GTK_WINDOW (dialog), GTK_FILE_CHOOSER_ENTRY (entry)))
+      location_mode_set (impl, new_mode, TRUE);
+      if (new_mode == LOCATION_MODE_FILENAME_ENTRY)
        {
-         if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
-             || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
-           {
-             gtk_widget_grab_focus (impl->browse_files_tree_view);
-           }
+         if (path != NULL)
+           location_set_user_text (impl, path);
          else
            {
-             g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-                       || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
-             gtk_widget_grab_focus (impl->save_file_name_entry);
+             location_entry_set_initial_text (impl);
+             gtk_editable_select_region (GTK_EDITABLE (impl->location_entry), 0, -1);
            }
-         refocus = FALSE;
        }
     }
-
-  if (refocus)
+  else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+          || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     {
-      GtkWindow *toplevel;
-
-      toplevel = get_toplevel (GTK_WIDGET (impl));
-      if (toplevel && toplevel->focus_widget)
-       gtk_widget_grab_focus (toplevel->focus_widget);
+      gtk_widget_grab_focus (impl->location_entry);
+      if (path != NULL)
+       location_set_user_text (impl, path);
     }
-
-  gtk_widget_destroy (dialog);
+  else
+    g_assert_not_reached ();
 }
 
 /* Handler for the "up-folder" keybinding signal */
 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));
 }
 
@@ -6404,23 +8540,56 @@ down_folder_handler (GtkFileChooserDefault *impl)
   _gtk_path_bar_down (GTK_PATH_BAR (impl->browse_path_bar));
 }
 
-/* Handler for the "home-folder" keybinding signal */
+/* Switches to the shortcut in the specified index */
 static void
-home_folder_handler (GtkFileChooserDefault *impl)
+switch_to_shortcut (GtkFileChooserDefault *impl,
+                   int pos)
 {
-  int pos;
   GtkTreeIter iter;
 
-  if (!impl->has_home)
-    return; /* Should we put up an error dialog? */
-
-  pos = shortcuts_get_index (impl, SHORTCUTS_HOME);
   if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
     g_assert_not_reached ();
 
   shortcuts_activate_iter (impl, &iter);
 }
 
+/* Handler for the "home-folder" keybinding signal */
+static void
+home_folder_handler (GtkFileChooserDefault *impl)
+{
+  if (impl->has_home)
+    switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_HOME));
+}
+
+/* Handler for the "desktop-folder" keybinding signal */
+static void
+desktop_folder_handler (GtkFileChooserDefault *impl)
+{
+  if (impl->has_desktop)
+    switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_DESKTOP));
+}
+
+static void
+quick_bookmark_handler (GtkFileChooserDefault *impl,
+                       gint bookmark_index)
+{
+  int bookmark_pos;
+  GtkTreePath *path;
+
+  if (bookmark_index < 0 || bookmark_index >= impl->num_bookmarks)
+    return;
+
+  bookmark_pos = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS) + bookmark_index;
+
+  path = gtk_tree_path_new_from_indices (bookmark_pos, -1);
+  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
+                               path, NULL,
+                               FALSE, 0.0, 0.0);
+  gtk_tree_path_free (path);
+
+  switch_to_shortcut (impl, bookmark_pos);
+}
+
 \f
 
 /* Drag and drop interfaces */
@@ -6494,14 +8663,11 @@ 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"