]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilechooserdefault.c
Display an error when we come to the root.
[~andy/gtk] / gtk / gtkfilechooserdefault.c
index 3d46c1cc10b0aaed5fbcfd640cdf94623b7e54b3..c5338b9b69ef938d9d21ae5188e07bc943c09c88 100644 (file)
@@ -28,6 +28,7 @@
 #include "gtkcellrenderertext.h"
 #include "gtkcellrenderertext.h"
 #include "gtkcheckmenuitem.h"
+#include "gtkclipboard.h"
 #include "gtkcombobox.h"
 #include "gtkentry.h"
 #include "gtkeventbox.h"
@@ -36,6 +37,7 @@
 #include "gtkfilechooserdefault.h"
 #include "gtkfilechooserembed.h"
 #include "gtkfilechooserentry.h"
+#include "gtkfilechoosersettings.h"
 #include "gtkfilechooserutils.h"
 #include "gtkfilechooser.h"
 #include "gtkfilesystemmodel.h"
@@ -53,6 +55,7 @@
 #include "gtkmessagedialog.h"
 #include "gtkpathbar.h"
 #include "gtkprivate.h"
+#include "gtkradiobutton.h"
 #include "gtkscrolledwindow.h"
 #include "gtkseparatormenuitem.h"
 #include "gtksizegroup.h"
@@ -86,7 +89,7 @@
 #endif
 
 /* Profiling stuff */
-#define PROFILE_FILE_CHOOSER
+#undef PROFILE_FILE_CHOOSER
 #ifdef PROFILE_FILE_CHOOSER
 
 
@@ -152,6 +155,7 @@ struct _GtkFileChooserDefaultClass
 /* Signal IDs */
 enum {
   LOCATION_POPUP,
+  LOCATION_POPUP_ON_PASTE,
   UP_FOLDER,
   DOWN_FOLDER,
   HOME_FOLDER,
@@ -311,6 +315,7 @@ 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);
@@ -410,6 +415,10 @@ static const GtkFileInfo *get_list_file_info (GtkFileChooserDefault *impl,
 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);
+
 
 \f
 
@@ -434,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,
@@ -480,6 +489,14 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                             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 (I_("up-folder"),
                             G_OBJECT_CLASS_TYPE (class),
@@ -544,6 +561,11 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                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,
                                "up-folder",
@@ -640,6 +662,7 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
   impl->load_state = LOAD_EMPTY;
   impl->reload_state = RELOAD_EMPTY;
   impl->pending_select_paths = NULL;
+  impl->location_mode = LOCATION_MODE_PATH_BAR;
 
   gtk_box_set_spacing (GTK_BOX (impl), 12);
 
@@ -774,6 +797,8 @@ gtk_file_chooser_default_finalize (GObject *object)
 
   g_object_unref (impl->file_system);
 
+  g_free (impl->browse_files_last_selected_name);
+
   for (l = impl->filters; l; l = l->next)
     {
       GtkFileFilter *filter;
@@ -1880,7 +1905,11 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
          shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
        }
       else
-       shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
+        {
+         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);
@@ -1940,7 +1969,7 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
                                              G_TYPE_BOOLEAN,   /* is the previous column a volume? */
                                              G_TYPE_BOOLEAN,   /* removable */
                                              G_TYPE_BOOLEAN,   /* pixbuf cell visibility */
-                                             G_TYPE_OBJECT);   /* GtkFileSystemHandle */
+                                             G_TYPE_POINTER);   /* GtkFileSystemHandle */
 
   if (impl->file_system)
     {
@@ -2629,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
@@ -2816,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 */
@@ -2922,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)
     {
@@ -2946,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;
 }
 
@@ -3095,7 +3124,7 @@ shortcuts_drag_data_received_cb (GtkWidget          *widget,
   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 */
@@ -3143,7 +3172,7 @@ tree_view_keybinding_cb (GtkWidget             *tree_view,
       location_popup_handler (impl, event->string);
       return TRUE;
     }
-  
+
   return FALSE;
 }
 
@@ -3358,11 +3387,11 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
 #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_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_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_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"));
@@ -3390,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);
@@ -3514,7 +3543,7 @@ trap_activate_cb (GtkWidget   *widget,
   impl = (GtkFileChooserDefault *) data;
 
   modifiers = gtk_accelerator_get_default_mod_mask ();
-  
+
   if ((event->keyval == GDK_slash
        || event->keyval == GDK_KP_Divide
 #ifdef G_OS_UNIX
@@ -3573,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,
@@ -3748,7 +3769,7 @@ file_list_drag_data_received_cb (GtkWidget          *widget,
   g_strfreev (uris);
 
 out:
-  g_signal_stop_emission_by_name (widget, "drag-data-received");
+  g_signal_stop_emission_by_name (widget, "drag_data_received");
 }
 
 /* Don't do anything with the drag_drop signal */
@@ -3760,7 +3781,7 @@ file_list_drag_drop_cb (GtkWidget             *widget,
                        guint                  time_,
                        GtkFileChooserDefault *impl)
 {
-  g_signal_stop_emission_by_name (widget, "drag-drop");
+  g_signal_stop_emission_by_name (widget, "drag_drop");
   return TRUE;
 }
 
@@ -3774,7 +3795,7 @@ file_list_drag_motion_cb (GtkWidget             *widget,
                           guint                  time_,
                           GtkFileChooserDefault *impl)
 {
-  g_signal_stop_emission_by_name (widget, "drag-motion");
+  g_signal_stop_emission_by_name (widget, "drag_motion");
   return TRUE;
 }
 
@@ -3802,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);
@@ -3962,20 +3975,20 @@ create_file_list (GtkFileChooserDefault *impl)
                      num_file_list_dest_targets,
                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
   
-  g_signal_connect (impl->browse_files_tree_view, "row-activated",
+  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_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_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_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));
@@ -4010,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,
@@ -4024,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);
@@ -4202,6 +4215,8 @@ save_widgets_create (GtkFileChooserDefault *impl)
   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);
@@ -4210,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);
@@ -4220,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);
@@ -4274,12 +4291,225 @@ save_widgets_destroy (GtkFileChooserDefault *impl)
 
   gtk_widget_destroy (impl->save_widgets);
   impl->save_widgets = NULL;
-  impl->save_file_name_entry = 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 */
 static GtkWidget *
 browse_widgets_create (GtkFileChooserDefault *impl)
@@ -4289,16 +4519,22 @@ browse_widgets_create (GtkFileChooserDefault *impl)
   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);
 
-  /* The path bar and 'Create Folder' button */
+  /* 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);
@@ -4310,6 +4546,18 @@ browse_widgets_create (GtkFileChooserDefault *impl)
                    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);
@@ -4539,6 +4787,7 @@ update_appearance (GtkFileChooserDefault *impl)
     {
       const char *text;
 
+      gtk_widget_hide (impl->location_button);
       save_widgets_create (impl);
 
       if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
@@ -4548,8 +4797,6 @@ 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);
@@ -4575,10 +4822,15 @@ update_appearance (GtkFileChooserDefault *impl)
   else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
           impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
     {
+      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
@@ -4921,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));
     }
@@ -5089,6 +5341,40 @@ get_is_file_filtered (GtkFileChooserDefault *impl,
   return !result;
 }
 
+static void
+settings_load (GtkFileChooserDefault *impl)
+{
+  GtkFileChooserSettings *settings;
+  LocationMode location_mode;
+  gboolean show_hidden;
+
+  settings = _gtk_file_chooser_settings_new ();
+
+  location_mode = _gtk_file_chooser_settings_get_location_mode (settings);
+  show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings);
+
+  g_object_unref (settings);
+
+  location_mode_set (impl, location_mode, TRUE);
+  gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
+}
+
+static void
+settings_save (GtkFileChooserDefault *impl)
+{
+  GtkFileChooserSettings *settings;
+
+  settings = _gtk_file_chooser_settings_new ();
+
+  _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)));
+
+  /* NULL GError */
+  _gtk_file_chooser_settings_save (settings, NULL);
+
+  g_object_unref (settings);
+}
+
 /* GtkWidget::map method */
 static void
 gtk_file_chooser_default_map (GtkWidget *widget)
@@ -5130,6 +5416,8 @@ gtk_file_chooser_default_map (GtkWidget *widget)
 
   bookmarks_changed_cb (impl->file_system, impl);
 
+  settings_load (impl);
+
   profile_end ("end", NULL);
 }
 
@@ -5141,6 +5429,8 @@ gtk_file_chooser_default_unmap (GtkWidget *widget)
 
   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;
@@ -5310,7 +5600,7 @@ load_set_model (GtkFileChooserDefault *impl)
   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);
@@ -5351,7 +5641,7 @@ load_timeout_cb (gpointer data)
   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)
 {
@@ -5495,6 +5785,9 @@ show_and_select_paths_finished_loading (GtkFileFolder *folder,
                                      select_func, data->impl);
     }
 
+  browse_files_center_selected_row (data->impl);
+
+  g_object_unref (data->impl);
   gtk_file_paths_free (data->paths);
   g_free (data);
 }
@@ -5693,48 +5986,142 @@ set_list_model (GtkFileChooserDefault *impl,
   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;
-  gboolean change_entry;
+  struct update_chooser_entry_selected_foreach_closure closure;
+  const char *file_part;
 
-  if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
+  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))
+  file_part = NULL;
+
+  if (closure.num_selected == 0)
     {
-      /* 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;
+      goto maybe_clear_entry;
     }
+  else if (closure.num_selected == 1)
+    {
+      GtkTreeIter child_iter;
+      const GtkFileInfo *info;
+      gboolean change_entry;
 
-  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
-                                                 &child_iter,
-                                                 &iter);
+      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+                                                     &child_iter,
+                                                     &closure.first_selected_iter);
 
-  info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+      info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
 
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
-    change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
+      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
-    change_entry = TRUE;                                /* ... unless we are in CREATE_FOLDER mode */
+    {
+      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 (change_entry)
-    _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
-                                          gtk_file_info_get_display_name (info));
+      if (clear_entry)
+       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+    }
 }
 
 static gboolean
@@ -5751,6 +6138,8 @@ struct UpdateCurrentFolderData
   GtkFileChooserDefault *impl;
   GtkFilePath *path;
   gboolean keep_trail;
+  GtkFilePath *original_path;
+  GError *original_error;
 };
 
 static void
@@ -5767,6 +6156,7 @@ update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
     goto out;
 
   impl->update_current_folder_handle = NULL;
+  impl->reload_state = RELOAD_EMPTY;
 
   set_busy_cursor (impl, FALSE);
 
@@ -5775,8 +6165,52 @@ update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
 
   if (error)
     {
-      error_changing_folder_dialog (impl, data->path, g_error_copy (error));
-      goto out;
+      GtkFilePath *parent_path;
+
+      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;
+       }
+    }
+
+  if (data->original_path)
+    {
+      error_changing_folder_dialog (impl, data->original_path, data->original_error);
+
+      gtk_file_path_free (data->original_path);
     }
 
   if (!gtk_file_info_get_is_folder (info))
@@ -5808,8 +6242,8 @@ update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
 
   /* Set the folder on the save entry */
 
-  if (impl->save_file_name_entry)
-    _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
+  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
@@ -5870,6 +6304,8 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
   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,
@@ -5914,7 +6350,7 @@ gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
                    || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
 
   pending_select_paths_free (impl);
-  _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), name);
+  _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
 }
 
 static void
@@ -6083,9 +6519,12 @@ 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->save_file_name_entry);
+  chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
 
   if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0)
     {
@@ -6168,41 +6607,77 @@ 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)
+  toplevel = get_toplevel (GTK_WIDGET (impl));
+  if (toplevel)
+    current_focus = gtk_window_get_focus (toplevel);
+  else
+    current_focus = NULL;
+
+  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:
+
       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_empty)
+      if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
        {
-         if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
-           {
-             gtk_file_path_free (info.path_from_entry);
-             return NULL;
-           }
+         gtk_file_path_free (info.path_from_entry);
+         return NULL;
        }
-    }
 
-  if (!info.path_from_entry || impl->select_multiple)
+      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
     {
-      GtkTreeSelection *selection;
-
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-      gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
+    /* 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; 
     }
 
-  if (info.path_from_entry)
-    info.result = g_slist_prepend (info.result, info.path_from_entry);
+ out:
 
   /* If there's no folder selected, and we're in SELECT_FOLDER mode, then we
    * fall back to the current directory */
@@ -6383,10 +6858,11 @@ gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser    *chooser,
       gchar *uri;
 
       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"),
+                  _("Shortcut %s already exists"),
                   uri);
       g_free (uri);
 
@@ -6407,7 +6883,7 @@ gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser    *chooser,
           g_set_error (error,
                       GTK_FILE_CHOOSER_ERROR,
                       GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
-                      _("shortcut %s already exists"),
+                      _("Shortcut %s already exists"),
                       uri);
           g_free (uri);
 
@@ -6493,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,
@@ -6896,7 +7373,7 @@ out:
   g_object_unref (handle);
 }
 
-struct SaveEntryData
+struct FileExistsData
 {
   GtkFileChooserDefault *impl;
   gboolean file_exists_and_is_not_folder;
@@ -6912,7 +7389,7 @@ save_entry_get_info_cb (GtkFileSystemHandle *handle,
 {
   gboolean parent_is_folder;
   gboolean cancelled = handle->cancelled;
-  struct SaveEntryData *data = user_data;
+  struct FileExistsData *data = user_data;
 
   if (handle != data->impl->should_respond_get_info_handle)
     goto out;
@@ -6938,7 +7415,7 @@ save_entry_get_info_cb (GtkFileSystemHandle *handle,
              gboolean retval;
              const char *file_part;
 
-             file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->save_file_name_entry));
+             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)
@@ -6975,6 +7452,117 @@ out:
   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)
@@ -7066,7 +7654,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
          g_assert_not_reached ();
        }
     }
-  else if ((impl->save_file_name_entry != NULL) && (current_focus == impl->save_file_name_entry))
+  else if ((impl->location_entry != NULL) && (current_focus == impl->location_entry))
     {
       GtkFilePath *path;
       gboolean is_well_formed, is_empty, is_file_part_empty;
@@ -7078,9 +7666,12 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
     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);
+      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_well_formed)
@@ -7091,60 +7682,49 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
       error = NULL;
       if (is_folder)
        {
-         if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+         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 /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+         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
-       {
-         gboolean file_exists_and_is_not_folder;
-
-         file_exists_and_is_not_folder = g_error_matches (error, GTK_FILE_SYSTEM_ERROR, GTK_FILE_SYSTEM_ERROR_NOT_FOLDER);
-
-         if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER && file_exists_and_is_not_folder)
+         else
            {
-             /* Oops, the user typed the name of an existing path which is not a folder */
-             error_creating_folder_over_existing_file_dialog (impl, path, error);
-             error = NULL; /* as it will be freed below for the general case */
+             g_assert_not_reached ();
              retval = FALSE;
            }
-         else
-           {
-             GtkFilePath *parent_path;
-             struct SaveEntryData *data;
-
-             /* check that everything up to the last component exists */
+       }
+      else
+       {
+         struct FileExistsData *data;
 
-             parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
+         /* We need to check whether path exists and is not a folder */
 
-             data = g_new0 (struct SaveEntryData, 1);
-             data->impl = g_object_ref (impl);
-             data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
-             data->parent_path = parent_path; /* Takes ownership */
-             data->path = gtk_file_path_copy (path);
+         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->should_respond_get_info_handle)
-               gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+         if (impl->file_exists_get_info_handle)
+           gtk_file_system_cancel_operation (impl->file_exists_get_info_handle);
 
-             impl->should_respond_get_info_handle =
-               gtk_file_system_get_info (impl->file_system, parent_path,
-                                         GTK_FILE_INFO_IS_FOLDER,
-                                         save_entry_get_info_cb,
-                                         data);
-             set_busy_cursor (impl, TRUE);
+         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);
 
-             retval = FALSE;
-           }
+         set_busy_cursor (impl, TRUE);
+         retval = FALSE;
 
          if (error != NULL)
            g_error_free (error);
@@ -7179,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
@@ -7202,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);
 }
 
@@ -7440,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,
@@ -7765,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;
@@ -7787,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);
@@ -7870,281 +8471,59 @@ _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);
-  _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry), impl->current_folder);
-  if (path[0])
-    gtk_entry_set_text (GTK_ENTRY (entry), path);
-  else
-    {
-      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);
-}
-
-struct UpdateFromEntryData
-{
-  GtkFileChooserDefault *impl;
-  GtkFilePath *subfolder_path;
-  GtkFilePath *folder_path;
-  char *file_part;
-};
-
 static void
-update_from_entry_get_info_cb (GtkFileSystemHandle *handle,
-                              const GtkFileInfo   *file_info,
-                              const GError        *error,
-                              gpointer             user_data)
+location_set_user_text (GtkFileChooserDefault *impl,
+                       const gchar           *path)
 {
-  gboolean cancelled = handle->cancelled;
-  struct UpdateFromEntryData *data = user_data;
-
-  if (handle != data->impl->update_from_entry_handle)
-    goto out;
-
-  data->impl->update_from_entry_handle = NULL;
-
-  if (cancelled)
-    goto out;
-
-  if (!file_info)
-    {
-      if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-          || data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-        {
-          if (!change_folder_and_display_error (data->impl, data->folder_path))
-            goto out;
-
-          gtk_file_chooser_default_set_current_name (GTK_FILE_CHOOSER (data->impl), data->file_part);
-        }
-      else
-        {
-         GError *err = g_error_copy (error);
-
-          error_getting_info_dialog (data->impl, data->subfolder_path, err);
-       }
-
-      goto out;
-    }
-
-  if (gtk_file_info_get_is_folder (file_info))
-    change_folder_and_display_error (data->impl, data->subfolder_path);
-  else
-    {
-      gboolean result;
-      GError *select_error = NULL;
-
-      result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (data->impl), data->subfolder_path, &select_error);
-
-      if (!result)
-        error_dialog (data->impl, _("Could not select item"),
-                     data->subfolder_path, select_error);
-    }
-
-out:
-  g_object_unref (data->impl);
-  gtk_file_path_free (data->subfolder_path);
-  gtk_file_path_free (data->folder_path);
-  g_free (data->file_part);
-  g_free (data);
-
-  g_object_unref (handle);
-}
-
-static gboolean
-update_from_entry (GtkFileChooserDefault *impl,
-                  GtkWindow             *parent,
-                  GtkFileChooserEntry   *chooser_entry)
-{
-  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
-    {
-      GtkFilePath *subfolder_path = NULL;
-      GError *error = NULL;
-      gboolean result = FALSE;
-      struct UpdateFromEntryData *data;
-
-      /* 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.
-       */
-
-      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);
-          gtk_file_path_free (subfolder_path);
-
-          return result;
-       }
-
-      data = g_new0 (struct UpdateFromEntryData, 1);
-      data->impl = g_object_ref (impl);
-      data->folder_path = gtk_file_path_copy (folder_path);
-      data->subfolder_path = subfolder_path;
-      data->file_part = g_strdup (file_part);
-
-      if (impl->update_from_entry_handle)
-       gtk_file_system_cancel_operation (impl->update_from_entry_handle);
-
-      impl->update_from_entry_handle =
-        gtk_file_system_get_info (impl->file_system, subfolder_path,
-                                 GTK_FILE_INFO_IS_FOLDER,
-                                 update_from_entry_get_info_cb, data);
-
-      return TRUE;
-    }
-
-  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);
-  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);
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+      LocationMode new_mode;
 
-  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);
-
-  /* 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 */
@@ -8292,6 +8671,3 @@ shortcuts_model_filter_new (GtkFileChooserDefault *impl,
 
   return GTK_TREE_MODEL (model);
 }
-
-#define __GTK_FILE_CHOOSER_DEFAULT_C__
-#include "gtkaliasdef.c"