]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilechooserdefault.c
Add docs for new ports.
[~andy/gtk] / gtk / gtkfilechooserdefault.c
index e78aeab68883e1ec0e510191f48197e32b15781b..4843f28b253cdfecfa2b46f0d9db235d0c5c14ad 100644 (file)
@@ -32,6 +32,7 @@
 #include "gtkentry.h"
 #include "gtkeventbox.h"
 #include "gtkexpander.h"
+#include "gtkfilechooserprivate.h"
 #include "gtkfilechooserdefault.h"
 #include "gtkfilechooserembed.h"
 #include "gtkfilechooserentry.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"
 
 
 \f
 
-/* Profiling stuff */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef G_OS_WIN32
+#include <io.h>
+#endif
 
+/* Profiling stuff */
 #define PROFILE_FILE_CHOOSER
 #ifdef PROFILE_FILE_CHOOSER
-#include <unistd.h>
+
+
+#ifndef F_OK 
+#define F_OK 0
+#endif
 
 #define PROFILE_INDENT 4
 static int profile_indent;
@@ -107,9 +114,9 @@ _gtk_file_chooser_profile_log (const char *func, int indent, const char *msg1, c
     profile_add_indent (indent);
 
   if (profile_indent == 0)
-    str = g_strdup_printf ("MARK: %s %s %s", func, msg1 ? msg1 : "", msg2 ? msg2 : "");
+    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, msg1 ? msg1 : "", msg2 ? msg2 : "");
+    str = g_strdup_printf ("MARK: %*c %s %s %s", profile_indent - 1, ' ', func ? func : "", msg1 ? msg1 : "", msg2 ? msg2 : "");
 
   access (str, F_OK);
   g_free (str);
@@ -135,13 +142,6 @@ typedef struct _GtkFileChooserDefaultClass 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
@@ -149,117 +149,14 @@ 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_shortcuts_popup_menu;
-  GtkWidget *browse_shortcuts_popup_menu_remove_item;
-  GtkWidget *browse_shortcuts_popup_menu_rename_item;
-  GtkWidget *browse_files_tree_view;
-  GtkWidget *browse_files_popup_menu;
-  GtkWidget *browse_files_popup_menu_add_shortcut_item;
-  GtkWidget *browse_files_popup_menu_hidden_files_item;
-  GtkWidget *browse_new_folder_button;
-  GtkWidget *browse_path_bar;
-
-  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;
-
-  GtkTreeModelSort *sort_model;
-
-  LoadState load_state;
-  guint load_timeout_id;
-
-  GSList *pending_select_paths;
-
-  GtkFileFilter *current_filter;
-  GSList *filters;
-
-  GtkTooltips *tooltips;
-
-  gboolean has_home;
-  gboolean has_desktop;
-
-  int num_volumes;
-  int num_shortcuts;
-  int num_bookmarks;
-
-  gulong volumes_changed_id;
-  gulong bookmarks_changed_id;
-
-  GtkFilePath *current_volume_path;
-  GtkFilePath *current_folder;
-  GtkFilePath *preview_path;
-  char *preview_display_name;
-
-  GtkTreeViewColumn *list_name_column;
-  GtkCellRenderer *list_name_renderer;
-
-  GSource *edited_idle;
-  char *edited_new_text;
-
-  gulong settings_signal_id;
-  int icon_size;
-
-  gulong toplevel_set_focus_id;
-  GtkWidget *toplevel_last_focus_widget;
-
-#if 0
-  GdkDragContext *shortcuts_drag_context;
-  GSource *shortcuts_drag_outside_idle;
-#endif
-
-  /* Flags */
-
-  guint local_only : 1;
-  guint preview_widget_active : 1;
-  guint use_preview_label : 1;
-  guint select_multiple : 1;
-  guint show_hidden : 1;
-  guint do_overwrite_confirmation : 1;
-  guint list_sort_ascending : 1;
-  guint changing_folder : 1;
-  guint shortcuts_current_folder_active : 1;
-
-#if 0
-  guint shortcuts_drag_outside : 1;
-#endif
-};
-
 /* Signal IDs */
 enum {
   LOCATION_POPUP,
   UP_FOLDER,
   DOWN_FOLDER,
   HOME_FOLDER,
+  DESKTOP_FOLDER,
+  QUICK_BOOKMARK,
   LAST_SIGNAL
 };
 
@@ -363,6 +260,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,
@@ -417,6 +315,9 @@ static void location_popup_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,
@@ -470,6 +371,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);
 
@@ -574,7 +476,7 @@ _gtk_file_chooser_default_get_type (void)
        NULL                                                           /* interface_data */
       };
 
-      file_chooser_default_type = g_type_register_static (GTK_TYPE_VBOX, "GtkFileChooserDefault",
+      file_chooser_default_type = g_type_register_static (GTK_TYPE_VBOX, I_("GtkFileChooserDefault"),
                                                         &file_chooser_default_info, 0);
 
       g_type_add_interface_static (file_chooser_default_type,
@@ -591,9 +493,13 @@ _gtk_file_chooser_default_get_type (void)
 static void
 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;
+  int i;
 
   parent_class = g_type_class_peek_parent (class);
 
@@ -605,12 +511,13 @@ 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),
@@ -618,7 +525,7 @@ gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                             _gtk_marshal_VOID__STRING,
                             G_TYPE_NONE, 1, G_TYPE_STRING);
   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),
@@ -626,7 +533,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),
@@ -634,13 +541,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);
 
@@ -653,6 +576,17 @@ 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_Up, GDK_MOD1_MASK,
@@ -684,6 +618,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);
 
@@ -727,7 +671,9 @@ static void
 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;
@@ -735,13 +681,13 @@ 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;
 
   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);
 }
@@ -926,6 +872,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);
 }
@@ -1065,6 +1015,8 @@ 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:
@@ -1333,12 +1285,6 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
     }
   else
     {
-      if (!check_is_folder (impl->file_system, path, error))
-       {
-         profile_end ("end - is not folder", NULL);
-         return FALSE;
-       }
-
       if (label)
        label_copy = g_strdup (label);
       else
@@ -1404,7 +1350,7 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
   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);
+  impl->has_home = shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, NULL, FALSE, &error);
   if (!impl->has_home)
     error_getting_info_dialog (impl, home_path, error);
 
@@ -1418,6 +1364,7 @@ static void
 shortcuts_append_desktop (GtkFileChooserDefault *impl)
 {
   char *name;
+  const char *home;
   GtkFilePath *path;
 
   profile_start ("start", NULL);
@@ -1425,7 +1372,7 @@ shortcuts_append_desktop (GtkFileChooserDefault *impl)
 #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)
     {
       profile_end ("end - no home directory!?", NULL);
@@ -1467,10 +1414,8 @@ 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))
@@ -1599,14 +1544,22 @@ 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;
+                   }
+               }
            }
        }
 
@@ -1781,7 +1734,7 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
       impl->shortcuts_current_folder_active = success;
     }
 
-  if (success)
+  if (success && impl->save_folder_combo != NULL)
     gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
 }
 
@@ -1842,7 +1795,6 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
       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,
@@ -2050,8 +2002,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)
@@ -2068,7 +2020,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;
@@ -2082,17 +2038,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))
     {
@@ -2869,6 +2819,7 @@ shortcuts_reorder (GtkFileChooserDefault *impl,
   const GtkFilePath *file_path;
   GtkFilePath *file_path_copy;
   GError *error;
+  gchar *name;
 
   /* Get the selected path */
 
@@ -2884,12 +2835,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 */
 
@@ -2903,7 +2855,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);
 
@@ -2947,9 +2902,9 @@ 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");
@@ -2990,10 +2945,14 @@ 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;
     }
   
@@ -3022,9 +2981,9 @@ remove_shortcut_cb (GtkMenuItem           *item,
   remove_selected_bookmarks (impl);
 }
 
+/* Rename the selected bookmark */
 static void
-rename_shortcut_cb (GtkMenuItem           *item,
-                   GtkFileChooserDefault *impl)
+rename_selected_bookmark (GtkFileChooserDefault *impl)
 {
   GtkTreeIter iter;
   GtkTreePath *path;
@@ -3046,6 +3005,13 @@ rename_shortcut_cb (GtkMenuItem           *item,
     }
 }
 
+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)
@@ -3129,9 +3095,22 @@ 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;
 }
@@ -3149,7 +3128,9 @@ shortcuts_edited (GtkCellRenderer       *cell,
   g_object_set (cell, "editable", FALSE, NULL);
 
   path = gtk_tree_path_new_from_string (path_string);
-  gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path);
+  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);
@@ -3186,14 +3167,17 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
   /* 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);
-  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);
+  /* 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);
 
@@ -3246,7 +3230,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);
@@ -3342,10 +3327,14 @@ trap_activate_cb (GtkWidget   *widget,
 
   modifiers = gtk_accelerator_get_default_mod_mask ();
   
-  if (event->keyval == GDK_slash &&
-      ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
+  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;
     }
 
@@ -3353,7 +3342,7 @@ trap_activate_cb (GtkWidget   *widget,
        || event->keyval == GDK_ISO_Enter
        || event->keyval == GDK_KP_Enter
        || event->keyval == GDK_space)
-      && ((event->state && modifiers) == 0)
+      && ((event->state & modifiers) == 0)
       && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
           impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
     {
@@ -3447,7 +3436,7 @@ file_list_drag_data_received_cb (GtkWidget          *widget,
   chooser = GTK_FILE_CHOOSER (data);
   
   /* Parse the text/uri-list string, navigate to the first one */
-  uris = g_uri_list_extract_uris (selection_data->data);
+  uris = g_uri_list_extract_uris ((const char *) selection_data->data);
   if (uris[0]) 
     {
       uri = uris[0];
@@ -3667,9 +3656,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;
 }
@@ -3694,7 +3693,10 @@ 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);
@@ -3837,21 +3839,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);
@@ -3886,6 +3873,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,
@@ -3949,7 +3937,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;
@@ -3957,6 +3945,9 @@ save_widgets_create (GtkFileChooserDefault *impl)
   GtkWidget *widget;
   GtkWidget *alignment;
 
+  if (impl->save_widgets != NULL)
+    return;
+
   vbox = gtk_vbox_new (FALSE, 12);
 
   table = gtk_table_new (2, 2, FALSE);
@@ -4014,7 +4005,25 @@ 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->save_file_name_entry = NULL;
+  impl->save_folder_label = NULL;
+  impl->save_folder_combo = NULL;
+  impl->save_expander = NULL;
 }
 
 /* Creates the main hpaned with the widgets shared by Open and Save mode */
@@ -4022,6 +4031,7 @@ static GtkWidget *
 browse_widgets_create (GtkFileChooserDefault *impl)
 {
   GtkWidget *vbox;
+  GtkWidget *hbox;
   GtkWidget *hpaned;
   GtkWidget *widget;
   GtkSizeGroup *size_group;
@@ -4030,6 +4040,22 @@ browse_widgets_create (GtkFileChooserDefault *impl)
   size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
   vbox = gtk_vbox_new (FALSE, 12);
 
+  /* The path bar and 'Create Folder' button */
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+  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);
+
   /* Paned widget */
   hpaned = gtk_hpaned_new ();
   gtk_widget_show (hpaned);
@@ -4054,6 +4080,8 @@ gtk_file_chooser_default_constructor (GType                  type,
   GtkFileChooserDefault *impl;
   GObject *object;
 
+  profile_start ("start", NULL);
+
   object = parent_class->constructor (type,
                                      n_construct_properties,
                                      construct_params);
@@ -4067,10 +4095,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);
@@ -4082,6 +4106,8 @@ gtk_file_chooser_default_constructor (GType                  type,
   gtk_widget_pop_composite_child ();
   update_appearance (impl);
 
+  profile_end ("end", NULL);
+
   return object;
 }
 
@@ -4259,7 +4285,7 @@ update_appearance (GtkFileChooserDefault *impl)
     {
       const char *text;
 
-      gtk_widget_show (impl->save_widgets);
+      save_widgets_create (impl);
 
       if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
        text = _("Save in _folder:");
@@ -4268,6 +4294,8 @@ update_appearance (GtkFileChooserDefault *impl)
 
       gtk_label_set_text_with_mnemonic (GTK_LABEL (impl->save_folder_label), text);
 
+      _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), impl->action);
+
       if (gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
        {
          gtk_widget_set_sensitive (impl->save_folder_label, FALSE);
@@ -4293,7 +4321,7 @@ 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);
+      save_widgets_destroy (impl);
       gtk_widget_show (impl->browse_widgets);
     }
 
@@ -4302,6 +4330,9 @@ update_appearance (GtkFileChooserDefault *impl)
   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");
@@ -4337,10 +4368,6 @@ gtk_file_chooser_default_set_property (GObject      *object,
            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;
 
@@ -4568,6 +4595,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))
@@ -4577,6 +4606,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 */
@@ -4587,11 +4618,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
@@ -4602,8 +4637,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)))
     {
@@ -4613,6 +4653,8 @@ check_icon_theme (GtkFileChooserDefault *impl)
 
       change_icon_theme (impl);
     }
+
+  profile_end ("end", NULL);
 }
 
 static void
@@ -4625,13 +4667,17 @@ gtk_file_chooser_default_style_set (GtkWidget *widget,
 
   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
 
+  profile_msg ("    parent class style_set start", NULL);
   if (GTK_WIDGET_CLASS (parent_class)->style_set)
     GTK_WIDGET_CLASS (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);
 }
@@ -4642,6 +4688,8 @@ 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)
@@ -4651,6 +4699,8 @@ gtk_file_chooser_default_screen_changed (GtkWidget *widget,
   check_icon_theme (impl);
 
   g_signal_emit_by_name (widget, "default-size-changed");
+
+  profile_end ("end", NULL);
 }
 
 static gboolean
@@ -4705,6 +4755,7 @@ static void
 gtk_file_chooser_default_map (GtkWidget *widget)
 {
   GtkFileChooserDefault *impl;
+  char *current_working_dir;
 
   profile_start ("start", NULL);
 
@@ -4712,10 +4763,29 @@ gtk_file_chooser_default_map (GtkWidget *widget)
 
   GTK_WIDGET_CLASS (parent_class)->map (widget);
 
-  if (impl->current_folder)
+  switch (impl->reload_state)
     {
+    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 */
+      g_assert (impl->current_folder != NULL);
+
       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);
@@ -4723,6 +4793,19 @@ gtk_file_chooser_default_map (GtkWidget *widget)
   profile_end ("end", NULL);
 }
 
+/* GtkWidget::unmap method */
+static void
+gtk_file_chooser_default_unmap (GtkWidget *widget)
+{
+  GtkFileChooserDefault *impl;
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+
+  impl->reload_state = RELOAD_WAS_UNMAPPED;
+}
+
 static gboolean
 list_model_filter_func (GtkFileSystemModel *model,
                        GtkFilePath        *path,
@@ -4872,9 +4955,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);
@@ -4882,15 +4968,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_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 */
@@ -5004,105 +5095,70 @@ browse_files_center_selected_row (GtkFileChooserDefault *impl)
 static gboolean
 show_and_select_paths (GtkFileChooserDefault *impl,
                       const GtkFilePath     *parent_path,
-                      const GtkFilePath     *only_one_path,
                       GSList                *paths,
-                      GError               **error)
+                      GError                **error)
 {
   GtkFileFolder *folder;
-  gboolean success;
   gboolean have_hidden;
   gboolean have_filtered;
+  GSList *l;
 
   profile_start ("start", NULL);
 
-  if (!only_one_path && !paths)
+  if (!paths)
     {
       profile_end ("end", NULL);
       return TRUE;
     }
 
-  folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_HIDDEN, error);
+  folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN, error);
   if (!folder)
     {
       profile_end ("end", NULL);
       return FALSE;
     }
 
-  success = FALSE;
   have_hidden = FALSE;
   have_filtered = FALSE;
 
-  if (only_one_path)
+  for (l = paths; l; l = l->next)
     {
+      const GtkFilePath *path;
       GtkFileInfo *info;
 
-      info = gtk_file_folder_get_info (folder, only_one_path, error);
-      if (info)
-       {
-         success = TRUE;
-         have_hidden = gtk_file_info_get_is_hidden (info);
-         have_filtered = get_is_file_filtered (impl, only_one_path, info);
-         gtk_file_info_free (info);
-       }
-    }
-  else
-    {
-      GSList *l;
+      path = l->data;
 
-      for (l = paths; l; l = l->next)
+      /* NULL GError */
+      info = gtk_file_folder_get_info (folder, path, NULL);
+      if (info)
        {
-         const GtkFilePath *path;
-         GtkFileInfo *info;
-
-         path = l->data;
+         if (!have_hidden)
+           have_hidden = gtk_file_info_get_is_hidden (info);
 
-         /* NULL GError */
-         info = gtk_file_folder_get_info (folder, path, NULL);
-         if (info)
-           {
-             if (!have_hidden)
-               have_hidden = gtk_file_info_get_is_hidden (info);
+         if (!have_filtered)
+           have_filtered = !gtk_file_info_get_is_folder (info) && get_is_file_filtered (impl, path, info);
 
-             if (!have_filtered)
-               have_filtered = get_is_file_filtered (impl, path, info);
-
-             gtk_file_info_free (info);
+         gtk_file_info_free (info);
 
-             if (have_hidden && have_filtered)
-               break; /* we now have all the information we need */
-           }
+         if (have_hidden && have_filtered)
+           break; /* we now have all the information we need */
        }
-
-      success = TRUE;
     }
 
   g_object_unref (folder);
 
-  if (!success)
-    {
-      profile_end ("end", NULL);
-      return FALSE;
-    }
-
   if (have_hidden)
     g_object_set (impl, "show-hidden", TRUE, NULL);
 
   if (have_filtered)
     set_current_filter (impl, NULL);
 
-  if (only_one_path)
-    _gtk_file_system_model_path_do (impl->browse_files_model, only_one_path, select_func, impl);
-  else
+  for (l = paths; l; l = l->next)
     {
-      GSList *l;
-
-      for (l = paths; l; l = l->next)
-       {
-         const GtkFilePath *path;
+      const GtkFilePath *path;
 
-         path = l->data;
-         _gtk_file_system_model_path_do (impl->browse_files_model, path, select_func, impl);
-       }
+      path = l->data;
+      _gtk_file_system_model_path_do (impl->browse_files_model, path, select_func, impl);
     }
 
   profile_end ("end", NULL);
@@ -5120,7 +5176,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);
     }
@@ -5177,6 +5233,9 @@ 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);
 }
@@ -5249,7 +5308,14 @@ update_chooser_entry (GtkFileChooserDefault *impl)
 
   if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
     {
-      _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), "");
+      /* If nothing is selected, we only reset the file name entry if we are in
+       * CREATE_FOLDER mode.  In SAVE mode, nothing will be selected when the
+       * user starts typeahead in the treeview, and we don't want to clear the
+       * file name entry in that case --- the user could be typing-ahead to look
+       * for a folder name.  See http://bugzilla.gnome.org/show_bug.cgi?id=308332
+       */
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), "");
       return;
     }
 
@@ -5321,6 +5387,8 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
        gtk_file_path_free (impl->current_folder);
 
       impl->current_folder = gtk_file_path_copy (path);
+
+      impl->reload_state = RELOAD_HAS_FOLDER;
     }
 
   /* Update the widgets that may trigger a folder change themselves.  */
@@ -5336,8 +5404,9 @@ gtk_file_chooser_default_update_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->save_file_name_entry)
+    _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_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
@@ -5365,6 +5434,21 @@ 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);
 }
 
@@ -5424,8 +5508,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;
     }
@@ -5664,7 +5752,7 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
   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);
@@ -5713,8 +5801,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);
@@ -5758,7 +5845,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);
@@ -5796,6 +5885,23 @@ gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser    *chooser,
   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;
+
+      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;
+    }
+
   pos = shortcuts_get_pos_for_shortcut_folder (impl, impl->num_shortcuts);
 
   result = shortcuts_insert_path (impl, pos, FALSE, NULL, path, NULL, FALSE, error);
@@ -6124,6 +6230,9 @@ confirm_dialog_should_accept_filename (GtkFileChooserDefault *impl,
   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);
@@ -6313,7 +6422,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
          g_assert_not_reached ();
        }
     }
-  else if (current_focus == impl->save_file_name_entry)
+  else if ((impl->save_file_name_entry != NULL) && (current_focus == impl->save_file_name_entry))
     {
       GtkFilePath *path;
       gboolean is_well_formed, is_empty, is_file_part_empty;
@@ -6501,8 +6610,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)
@@ -6539,7 +6647,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);
@@ -6623,8 +6733,11 @@ shortcuts_activate_volume (GtkFileChooserDefault *impl,
     }
 
   path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
-  change_folder_and_display_error (impl, path);
-  gtk_file_path_free (path);
+  if (path != NULL)
+    {
+      change_folder_and_display_error (impl, path);
+      gtk_file_path_free (path);
+    }
 
  out:
 
@@ -6660,7 +6773,10 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
       const GtkFilePath *file_path;
 
       file_path = col_data;
-      change_folder_and_display_error (impl, file_path);
+      if (check_is_folder (impl->file_system, file_path, NULL))
+       change_folder_and_display_error (impl, file_path);
+      else
+       gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (impl), file_path, NULL);
     }
 }
 
@@ -6704,6 +6820,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;
 }
 
@@ -6810,9 +6933,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;
 
@@ -6974,7 +7101,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];
@@ -6998,10 +7125,10 @@ list_mtime_data_func (GtkTreeViewColumn *tree_column,
     strcpy (buf, _("Unknown"));
   else
     {
-      g_date_set_time (&mtime, (GTime) time_mtime);
-
-      time_now = (GTime ) time (NULL);
-      g_date_set_time (&now, (GTime) time_now);
+      time_t time_now;
+      g_date_set_time_t (&mtime, time_mtime);
+      time_now = time (NULL);
+      g_date_set_time_t (&now, time_now);
 
       days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
 
@@ -7053,15 +7180,11 @@ location_entry_create (GtkFileChooserDefault *impl,
   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);
+  _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry), impl->current_folder);
   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);
-    }
+    gtk_entry_set_text (GTK_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), "");
@@ -7223,6 +7346,9 @@ location_popup_handler (GtkFileChooserDefault *impl,
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                        accept_stock, GTK_RESPONSE_ACCEPT,
                                        NULL);
+  if (toplevel->group)
+    gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
+  
   gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
   gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
@@ -7292,7 +7418,6 @@ location_popup_handler (GtkFileChooserDefault *impl,
 static void
 up_folder_handler (GtkFileChooserDefault *impl)
 {
-  pending_select_paths_add (impl, impl->current_folder);
   _gtk_path_bar_up (GTK_PATH_BAR (impl->browse_path_bar));
 }
 
@@ -7303,23 +7428,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 */