]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilechooserdefault.c
Unify the handling of various "Enter" keysyms all over the place.
[~andy/gtk] / gtk / gtkfilechooserdefault.c
index d2abc315e29dd7f6e138dcc5a9ad404d8f89e3b7..08971f8b9db11bec65ad79df3f82ac3cb55324c8 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
 /* GTK - The GIMP Toolkit
  * gtkfilechooserdefault.c: Default implementation of GtkFileChooser
  * Copyright (C) 2003, Red Hat, Inc.
 #include "gtkpathbar.h"
 #include "gtkprivate.h"
 #include "gtkradiobutton.h"
+#include "gtkrecentfilter.h"
+#include "gtkrecentmanager.h"
 #include "gtkscrolledwindow.h"
 #include "gtkseparatormenuitem.h"
 #include "gtksizegroup.h"
 #include "gtkstock.h"
 #include "gtktable.h"
+#include "gtktooltip.h"
 #include "gtktreednd.h"
 #include "gtktreeprivate.h"
 #include "gtktreeselection.h"
@@ -77,8 +81,9 @@
 #include <errno.h>
 #include <string.h>
 #include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
-\f
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -136,7 +141,7 @@ _gtk_file_chooser_profile_log (const char *func, int indent, const char *msg1, c
 #define profile_msg(x, y)
 #endif
 
-\f
+
 
 typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
 
@@ -160,6 +165,11 @@ enum {
   HOME_FOLDER,
   DESKTOP_FOLDER,
   QUICK_BOOKMARK,
+  LOCATION_TOGGLE_POPUP,
+  SHOW_HIDDEN,
+  SEARCH_SHORTCUT,
+  RECENT_SHORTCUT,
+
   LAST_SIGNAL
 };
 
@@ -170,13 +180,21 @@ enum {
   SHORTCUTS_COL_PIXBUF,
   SHORTCUTS_COL_NAME,
   SHORTCUTS_COL_DATA,
-  SHORTCUTS_COL_IS_VOLUME,
+  SHORTCUTS_COL_TYPE,
   SHORTCUTS_COL_REMOVABLE,
   SHORTCUTS_COL_PIXBUF_VISIBLE,
   SHORTCUTS_COL_HANDLE,
   SHORTCUTS_COL_NUM_COLUMNS
 };
 
+typedef enum {
+  SHORTCUT_TYPE_PATH,
+  SHORTCUT_TYPE_VOLUME,
+  SHORTCUT_TYPE_SEPARATOR,
+  SHORTCUT_TYPE_SEARCH,
+  SHORTCUT_TYPE_RECENT
+} ShortcutType;
+
 /* Column numbers for the file list */
 enum {
   FILE_LIST_COL_NAME,
@@ -185,6 +203,30 @@ enum {
   FILE_LIST_COL_NUM_COLUMNS
 };
 
+/* Column numbers for the search model.  
+ * Keep this in sync with search_setup_model() 
+ */
+enum {
+  SEARCH_MODEL_COL_PATH,
+  SEARCH_MODEL_COL_DISPLAY_NAME,
+  SEARCH_MODEL_COL_COLLATION_KEY,
+  SEARCH_MODEL_COL_STAT,
+  SEARCH_MODEL_COL_HANDLE,
+  SEARCH_MODEL_COL_PIXBUF,
+  SEARCH_MODEL_COL_MIME_TYPE,
+  SEARCH_MODEL_COL_IS_FOLDER,
+  SEARCH_MODEL_COL_NUM_COLUMNS
+};
+
+enum {
+  RECENT_MODEL_COL_PATH,
+  RECENT_MODEL_COL_DISPLAY_NAME,
+  RECENT_MODEL_COL_INFO,
+  RECENT_MODEL_COL_IS_FOLDER,
+  RECENT_MODEL_COL_HANDLE,
+  RECENT_MODEL_COL_NUM_COLUMNS
+};
+
 /* Identifiers for target types */
 enum {
   GTK_TREE_MODEL_ROW,
@@ -196,8 +238,7 @@ static const GtkTargetEntry shortcuts_source_targets[] = {
   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
 };
 
-static const int num_shortcuts_source_targets = (sizeof (shortcuts_source_targets)
-                                                / sizeof (shortcuts_source_targets[0]));
+static const int num_shortcuts_source_targets = G_N_ELEMENTS (shortcuts_source_targets); 
 
 /* Target types for dropping into the shortcuts list */
 static const GtkTargetEntry shortcuts_dest_targets[] = {
@@ -205,28 +246,43 @@ static const GtkTargetEntry shortcuts_dest_targets[] = {
   { "text/uri-list", 0, TEXT_URI_LIST }
 };
 
-static const int num_shortcuts_dest_targets = (sizeof (shortcuts_dest_targets)
-                                              / sizeof (shortcuts_dest_targets[0]));
+static const int num_shortcuts_dest_targets = G_N_ELEMENTS (shortcuts_dest_targets); 
 
 /* Target types for DnD from the file list */
 static const GtkTargetEntry file_list_source_targets[] = {
   { "text/uri-list", 0, TEXT_URI_LIST }
 };
 
-static const int num_file_list_source_targets = (sizeof (file_list_source_targets)
-                                                / sizeof (file_list_source_targets[0]));
+static const int num_file_list_source_targets = G_N_ELEMENTS (file_list_source_targets); 
 
 /* Target types for dropping into the file list */
 static const GtkTargetEntry file_list_dest_targets[] = {
   { "text/uri-list", 0, TEXT_URI_LIST }
 };
 
-static const int num_file_list_dest_targets = (sizeof (file_list_dest_targets)
-                                              / sizeof (file_list_dest_targets[0]));
+static const int num_file_list_dest_targets = G_N_ELEMENTS (file_list_dest_targets); 
+
+/* Target types for dragging from the recent files list */
+static const GtkTargetEntry recent_list_source_targets[] = {
+  { "text/uri-list", 0, TEXT_URI_LIST }
+};
+
+static const int num_recent_list_source_targets = G_N_ELEMENTS (recent_list_source_targets);
 
+static gboolean
+search_is_possible (GtkFileChooserDefault *impl)
+{
+  if (impl->search_engine == NULL)
+    impl->search_engine = _gtk_search_engine_new ();
+  
+  return impl->search_engine != NULL;
+}
 
 /* Interesting places in the shortcuts bar */
 typedef enum {
+  SHORTCUTS_SEARCH,
+  SHORTCUTS_RECENT,
+  SHORTCUTS_RECENT_SEPARATOR,
   SHORTCUTS_HOME,
   SHORTCUTS_DESKTOP,
   SHORTCUTS_VOLUMES,
@@ -241,7 +297,7 @@ typedef enum {
 #define FALLBACK_ICON_SIZE 16
 
 #define PREVIEW_HBOX_SPACING 12
-#define NUM_LINES 40
+#define NUM_LINES 45
 #define NUM_CHARS 60
 
 static void gtk_file_chooser_default_iface_init       (GtkFileChooserIface        *iface);
@@ -269,6 +325,8 @@ static void     gtk_file_chooser_default_style_set      (GtkWidget             *
                                                         GtkStyle              *previous_style);
 static void     gtk_file_chooser_default_screen_changed (GtkWidget             *widget,
                                                         GdkScreen             *previous_screen);
+static void     gtk_file_chooser_default_size_allocate  (GtkWidget             *widget,
+                                                        GtkAllocation         *allocation);
 
 static gboolean       gtk_file_chooser_default_set_current_folder         (GtkFileChooser    *chooser,
                                                                            const GtkFilePath *path,
@@ -276,6 +334,7 @@ static gboolean       gtk_file_chooser_default_set_current_folder      (GtkFileCh
 static gboolean       gtk_file_chooser_default_update_current_folder      (GtkFileChooser    *chooser,
                                                                            const GtkFilePath *path,
                                                                            gboolean           keep_trail,
+                                                                           gboolean           clear_entry,
                                                                            GError           **error);
 static GtkFilePath *  gtk_file_chooser_default_get_current_folder         (GtkFileChooser    *chooser);
 static void           gtk_file_chooser_default_set_current_name           (GtkFileChooser    *chooser,
@@ -306,22 +365,24 @@ static GSList *       gtk_file_chooser_default_list_shortcut_folders  (GtkFileCh
 static void           gtk_file_chooser_default_get_default_size       (GtkFileChooserEmbed *chooser_embed,
                                                                       gint                *default_width,
                                                                       gint                *default_height);
-static void           gtk_file_chooser_default_get_resizable_hints    (GtkFileChooserEmbed *chooser_embed,
-                                                                      gboolean            *resize_horizontally,
-                                                                      gboolean            *resize_vertically);
+static gboolean       gtk_file_chooser_default_get_resizable          (GtkFileChooserEmbed *chooser_embed);
 static gboolean       gtk_file_chooser_default_should_respond         (GtkFileChooserEmbed *chooser_embed);
 static void           gtk_file_chooser_default_initial_focus          (GtkFileChooserEmbed *chooser_embed);
 
-static void location_popup_handler (GtkFileChooserDefault *impl,
-                                   const gchar           *path);
+static void location_popup_handler  (GtkFileChooserDefault *impl,
+                                    const gchar           *path);
 static void location_popup_on_paste_handler (GtkFileChooserDefault *impl);
-static void up_folder_handler      (GtkFileChooserDefault *impl);
-static void down_folder_handler    (GtkFileChooserDefault *impl);
-static void home_folder_handler    (GtkFileChooserDefault *impl);
-static void desktop_folder_handler (GtkFileChooserDefault *impl);
-static void quick_bookmark_handler (GtkFileChooserDefault *impl,
-                                   gint                   bookmark_index);
-static void update_appearance      (GtkFileChooserDefault *impl);
+static void location_toggle_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 show_hidden_handler     (GtkFileChooserDefault *impl);
+static void search_shortcut_handler (GtkFileChooserDefault *impl);
+static void recent_shortcut_handler (GtkFileChooserDefault *impl);
+static void update_appearance       (GtkFileChooserDefault *impl);
 
 static void set_current_filter   (GtkFileChooserDefault *impl,
                                  GtkFileFilter         *filter);
@@ -329,10 +390,6 @@ static void check_preview_change (GtkFileChooserDefault *impl);
 
 static void filter_combo_changed       (GtkComboBox           *combo_box,
                                        GtkFileChooserDefault *impl);
-static void     shortcuts_row_activated_cb (GtkTreeView           *tree_view,
-                                           GtkTreePath           *path,
-                                           GtkTreeViewColumn     *column,
-                                           GtkFileChooserDefault *impl);
 
 static gboolean shortcuts_key_press_event_cb (GtkWidget             *widget,
                                              GdkEventKey           *event,
@@ -372,11 +429,11 @@ static void select_func (GtkFileSystemModel *model,
                         GtkTreeIter        *iter,
                         gpointer            user_data);
 
-static void path_bar_clicked           (GtkPathBar            *path_bar,
-                                       GtkFilePath           *file_path,
-                                       GtkFilePath           *child_path,
-                                       gboolean               child_is_hidden,
-                                       GtkFileChooserDefault *impl);
+static void path_bar_clicked (GtkPathBar            *path_bar,
+                              GtkFilePath           *file_path,
+                              GtkFilePath           *child_path,
+                              gboolean               child_is_hidden,
+                              GtkFileChooserDefault *impl);
 
 static void add_bookmark_button_clicked_cb    (GtkButton             *button,
                                               GtkFileChooserDefault *impl);
@@ -418,6 +475,31 @@ static void location_button_toggled_cb (GtkToggleButton *toggle,
                                        GtkFileChooserDefault *impl);
 static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
 
+static void     search_stop_searching        (GtkFileChooserDefault *impl,
+                                              gboolean               remove_query);
+static void     search_clear_model           (GtkFileChooserDefault *impl, 
+                                             gboolean               remove_from_treeview);
+static gboolean search_should_respond        (GtkFileChooserDefault *impl);
+static void     search_switch_to_browse_mode (GtkFileChooserDefault *impl);
+static GSList  *search_get_selected_paths    (GtkFileChooserDefault *impl);
+static void     search_entry_activate_cb     (GtkEntry              *entry, 
+                                             gpointer               data);
+static void     settings_load                (GtkFileChooserDefault *impl);
+static void     search_get_valid_child_iter  (GtkFileChooserDefault *impl,
+                                              GtkTreeIter           *child_iter,
+                                              GtkTreeIter           *iter);
+
+static void     recent_manager_update        (GtkFileChooserDefault *impl);
+static void     recent_stop_loading          (GtkFileChooserDefault *impl);
+static void     recent_clear_model           (GtkFileChooserDefault *impl,
+                                              gboolean               remove_from_treeview);
+static gboolean recent_should_respond        (GtkFileChooserDefault *impl);
+static void     recent_switch_to_browse_mode (GtkFileChooserDefault *impl);
+static GSList * recent_get_selected_paths    (GtkFileChooserDefault *impl);
+static void     recent_get_valid_child_iter  (GtkFileChooserDefault *impl,
+                                              GtkTreeIter           *child_iter,
+                                              GtkTreeIter           *iter);
+
 
 \f
 
@@ -427,26 +509,76 @@ typedef struct {
   GtkTreeModelFilter parent;
 
   GtkFileChooserDefault *impl;
-} ShortcutsModelFilter;
+} ShortcutsPaneModelFilter;
 
 typedef struct {
   GtkTreeModelFilterClass parent_class;
-} ShortcutsModelFilterClass;
+} ShortcutsPaneModelFilterClass;
 
-#define SHORTCUTS_MODEL_FILTER_TYPE (_shortcuts_model_filter_get_type ())
-#define SHORTCUTS_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_MODEL_FILTER_TYPE, ShortcutsModelFilter))
+#define SHORTCUTS_PANE_MODEL_FILTER_TYPE (_shortcuts_pane_model_filter_get_type ())
+#define SHORTCUTS_PANE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_PANE_MODEL_FILTER_TYPE, ShortcutsPaneModelFilter))
 
-static void shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);
+static void shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);
 
-G_DEFINE_TYPE_WITH_CODE (ShortcutsModelFilter,
-                        _shortcuts_model_filter,
+G_DEFINE_TYPE_WITH_CODE (ShortcutsPaneModelFilter,
+                        _shortcuts_pane_model_filter,
                         GTK_TYPE_TREE_MODEL_FILTER,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
-                                               shortcuts_model_filter_drag_source_iface_init))
+                                               shortcuts_pane_model_filter_drag_source_iface_init))
+
+static GtkTreeModel *shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
+                                                     GtkTreeModel          *child_model,
+                                                     GtkTreePath           *root);
+
+
+typedef struct {
+  GtkTreeModelSort parent;
+
+  GtkFileChooserDefault *impl;
+} RecentModelSort;
+
+typedef struct {
+  GtkTreeModelSortClass parent_class;
+} RecentModelSortClass;
+
+#define RECENT_MODEL_SORT_TYPE (_recent_model_sort_get_type ())
+#define RECENT_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RECENT_MODEL_SORT_TYPE, RecentModelSort))
 
-static GtkTreeModel *shortcuts_model_filter_new (GtkFileChooserDefault *impl,
-                                                GtkTreeModel          *child_model,
-                                                GtkTreePath           *root);
+static void recent_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (RecentModelSort,
+                         _recent_model_sort,
+                         GTK_TYPE_TREE_MODEL_SORT,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
+                                                recent_model_sort_drag_source_iface_init));
+
+static GtkTreeModel *recent_model_sort_new (GtkFileChooserDefault *impl,
+                                            GtkTreeModel          *child_model);
+
+
+typedef struct {
+  GtkTreeModelSort parent;
+
+  GtkFileChooserDefault *impl;
+} SearchModelSort;
+
+typedef struct {
+  GtkTreeModelSortClass parent_class;
+} SearchModelSortClass;
+
+#define SEARCH_MODEL_SORT_TYPE (_search_model_sort_get_type ())
+#define SEARCH_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEARCH_MODEL_SORT_TYPE, SearchModelSort))
+
+static void search_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (SearchModelSort,
+                         _search_model_sort,
+                         GTK_TYPE_TREE_MODEL_SORT,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
+                                                search_model_sort_drag_source_iface_init));
+
+static GtkTreeModel *search_model_sort_new (GtkFileChooserDefault *impl,
+                                            GtkTreeModel          *child_model);
 
 \f
 
@@ -479,6 +611,7 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
   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;
+  widget_class->size_allocate = gtk_file_chooser_default_size_allocate;
 
   signals[LOCATION_POPUP] =
     _gtk_binding_signal_new (I_("location-popup"),
@@ -496,6 +629,14 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                             NULL, NULL,
                             _gtk_marshal_VOID__VOID,
                             G_TYPE_NONE, 0);
+  signals[LOCATION_TOGGLE_POPUP] =
+    _gtk_binding_signal_new (I_("location-toggle-popup"),
+                            G_OBJECT_CLASS_TYPE (class),
+                            G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                            G_CALLBACK (location_toggle_popup_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),
@@ -536,13 +677,37 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                             NULL, NULL,
                             _gtk_marshal_VOID__INT,
                             G_TYPE_NONE, 1, G_TYPE_INT);
+  signals[SHOW_HIDDEN] =
+    _gtk_binding_signal_new ("show-hidden",
+                            G_OBJECT_CLASS_TYPE (class),
+                            G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                            G_CALLBACK (show_hidden_handler),
+                            NULL, NULL,
+                            _gtk_marshal_VOID__VOID,
+                            G_TYPE_NONE, 0);
+  signals[SEARCH_SHORTCUT] =
+    _gtk_binding_signal_new ("search-shortcut",
+                             G_OBJECT_CLASS_TYPE (class),
+                             G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                             G_CALLBACK (search_shortcut_handler),
+                             NULL, NULL,
+                             _gtk_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+  signals[RECENT_SHORTCUT] =
+    _gtk_binding_signal_new ("recent-shortcut",
+                             G_OBJECT_CLASS_TYPE (class),
+                             G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                             G_CALLBACK (recent_shortcut_handler),
+                             NULL, NULL,
+                             _gtk_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
 
   binding_set = gtk_binding_set_by_class (class);
 
   gtk_binding_entry_add_signal (binding_set,
                                GDK_l, GDK_CONTROL_MASK,
-                               "location-popup",
-                               1, G_TYPE_STRING, "");
+                               "location-toggle-popup",
+                               0);
 
   gtk_binding_entry_add_signal (binding_set,
                                GDK_slash, 0,
@@ -564,7 +729,6 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                GDK_v, GDK_CONTROL_MASK,
                                "location-popup-on-paste",
                                0);
-
   gtk_binding_entry_add_signal (binding_set,
                                GDK_Up, GDK_MOD1_MASK,
                                "up-folder",
@@ -599,6 +763,18 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                GDK_d, GDK_MOD1_MASK,
                                "desktop-folder",
                                0);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_h, GDK_CONTROL_MASK,
+                                "show-hidden",
+                                0);
+  gtk_binding_entry_add_signal (binding_set,
+                                GDK_s, GDK_MOD1_MASK,
+                                "search-shortcut",
+                                0);
+  gtk_binding_entry_add_signal (binding_set,
+                                GDK_r, GDK_MOD1_MASK,
+                                "recent-shortcut",
+                                0);
 
   for (i = 0; i < 10; i++)
     gtk_binding_entry_add_signal (binding_set,
@@ -607,12 +783,6 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
                                  1, G_TYPE_INT, i);
 
   _gtk_file_chooser_install_properties (gobject_class);
-
-  gtk_settings_install_property (g_param_spec_string ("gtk-file-chooser-backend",
-                                                     P_("Default file chooser backend"),
-                                                     P_("Name of the GtkFileChooser backend to use by default"),
-                                                     NULL,
-                                                     GTK_PARAM_READWRITE));
 }
 
 static void
@@ -640,7 +810,7 @@ static void
 gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface *iface)
 {
   iface->get_default_size = gtk_file_chooser_default_get_default_size;
-  iface->get_resizable_hints = gtk_file_chooser_default_get_resizable_hints;
+  iface->get_resizable = gtk_file_chooser_default_get_resizable;
   iface->should_respond = gtk_file_chooser_default_should_respond;
   iface->initial_focus = gtk_file_chooser_default_initial_focus;
 }
@@ -662,6 +832,7 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
   impl->reload_state = RELOAD_EMPTY;
   impl->pending_select_paths = NULL;
   impl->location_mode = LOCATION_MODE_PATH_BAR;
+  impl->operation_mode = OPERATION_MODE_BROWSE;
 
   gtk_box_set_spacing (GTK_BOX (impl), 12);
 
@@ -677,22 +848,24 @@ shortcuts_free_row_data (GtkFileChooserDefault *impl,
                         GtkTreeIter           *iter)
 {
   gpointer col_data;
-  gboolean is_volume;
+  ShortcutType shortcut_type;
   GtkFileSystemHandle *handle;
 
   gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
                      SHORTCUTS_COL_DATA, &col_data,
-                     SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                     SHORTCUTS_COL_TYPE, &shortcut_type,
                      SHORTCUTS_COL_HANDLE, &handle,
                      -1);
 
   if (handle)
     gtk_file_system_cancel_operation (handle);
 
-  if (!col_data)
+  if (!(shortcut_type == SHORTCUT_TYPE_PATH || 
+       shortcut_type == SHORTCUT_TYPE_VOLUME) ||
+      !col_data)
     return;
 
-  if (is_volume)
+  if (shortcut_type == SHORTCUT_TYPE_VOLUME)
     {
       GtkFileSystemVolume *volume;
 
@@ -703,6 +876,8 @@ shortcuts_free_row_data (GtkFileChooserDefault *impl,
     {
       GtkFilePath *path;
 
+      g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
+
       path = col_data;
       gtk_file_path_free (path);
     }
@@ -749,7 +924,8 @@ static void
 pending_select_paths_add (GtkFileChooserDefault *impl,
                          const GtkFilePath     *path)
 {
-  impl->pending_select_paths = g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path));
+  impl->pending_select_paths =
+    g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path));
 }
 
 /* Used from gtk_tree_selection_selected_foreach() */
@@ -789,8 +965,11 @@ gtk_file_chooser_default_finalize (GObject *object)
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
   GSList *l;
 
-  if (impl->shortcuts_filter_model)
-    g_object_unref (impl->shortcuts_filter_model);
+  if (impl->shortcuts_pane_filter_model)
+    g_object_unref (impl->shortcuts_pane_filter_model);
+
+  if (impl->shortcuts_combo_filter_model)
+    g_object_unref (impl->shortcuts_combo_filter_model);
 
   shortcuts_free (impl);
 
@@ -828,6 +1007,9 @@ gtk_file_chooser_default_finalize (GObject *object)
   if (impl->sort_model)
     g_object_unref (impl->sort_model);
 
+  search_clear_model (impl, FALSE);
+  recent_clear_model (impl, FALSE);
+
   g_free (impl->preview_display_name);
 
   g_free (impl->edited_new_text);
@@ -960,9 +1142,9 @@ error_creating_folder_over_existing_file_dialog (GtkFileChooserDefault *impl,
                                                 GError                *error)
 {
   error_dialog (impl,
-               _("The folder could not be created, as a file with the same name "
-                 "already exists.  Try using a different name for the folder, "
-                 "or rename the file first."),
+               _("The folder could not be created, as a file with the same "
+                  "name already exists.  Try using a different name for the "
+                  "folder, or rename the file first."),
                path, error);
 }
 
@@ -990,7 +1172,8 @@ error_changing_folder_dialog (GtkFileChooserDefault *impl,
 /* Changes folders, displaying an error dialog if this fails */
 static gboolean
 change_folder_and_display_error (GtkFileChooserDefault *impl,
-                                const GtkFilePath     *path)
+                                const GtkFilePath     *path,
+                                gboolean               clear_entry)
 {
   GError *error;
   gboolean result;
@@ -1012,7 +1195,7 @@ change_folder_and_display_error (GtkFileChooserDefault *impl,
   path_copy = gtk_file_path_copy (path);
 
   error = NULL;
-  result = gtk_file_chooser_default_update_current_folder (GTK_FILE_CHOOSER (impl), path_copy, TRUE, &error);
+  result = gtk_file_chooser_default_update_current_folder (GTK_FILE_CHOOSER (impl), path_copy, TRUE, clear_entry, &error);
 
   if (!result)
     error_changing_folder_dialog (impl, path_copy, error);
@@ -1079,6 +1262,36 @@ set_preview_widget (GtkFileChooserDefault *impl,
   update_preview_widget_visibility (impl);
 }
 
+/* Renders a "Search" icon at an appropriate size for a tree view */
+static GdkPixbuf *
+render_search_icon (GtkFileChooserDefault *impl)
+{
+  return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FIND, GTK_ICON_SIZE_MENU, NULL);
+}
+
+static GdkPixbuf *
+render_recent_icon (GtkFileChooserDefault *impl)
+{
+  GtkIconTheme *theme;
+  GdkPixbuf *retval;
+
+  if (gtk_widget_has_screen (GTK_WIDGET (impl)))
+    theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
+  else
+    theme = gtk_icon_theme_get_default ();
+
+  retval = gtk_icon_theme_load_icon (theme, "document-open-recent",
+                                     impl->icon_size, 0,
+                                     NULL);
+
+  /* fallback */
+  if (!retval)
+    retval = gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
+
+  return retval;
+}
+
+
 /* Re-reads all the icons for the shortcuts, used when the theme changes */
 struct ReloadIconsData
 {
@@ -1149,74 +1362,80 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl)
   do
     {
       gpointer data;
-      gboolean is_volume;
+      ShortcutType shortcut_type;
       gboolean pixbuf_visible;
       GdkPixbuf *pixbuf;
 
       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
                          SHORTCUTS_COL_DATA, &data,
-                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         SHORTCUTS_COL_TYPE, &shortcut_type,
                          SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
                          -1);
 
-      if (pixbuf_visible && data)
+      pixbuf = NULL;
+      if (pixbuf_visible)
         {
-         if (is_volume)
+         if (shortcut_type == SHORTCUT_TYPE_VOLUME)
            {
              GtkFileSystemVolume *volume;
 
              volume = data;
              pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
                                                           impl->icon_size, NULL);
-
-             gtk_list_store_set (impl->shortcuts_model, &iter,
-                                 SHORTCUTS_COL_PIXBUF, pixbuf,
-                                 -1);
-
-             if (pixbuf)
-               g_object_unref (pixbuf);
-           }
-         else if (gtk_file_system_path_is_local (impl->file_system, (GtkFilePath *)data))
-           {
-             const GtkFilePath *path;
-             struct ReloadIconsData *info;
-             GtkTreePath *tree_path;
-             GtkFileSystemHandle *handle;
-
-             path = data;
-
-             info = g_new0 (struct ReloadIconsData, 1);
-             info->impl = g_object_ref (impl);
-             tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
-             info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
-             gtk_tree_path_free (tree_path);
-
-             handle = gtk_file_system_get_info (impl->file_system, path,
-                                                GTK_FILE_INFO_ICON,
-                                                shortcuts_reload_icons_get_info_cb,
-                                                info);
-             impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
            }
-         else
+         else if (shortcut_type == SHORTCUT_TYPE_PATH)
+            {
+             if (gtk_file_system_path_is_local (impl->file_system, (GtkFilePath *)data))
+               {
+                 const GtkFilePath *path;
+                 struct ReloadIconsData *info;
+                 GtkTreePath *tree_path;
+                 GtkFileSystemHandle *handle;
+
+                 path = data;
+
+                 info = g_new0 (struct ReloadIconsData, 1);
+                 info->impl = g_object_ref (impl);
+                 tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+                 info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
+                 gtk_tree_path_free (tree_path);
+
+                 handle = gtk_file_system_get_info (impl->file_system, path,
+                                                    GTK_FILE_INFO_ICON,
+                                                    shortcuts_reload_icons_get_info_cb,
+                                                    info);
+                 impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
+               }
+              else
+               {
+                 GtkIconTheme *icon_theme;
+
+                 /* Don't call get_info for remote paths to avoid latency and
+                  * auth dialogs.
+                  * If we switch to a better bookmarks file format (XBEL), we
+                  * should use mime info to get a better icon.
+                  */
+                 icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
+                 pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-share", 
+                                                    impl->icon_size, 0, NULL);
+               }
+            }
+         else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
            {
-             GtkIconTheme *icon_theme;
+             pixbuf = render_search_icon (impl);
+            }
+         else if (shortcut_type == SHORTCUT_TYPE_RECENT)
+            {
+              pixbuf = render_recent_icon (impl);
+            }
 
-             /* Don't call get_info for remote paths to avoid latency and
-              * auth dialogs.
-              * If we switch to a better bookmarks file format (XBEL), we
-              * should use mime info to get a better icon.
-              */
-             icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
-             pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory", 
-                                                impl->icon_size, 0, NULL);
+          gtk_list_store_set (impl->shortcuts_model, &iter,
+                             SHORTCUTS_COL_PIXBUF, pixbuf,
+                             -1);
 
-             gtk_list_store_set (impl->shortcuts_model, &iter,
-                                 SHORTCUTS_COL_PIXBUF, pixbuf,
-                                 -1);
+          if (pixbuf)
+            g_object_unref (pixbuf);
 
-             if (pixbuf)
-               g_object_unref (pixbuf);
-           }
        }
     }
   while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
@@ -1347,7 +1566,6 @@ get_file_info_finished (GtkFileSystemHandle *handle,
 {
   gint pos = -1;
   gboolean cancelled = handle->cancelled;
-  gboolean is_volume = FALSE;
   GdkPixbuf *pixbuf;
   GtkTreePath *path;
   GtkTreeIter iter;
@@ -1412,15 +1630,18 @@ get_file_info_finished (GtkFileSystemHandle *handle,
                      SHORTCUTS_COL_PIXBUF, pixbuf,
                      SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
                      SHORTCUTS_COL_NAME, request->label_copy,
-                     SHORTCUTS_COL_IS_VOLUME, is_volume,
+                     SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
                      SHORTCUTS_COL_REMOVABLE, request->removable,
                      -1);
 
-  if (request->impl->shortcuts_filter_model)
-    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_filter_model));
+  if (request->impl->shortcuts_pane_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_pane_filter_model));
+
+  if (request->impl->shortcuts_combo_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_combo_filter_model));
 
-  if (request->type == SHORTCUTS_CURRENT_FOLDER
-      && request->impl->save_folder_combo != NULL)
+  if (request->type == SHORTCUTS_CURRENT_FOLDER &&
+      request->impl->save_folder_combo != NULL)
     {
       /* The current folder is updated via _activate_iter(), don't
        * have save_folder_combo_changed_cb() call _activate_iter()
@@ -1429,6 +1650,13 @@ get_file_info_finished (GtkFileSystemHandle *handle,
       g_signal_handlers_block_by_func (request->impl->save_folder_combo,
                                       G_CALLBACK (save_folder_combo_changed_cb),
                                       request->impl);
+      
+      if (request->impl->has_search)
+        pos -= 1;
+
+      if (request->impl->has_recent)
+        pos -= 2;
+
       gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos);
       g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
                                         G_CALLBACK (save_folder_combo_changed_cb),
@@ -1503,7 +1731,7 @@ _gtk_file_chooser_label_for_uri (const gchar *uri)
 static void
 shortcuts_insert_path (GtkFileChooserDefault *impl,
                       int                    pos,
-                      gboolean               is_volume,
+                      ShortcutType           shortcut_type,
                       GtkFileSystemVolume   *volume,
                       const GtkFilePath     *path,
                       const char            *label,
@@ -1516,79 +1744,89 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
   GtkTreeIter iter;
   GtkIconTheme *icon_theme;      
 
-  profile_start ("start", is_volume ? "volume" : (char *) path);
+  profile_start ("start", (shortcut_type == SHORTCUT_TYPE_VOLUME) ? "volume" 
+                         : ((shortcut_type == SHORTCUT_TYPE_PATH) ? (char *) path : NULL));
 
-  if (is_volume)
+  if (shortcut_type == SHORTCUT_TYPE_VOLUME)
     {
       data = volume;
       label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
       pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
                                                   impl->icon_size, NULL);
     }
-  else if (gtk_file_system_path_is_local (impl->file_system, path))
+  else if (shortcut_type == SHORTCUT_TYPE_PATH)
     {
-      struct ShortcutsInsertRequest *request;
-      GtkFileSystemHandle *handle;
-      GtkTreePath *p;
-
-      request = g_new0 (struct ShortcutsInsertRequest, 1);
-      request->impl = g_object_ref (impl);
-      request->path = gtk_file_path_copy (path);
-      request->name_only = TRUE;
-      request->removable = removable;
-      request->pos = pos;
-      request->type = type;
-      if (label)
-       request->label_copy = g_strdup (label);
-
-      if (pos == -1)
-       gtk_list_store_append (impl->shortcuts_model, &iter);
+      if (gtk_file_system_path_is_local (impl->file_system, path))
+        {
+          struct ShortcutsInsertRequest *request;
+          GtkFileSystemHandle *handle;
+          GtkTreePath *p;
+
+          request = g_new0 (struct ShortcutsInsertRequest, 1);
+          request->impl = g_object_ref (impl);
+          request->path = gtk_file_path_copy (path);
+          request->name_only = TRUE;
+          request->removable = removable;
+          request->pos = pos;
+          request->type = type;
+          if (label)
+           request->label_copy = g_strdup (label);
+
+          if (pos == -1)
+           gtk_list_store_append (impl->shortcuts_model, &iter);
+          else
+           gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
+
+          p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+          request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
+          gtk_tree_path_free (p);
+
+          handle = gtk_file_system_get_info (request->impl->file_system, request->path,
+                                            GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
+                                            get_file_info_finished, request);
+
+          gtk_list_store_set (impl->shortcuts_model, &iter,
+                             SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
+                             SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
+                             SHORTCUTS_COL_HANDLE, handle,
+                             -1);
+
+          shortcuts_update_count (impl, type, 1);
+
+          return;
+        }
       else
-       gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
-
-      p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
-      request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
-      gtk_tree_path_free (p);
-
-      handle = gtk_file_system_get_info (request->impl->file_system, request->path,
-                                        GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
-                                        get_file_info_finished, request);
+        {
+          /* Don't call get_info for remote paths to avoid latency and
+           * auth dialogs.
+           */
+          data = gtk_file_path_copy (path);
+          if (label)
+           label_copy = g_strdup (label);
+          else
+           {
+             gchar *uri;
 
-      gtk_list_store_set (impl->shortcuts_model, &iter,
-                         SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
-                         SHORTCUTS_COL_IS_VOLUME, is_volume,
-                         SHORTCUTS_COL_HANDLE, handle,
-                         -1);
+             uri = gtk_file_system_path_to_uri (impl->file_system, path);
 
-      shortcuts_update_count (impl, type, 1);
+             label_copy = _gtk_file_chooser_label_for_uri (uri);
 
-      return;
+             g_free (uri);
+           }
+    
+          /* If we switch to a better bookmarks file format (XBEL), we
+           * should use mime info to get a better icon.
+           */
+          icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
+          pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-share", 
+                                            impl->icon_size, 0, NULL);
+        }
     }
-  else
+   else
     {
-      /* Don't call get_info for remote paths to avoid latency and
-       * auth dialogs.
-       */
-      data = gtk_file_path_copy (path);
-      if (label)
-       label_copy = g_strdup (label);
-      else
-       {
-         gchar *uri;
-
-         uri = gtk_file_system_path_to_uri (impl->file_system, path);
-
-         label_copy = _gtk_file_chooser_label_for_uri (uri);
+      g_assert_not_reached ();
 
-         g_free (uri);
-       }
-    
-      /* If we switch to a better bookmarks file format (XBEL), we
-       * should use mime info to get a better icon.
-       */
-      icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
-      pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory", 
-                                        impl->icon_size, 0, NULL);
+      return;
     }
 
   if (pos == -1)
@@ -1603,13 +1841,16 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
                      SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
                      SHORTCUTS_COL_NAME, label_copy,
                      SHORTCUTS_COL_DATA, data,
-                     SHORTCUTS_COL_IS_VOLUME, is_volume,
+                     SHORTCUTS_COL_TYPE, shortcut_type,
                      SHORTCUTS_COL_REMOVABLE, removable,
                      SHORTCUTS_COL_HANDLE, NULL,
                      -1);
 
-  if (impl->shortcuts_filter_model)
-    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+  if (impl->shortcuts_pane_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
+
+  if (impl->shortcuts_combo_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
 
   if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
     {
@@ -1618,9 +1859,17 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
        * again.
        */
       gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
+
+      if (impl->has_search)
+        combo_pos -= 1;
+
+      if (impl->has_recent)
+        combo_pos -= 2;
+      
       g_signal_handlers_block_by_func (impl->save_folder_combo,
                                       G_CALLBACK (save_folder_combo_changed_cb),
                                       impl);
+      
       gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos);
       g_signal_handlers_unblock_by_func (impl->save_folder_combo,
                                         G_CALLBACK (save_folder_combo_changed_cb),
@@ -1635,6 +1884,54 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
   profile_end ("end", NULL);
 }
 
+static void
+shortcuts_append_search (GtkFileChooserDefault *impl)
+{
+  GdkPixbuf *pixbuf;
+  GtkTreeIter iter;
+
+  pixbuf = render_search_icon (impl);
+
+  gtk_list_store_append (impl->shortcuts_model, &iter);
+  gtk_list_store_set (impl->shortcuts_model, &iter,
+                     SHORTCUTS_COL_PIXBUF, pixbuf,
+                     SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
+                     SHORTCUTS_COL_NAME, _("Search"),
+                     SHORTCUTS_COL_DATA, NULL,
+                     SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEARCH,
+                     SHORTCUTS_COL_REMOVABLE, FALSE,
+                     -1);
+
+  if (pixbuf)
+    g_object_unref (pixbuf);
+
+  impl->has_search = TRUE;
+}
+
+static void
+shortcuts_append_recent (GtkFileChooserDefault *impl)
+{
+  GdkPixbuf *pixbuf;
+  GtkTreeIter iter;
+
+  pixbuf = render_recent_icon (impl);
+
+  gtk_list_store_append (impl->shortcuts_model, &iter);
+  gtk_list_store_set (impl->shortcuts_model, &iter,
+                      SHORTCUTS_COL_PIXBUF, pixbuf,
+                      SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
+                      SHORTCUTS_COL_NAME, _("Recently Used"),
+                      SHORTCUTS_COL_DATA, NULL,
+                      SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_RECENT,
+                      SHORTCUTS_COL_REMOVABLE, FALSE,
+                      -1);
+  
+  if (pixbuf)
+    g_object_unref (pixbuf);
+
+  impl->has_recent = TRUE;
+}
+
 /* Appends an item for the user's home directory to the shortcuts model */
 static void
 shortcuts_append_home (GtkFileChooserDefault *impl)
@@ -1653,7 +1950,8 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
 
   home_path = gtk_file_system_filename_to_path (impl->file_system, home);
 
-  shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
+  shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
+  impl->has_home = TRUE;
 
   gtk_file_path_free (home_path);
 
@@ -1664,29 +1962,16 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
 static void
 shortcuts_append_desktop (GtkFileChooserDefault *impl)
 {
-  char *name;
-  const char *home;
+  const char *name;
   GtkFilePath *path;
 
   profile_start ("start", NULL);
 
-#ifdef G_OS_WIN32
-  name = _gtk_file_system_win32_get_desktop ();
-#else
-  home = g_get_home_dir ();
-  if (home == NULL)
-    {
-      profile_end ("end - no home directory!?", NULL);
-      return;
-    }
-
-  name = g_build_filename (home, "Desktop", NULL);
-#endif
-
+  name = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
   path = gtk_file_system_filename_to_path (impl->file_system, name);
-  g_free (name);
+  shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
+  impl->has_desktop = TRUE;
 
-  shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
   /* We do not actually pop up an error dialog if there is no desktop directory
    * because some people may really not want to have one.
    */
@@ -1707,9 +1992,7 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
 
   profile_start ("start", NULL);
 
-  /* As there is no separator now, we want to start there.
-   */
-  start_row = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
+  start_row = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR) + 1;
   num_inserted = 0;
 
   for (; paths; paths = paths->next)
@@ -1721,11 +2004,13 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
       if (impl->local_only &&
          !gtk_file_system_path_is_local (impl->file_system, path))
        continue;
+      if (shortcut_find_position (impl, path) != -1)
+        continue;
 
       label = gtk_file_system_get_bookmark_label (impl->file_system, path);
 
       /* NULL GError, but we don't really want to show error boxes here */
-      shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
+      shortcuts_insert_path (impl, start_row + num_inserted, SHORTCUT_TYPE_PATH, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
       num_inserted++;
 
       g_free (label);
@@ -1744,6 +2029,21 @@ shortcuts_get_index (GtkFileChooserDefault *impl,
   int n;
 
   n = 0;
+  
+  if (where == SHORTCUTS_SEARCH)
+    goto out;
+
+  n += impl->has_search ? 1 : 0;
+
+  if (where == SHORTCUTS_RECENT)
+    goto out;
+
+  n += impl->has_recent ? 1 : 0;
+
+  if (where == SHORTCUTS_RECENT_SEPARATOR)
+    goto out;
+
+  n += impl->has_recent ? 1 : 0;
 
   if (where == SHORTCUTS_HOME)
     goto out;
@@ -1841,15 +2141,18 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
            }
        }
 
-      shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
+      shortcuts_insert_path (impl, start_row + n, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
       n++;
     }
 
   impl->num_volumes = n;
   g_slist_free (list);
 
-  if (impl->shortcuts_filter_model)
-    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+  if (impl->shortcuts_pane_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
+
+  if (impl->shortcuts_combo_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
 
   impl->changing_folder = old_changing_folders;
 
@@ -1859,11 +2162,13 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
 /* Inserts a separator node in the shortcuts list */
 static void
 shortcuts_insert_separator (GtkFileChooserDefault *impl,
-                           ShortcutsIndex where)
+                           ShortcutsIndex         where)
 {
   GtkTreeIter iter;
 
-  g_assert (where == SHORTCUTS_BOOKMARKS_SEPARATOR || where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
+  g_assert (where == SHORTCUTS_RECENT_SEPARATOR || 
+            where == SHORTCUTS_BOOKMARKS_SEPARATOR || 
+           where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
 
   gtk_list_store_insert (impl->shortcuts_model, &iter,
                         shortcuts_get_index (impl, where));
@@ -1872,6 +2177,7 @@ shortcuts_insert_separator (GtkFileChooserDefault *impl,
                      SHORTCUTS_COL_PIXBUF_VISIBLE, FALSE,
                      SHORTCUTS_COL_NAME, NULL,
                      SHORTCUTS_COL_DATA, NULL,
+                     SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEPARATOR,
                      -1);
 }
 
@@ -1884,7 +2190,7 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
   GtkTreeIter iter;
   GtkFilePath *list_selected = NULL;
   GtkFilePath *combo_selected = NULL;
-  gboolean is_volume;
+  ShortcutType shortcut_type;
   gpointer col_data;
 
   profile_start ("start", NULL);
@@ -1897,10 +2203,10 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), 
                          &iter, 
                          SHORTCUTS_COL_DATA, &col_data,
-                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         SHORTCUTS_COL_TYPE, &shortcut_type,
                          -1);
 
-      if (col_data && !is_volume)
+      if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
        list_selected = gtk_file_path_copy (col_data);
     }
 
@@ -1908,13 +2214,18 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (impl->save_folder_combo), 
                                     &iter))
     {
+      GtkTreeIter child_iter;
+
+      gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER  (impl->shortcuts_combo_filter_model),
+                                                       &child_iter,
+                                                       &iter);
       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), 
-                         &iter, 
+                         &child_iter, 
                          SHORTCUTS_COL_DATA, &col_data,
-                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         SHORTCUTS_COL_TYPE, &shortcut_type,
                          -1);
       
-      if (col_data && !is_volume)
+      if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
        combo_selected = gtk_file_path_copy (col_data);
     }
 
@@ -1924,16 +2235,20 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
                           impl->num_bookmarks + 1);
 
   impl->num_bookmarks = 0;
+  shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
 
   bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
   shortcuts_append_paths (impl, bookmarks);
   gtk_file_paths_free (bookmarks);
 
-  if (impl->num_bookmarks > 0)
-    shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
+  if (impl->num_bookmarks == 0)
+    shortcuts_remove_rows (impl, shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR), 1);
 
-  if (impl->shortcuts_filter_model)
-    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+  if (impl->shortcuts_pane_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
+
+  if (impl->shortcuts_combo_filter_model)
+    gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
 
   if (list_selected)
     {
@@ -1947,8 +2262,16 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
 
       pos = shortcut_find_position (impl, combo_selected);
       if (pos != -1)
-       gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), 
-                                 pos);
+        {
+          if (impl->has_search)
+            pos -= 1;
+
+          if (impl->has_recent)
+            pos -= 2;
+
+         gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
+        }
+
       gtk_file_path_free (combo_selected);
     }
   
@@ -1993,11 +2316,11 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
       if (base_path &&
          strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
        {
-         shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
+         shortcuts_insert_path (impl, pos, SHORTCUT_TYPE_VOLUME, 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, SHORTCUT_TYPE_PATH, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
          if (volume)
            gtk_file_system_volume_free (impl->file_system, volume);
        }
@@ -2006,7 +2329,15 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
        gtk_file_path_free (base_path);
     }
   else if (impl->save_folder_combo != NULL)
-    gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
+    {
+      if (impl->has_search)
+        pos -= 1;
+
+      if (impl->has_recent)
+        pos -= 2; /* + separator */
+
+      gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
+    }
 }
 
 /* Updates the current folder row in the shortcuts model */
@@ -2028,9 +2359,9 @@ shortcuts_update_current_folder (GtkFileChooserDefault *impl)
 
 /* Filter function used for the shortcuts filter model */
 static gboolean
-shortcuts_filter_cb (GtkTreeModel          *model,
-                    GtkTreeIter           *iter,
-                    gpointer               data)
+shortcuts_pane_filter_cb (GtkTreeModel *model,
+                         GtkTreeIter  *iter,
+                         gpointer      data)
 {
   GtkFileChooserDefault *impl;
   GtkTreePath *path;
@@ -2057,11 +2388,22 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
                                              GDK_TYPE_PIXBUF,  /* pixbuf */
                                              G_TYPE_STRING,    /* name */
                                              G_TYPE_POINTER,   /* path or volume */
-                                             G_TYPE_BOOLEAN,   /* is the previous column a volume? */
+                                             G_TYPE_INT,       /* ShortcutType */
                                              G_TYPE_BOOLEAN,   /* removable */
                                              G_TYPE_BOOLEAN,   /* pixbuf cell visibility */
                                              G_TYPE_POINTER);   /* GtkFileSystemHandle */
 
+  if (search_is_possible (impl))
+    {
+      shortcuts_append_search (impl);
+    }
+
+  if (impl->recent_manager)
+    {
+      shortcuts_append_recent (impl);
+      shortcuts_insert_separator (impl, SHORTCUTS_RECENT_SEPARATOR);
+    }
+  
   if (impl->file_system)
     {
       shortcuts_append_home (impl);
@@ -2069,12 +2411,12 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
       shortcuts_add_volumes (impl);
     }
 
-  impl->shortcuts_filter_model = shortcuts_model_filter_new (impl,
-                                                            GTK_TREE_MODEL (impl->shortcuts_model),
-                                                            NULL);
+  impl->shortcuts_pane_filter_model = shortcuts_pane_model_filter_new (impl,
+                                                                      GTK_TREE_MODEL (impl->shortcuts_model),
+                                                                      NULL);
 
-  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
-                                         shortcuts_filter_cb,
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
+                                         shortcuts_pane_filter_cb,
                                          impl,
                                          NULL);
 }
@@ -2127,7 +2469,7 @@ edited_idle_create_folder_cb (GtkFileSystemHandle *handle,
     goto out;
 
   if (!error)
-    change_folder_and_display_error (impl, path);
+    change_folder_and_display_error (impl, path, FALSE);
   else
     error_creating_folder_dialog (impl, path, g_error_copy (error));
 
@@ -2213,10 +2555,10 @@ renderer_edited_cb (GtkCellRendererText   *cell_renderer_text,
                    const gchar           *new_text,
                    GtkFileChooserDefault *impl)
 {
- /* work around bug #154921 */
 /* work around bug #154921 */
   g_object_set (cell_renderer_text, 
                "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
-   queue_edited_idle (impl, new_text);
+  queue_edited_idle (impl, new_text);
 }
 
 /* Callback used from the text cell renderer when the new folder edition gets
@@ -2226,10 +2568,10 @@ static void
 renderer_editing_canceled_cb (GtkCellRendererText   *cell_renderer_text,
                              GtkFileChooserDefault *impl)
 {
- /* work around bug #154921 */
 /* work around bug #154921 */
   g_object_set (cell_renderer_text, 
                "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
-   queue_edited_idle (impl, NULL);
+  queue_edited_idle (impl, NULL);
 }
 
 /* Creates the widgets for the filter combo box */
@@ -2242,16 +2584,19 @@ filter_create (GtkFileChooserDefault *impl)
   g_signal_connect (impl->filter_combo, "changed",
                    G_CALLBACK (filter_combo_changed), impl);
 
+  gtk_widget_set_tooltip_text (impl->filter_combo,
+                         _("Select which types of files are shown"));
+
   return impl->filter_combo;
 }
 
 static GtkWidget *
 button_new (GtkFileChooserDefault *impl,
-           const char *text,
-           const char *stock_id,
-           gboolean    sensitive,
-           gboolean    show,
-           GCallback   callback)
+           const char            *text,
+           const char            *stock_id,
+           gboolean               sensitive,
+           gboolean               show,
+           GCallback              callback)
 {
   GtkWidget *button;
   GtkWidget *image;
@@ -2292,16 +2637,16 @@ shortcut_find_position (GtkFileChooserDefault *impl,
   for (i = 0; i < current_folder_separator_idx; i++)
     {
       gpointer col_data;
-      gboolean is_volume;
+      ShortcutType shortcut_type;
 
       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
                          SHORTCUTS_COL_DATA, &col_data,
-                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         SHORTCUTS_COL_TYPE, &shortcut_type,
                          -1);
 
       if (col_data)
        {
-         if (is_volume)
+         if (shortcut_type == SHORTCUT_TYPE_VOLUME)
            {
              GtkFileSystemVolume *volume;
              GtkFilePath *base_path;
@@ -2317,7 +2662,7 @@ shortcut_find_position (GtkFileChooserDefault *impl,
              if (exists)
                return i;
            }
-         else
+         else if (shortcut_type == SHORTCUT_TYPE_PATH)
            {
              GtkFilePath *model_path;
 
@@ -2374,10 +2719,29 @@ add_bookmark_foreach_cb (GtkTreeModel *model,
 
   impl = (GtkFileChooserDefault *) data;
 
-  fs_model = impl->browse_files_model;
-  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
+  switch (impl->operation_mode)
+    {
+    case OPERATION_MODE_BROWSE:
+      fs_model = impl->browse_files_model;
+      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
+      file_path = _gtk_file_system_model_get_path (fs_model, &child_iter);
+      break;
+
+    case OPERATION_MODE_SEARCH:
+      search_get_valid_child_iter (impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                          SEARCH_MODEL_COL_PATH, &file_path,
+                          -1);
+      break;
 
-  file_path = _gtk_file_system_model_get_path (fs_model, &child_iter);
+    case OPERATION_MODE_RECENT:
+      recent_get_valid_child_iter (impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                          RECENT_MODEL_COL_PATH, &file_path,
+                          -1);
+      break;
+    }
+  
   shortcuts_add_bookmark_from_path (impl, file_path, -1);
 }
 
@@ -2423,7 +2787,7 @@ shortcuts_get_selected (GtkFileChooserDefault *impl,
   if (!gtk_tree_selection_get_selected (selection, NULL, &parent_iter))
     return FALSE;
 
-  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
                                                    iter,
                                                    &parent_iter);
   return TRUE;
@@ -2446,11 +2810,12 @@ remove_selected_bookmarks (GtkFileChooserDefault *impl)
                      SHORTCUTS_COL_DATA, &col_data,
                      SHORTCUTS_COL_REMOVABLE, &removable,
                      -1);
-  g_assert (col_data != NULL);
 
   if (!removable)
     return;
 
+  g_assert (col_data != NULL);
+
   path = col_data;
 
   error = NULL;
@@ -2488,10 +2853,28 @@ selection_check_foreach_cb (GtkTreeModel *model,
   closure = data;
   closure->num_selected++;
 
-  gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
+  switch (closure->impl->operation_mode)
+    {
+    case OPERATION_MODE_BROWSE:
+      gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
+      info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
+      is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE;
+      break;
 
-  info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
-  is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE;
+    case OPERATION_MODE_SEARCH:
+      search_get_valid_child_iter (closure->impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
+                          SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                          -1);
+      break;
+
+    case OPERATION_MODE_RECENT:
+      recent_get_valid_child_iter (closure->impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
+                          RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                          -1);
+      break;
+    }
 
   closure->all_folders = closure->all_folders && is_folder;
   closure->all_files = closure->all_files && !is_folder;
@@ -2545,8 +2928,27 @@ get_selected_path_foreach_cb (GtkTreeModel *model,
 
   closure = data;
 
-  gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
-  closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
+  switch (closure->impl->operation_mode)
+    {
+    case OPERATION_MODE_BROWSE:
+      gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
+      closure->path = _gtk_file_system_model_get_path (closure->impl->browse_files_model, &child_iter);
+      break;
+
+    case OPERATION_MODE_SEARCH:
+      search_get_valid_child_iter (closure->impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
+                          SEARCH_MODEL_COL_PATH, &closure->path,
+                          -1);
+      break;
+
+    case OPERATION_MODE_RECENT:
+      recent_get_valid_child_iter (closure->impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
+                          RECENT_MODEL_COL_PATH, &closure->path,
+                          -1);
+      break;
+    }
 }
 
 /* Returns a selected path from the file list */
@@ -2584,13 +2986,35 @@ update_tooltip (GtkTreeModel      *model,
 
   if (udata->tip == NULL)
     {
-      gtk_tree_model_sort_convert_iter_to_child_iter (udata->impl->sort_model,
-                                                     &child_iter,
-                                                     iter);
-  
-      info = _gtk_file_system_model_get_info (udata->impl->browse_files_model, &child_iter);
+      const gchar *display_name;
+
+      switch (udata->impl->operation_mode)
+        {
+        case OPERATION_MODE_BROWSE:
+          gtk_tree_model_sort_convert_iter_to_child_iter (udata->impl->sort_model,
+                                                          &child_iter,
+                                                          iter);
+          info = _gtk_file_system_model_get_info (udata->impl->browse_files_model, &child_iter);
+          display_name = gtk_file_info_get_display_name (info);
+          break;
+
+        case OPERATION_MODE_SEARCH:
+          search_get_valid_child_iter (udata->impl, &child_iter, iter);
+          gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->search_model), &child_iter,
+                              SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
+                              -1);
+          break;
+
+        case OPERATION_MODE_RECENT:
+          recent_get_valid_child_iter (udata->impl, &child_iter, iter);
+          gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->recent_model), &child_iter,
+                              RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
+                              -1);
+          break;
+        }
+
       udata->tip = g_strdup_printf (_("Add the folder '%s' to the bookmarks"),
-                                   gtk_file_info_get_display_name (info));
+                                    display_name);
     }
 }
 
@@ -2625,27 +3049,27 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
 
   if (impl->browse_files_popup_menu_add_shortcut_item)
     gtk_widget_set_sensitive (impl->browse_files_popup_menu_add_shortcut_item,
-                             (num_selected == 0) ? FALSE : active);
+                              (num_selected == 0) ? FALSE : active);
 
   if (active)
     {
       if (num_selected == 0)
-       tip = g_strdup_printf (_("Add the current folder to the bookmarks"));    
+        tip = g_strdup_printf (_("Add the current folder to the bookmarks"));
       else if (num_selected > 1)
-       tip = g_strdup_printf (_("Add the selected folders to the bookmarks"));
+        tip = g_strdup_printf (_("Add the selected folders to the bookmarks"));
       else
-       {
-         GtkTreeSelection *selection;
-         UpdateTooltipData data;
-         
-         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-         data.impl = impl;
-         data.tip = NULL;
-         gtk_tree_selection_selected_foreach (selection, update_tooltip, &data);
-         tip = data.tip;
-         
-       }
-      gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_add_button, tip, NULL);
+        {
+          GtkTreeSelection *selection;
+          UpdateTooltipData data;
+
+          selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+          data.impl = impl;
+          data.tip = NULL;
+          gtk_tree_selection_selected_foreach (selection, update_tooltip, &data);
+          tip = data.tip;
+        }
+
+      gtk_widget_set_tooltip_text (impl->browse_shortcuts_add_button, tip);
       g_free (tip);
     }
 }
@@ -2673,8 +3097,7 @@ bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
       gchar *tip;
 
       tip = g_strdup_printf (_("Remove the bookmark '%s'"), name);
-      gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_remove_button,
-                           tip, NULL);
+      gtk_widget_set_tooltip_text (impl->browse_shortcuts_remove_button, tip);
       g_free (tip);
     }
 
@@ -3026,9 +3449,11 @@ shortcuts_drag_motion_cb (GtkWidget             *widget,
     }
 #endif
 
-  if (context->suggested_action == GDK_ACTION_COPY || (context->actions & GDK_ACTION_COPY) != 0)
+  if (context->suggested_action == GDK_ACTION_COPY ||
+      (context->actions & GDK_ACTION_COPY) != 0)
     action = GDK_ACTION_COPY;
-  else if (context->suggested_action == GDK_ACTION_MOVE || (context->actions & GDK_ACTION_MOVE) != 0)
+  else if (context->suggested_action == GDK_ACTION_MOVE ||
+           (context->actions & GDK_ACTION_MOVE) != 0)
     action = GDK_ACTION_MOVE;
   else
     {
@@ -3098,7 +3523,7 @@ shortcuts_drop_uris (GtkFileChooserDefault *impl,
        }
       else
        {
-         GError *error;
+         GError *error = NULL;
 
          g_set_error (&error,
                       GTK_FILE_CHOOSER_ERROR,
@@ -3120,7 +3545,7 @@ shortcuts_reorder (GtkFileChooserDefault *impl,
 {
   GtkTreeIter iter;
   gpointer col_data;
-  gboolean is_volume;
+  ShortcutType shortcut_type;
   GtkTreePath *path;
   int old_position;
   int bookmarks_index;
@@ -3145,10 +3570,10 @@ shortcuts_reorder (GtkFileChooserDefault *impl,
   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,
+                     SHORTCUTS_COL_TYPE, &shortcut_type,
                      -1);
   g_assert (col_data != NULL);
-  g_assert (!is_volume);
+  g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
   
   file_path = col_data;
   file_path_copy = gtk_file_path_copy (file_path); /* removal below will free file_path, so we need a copy */
@@ -3223,8 +3648,22 @@ static void
 shortcuts_selection_changed_cb (GtkTreeSelection      *selection,
                                GtkFileChooserDefault *impl)
 {
+  GtkTreeIter iter;
+  GtkTreeIter child_iter;
+
   bookmarks_check_remove_sensitivity (impl);
   shortcuts_check_popup_sensitivity (impl);
+
+  if (impl->changing_folder)
+    return;
+
+  if (gtk_tree_selection_get_selected(selection, NULL, &iter))
+    {
+      gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
+                                                       &child_iter,
+                                                       &iter);
+      shortcuts_activate_iter (impl, &child_iter);
+    }
 }
 
 static gboolean
@@ -3232,17 +3671,11 @@ shortcuts_row_separator_func (GtkTreeModel *model,
                              GtkTreeIter  *iter,
                              gpointer      data)
 {
-  gint column = GPOINTER_TO_INT (data);
-  gchar *text;
+  ShortcutType shortcut_type;
 
-  gtk_tree_model_get (model, iter, column, &text, -1);
+  gtk_tree_model_get (model, iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
   
-  if (!text)
-    return TRUE;
-
-  g_free (text);
-
-  return FALSE;
+  return shortcut_type == SHORTCUT_TYPE_SEPARATOR;
 }
 
 /* Since GtkTreeView has a keybinding attached to '/', we need to catch
@@ -3487,7 +3920,7 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
   /* Accessible object name for the file chooser's shortcuts pane */
   atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Places"));
 
-  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_filter_model);
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_pane_filter_model);
 
   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
                                          GDK_BUTTON1_MASK,
@@ -3502,7 +3935,7 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
                     GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
-  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
   gtk_tree_selection_set_select_function (selection,
                                          shortcuts_select_func,
                                          impl, NULL);
@@ -3510,9 +3943,6 @@ 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_CALLBACK (shortcuts_row_activated_cb), impl);
-
   g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
                    G_CALLBACK (shortcuts_key_press_event_cb), impl);
 
@@ -3560,8 +3990,7 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
 
   gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
                                        shortcuts_row_separator_func,
-                                       GINT_TO_POINTER (SHORTCUTS_COL_NAME),
-                                       NULL);
+                                       NULL, NULL);
 
   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), column);
 
@@ -3601,8 +4030,8 @@ shortcuts_pane_create (GtkFileChooserDefault *impl,
                                                  TRUE,
                                                  G_CALLBACK (add_bookmark_button_clicked_cb));
   gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_add_button, TRUE, TRUE, 0);
-  gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_add_button,
-                        _("Add the selected folder to the Bookmarks"), NULL);
+  gtk_widget_set_tooltip_text (impl->browse_shortcuts_add_button,
+                        _("Add the selected folder to the Bookmarks"));
 
   /* Remove bookmark button */
 
@@ -3613,8 +4042,8 @@ shortcuts_pane_create (GtkFileChooserDefault *impl,
                                                     TRUE,
                                                     G_CALLBACK (remove_bookmark_button_clicked_cb));
   gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_remove_button, TRUE, TRUE, 0);
-  gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_remove_button,
-                        _("Remove the selected bookmark"), NULL);
+  gtk_widget_set_tooltip_text (impl->browse_shortcuts_remove_button,
+                        _("Remove the selected bookmark"));
 
   return vbox;
 }
@@ -3649,7 +4078,8 @@ trap_activate_cb (GtkWidget   *widget,
   if ((event->keyval == GDK_Return
        || event->keyval == GDK_ISO_Enter
        || event->keyval == GDK_KP_Enter
-       || event->keyval == GDK_space)
+       || event->keyval == GDK_space
+       || event->keyval == GDK_KP_Space)
       && ((event->state & modifiers) == 0)
       && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
           impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
@@ -3771,7 +4201,7 @@ file_list_drag_data_received_get_info_cb (GtkFileSystemHandle *handle,
        data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
       data->uris[1] == 0 && !error &&
       gtk_file_info_get_is_folder (info))
-    change_folder_and_display_error (data->impl, data->path);
+    change_folder_and_display_error (data->impl, data->path, FALSE);
   else
     {
       GError *error = NULL;
@@ -3932,6 +4362,8 @@ file_list_update_popup_menu (GtkFileChooserDefault *impl)
 {
   file_list_build_popup_menu (impl);
 
+  /* FIXME - handle OPERATION_MODE_SEARCH and OPERATION_MODE_RECENT */
+
   /* The sensitivity of the Add to Bookmarks item is set in
    * bookmarks_check_add_sensitivity()
    */
@@ -4031,9 +4463,114 @@ list_button_press_event_cb (GtkWidget             *widget,
   return TRUE;
 }
 
-/* Creates the widgets for the file list */
-static GtkWidget *
-create_file_list (GtkFileChooserDefault *impl)
+/* Sets the sort column IDs for the file list based on the operation mode */
+static void
+file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
+{
+  int name_id, mtime_id;
+
+  name_id = mtime_id = 0;
+
+  switch (impl->operation_mode)
+    {
+    case OPERATION_MODE_BROWSE:
+      name_id = FILE_LIST_COL_NAME;
+      mtime_id = FILE_LIST_COL_MTIME;
+      break;
+    case OPERATION_MODE_SEARCH:
+      name_id = SEARCH_MODEL_COL_PATH;
+      mtime_id = SEARCH_MODEL_COL_STAT;
+      break;
+    case OPERATION_MODE_RECENT:
+      name_id = RECENT_MODEL_COL_PATH;
+      mtime_id = RECENT_MODEL_COL_INFO;
+      break;
+    }
+
+  gtk_tree_view_column_set_sort_column_id (impl->list_name_column, name_id);
+  gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, mtime_id);
+}
+
+static gboolean
+file_list_query_tooltip_cb (GtkWidget  *widget,
+                            gint        x,
+                            gint        y,
+                            gboolean    keyboard_tip,
+                            GtkTooltip *tooltip,
+                            gpointer    user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+  GtkTreeIter iter, child_iter;
+  GtkTreePath *path = NULL;
+  GtkFilePath *file_path = NULL;
+  gchar *filename;
+
+  if (impl->operation_mode == OPERATION_MODE_BROWSE)
+    return FALSE;
+
+
+  gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                                     &x, &y,
+                                     keyboard_tip,
+                                     NULL, &path, NULL);
+                                       
+  if (!path)
+    return FALSE;
+
+  switch (impl->operation_mode)
+    {
+    case OPERATION_MODE_SEARCH:
+      if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
+        {
+          gtk_tree_path_free (path);
+          return FALSE;
+        }
+
+      search_get_valid_child_iter (impl, &child_iter, &iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                          SEARCH_MODEL_COL_PATH, &file_path,
+                          -1);
+      break;
+    
+    case OPERATION_MODE_RECENT:
+      if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
+        {
+          gtk_tree_path_free (path);
+          return FALSE;
+        }
+
+      recent_get_valid_child_iter (impl, &child_iter, &iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                          RECENT_MODEL_COL_PATH, &file_path,
+                          -1);
+      break;
+
+    case OPERATION_MODE_BROWSE:
+      g_assert_not_reached ();
+      return FALSE;
+    }
+
+  if (!file_path)
+    {
+      gtk_tree_path_free (path);
+      return FALSE;
+    }
+
+  filename = gtk_file_system_path_to_filename (impl->file_system, file_path);
+  gtk_tooltip_set_text (tooltip, filename);
+  gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                                 tooltip,
+                                 path);
+
+  g_free (filename);
+  gtk_tree_path_free (path);
+
+  return TRUE;
+}
+
+/* Creates the widgets for the file list */
+static GtkWidget *
+create_file_list (GtkFileChooserDefault *impl)
 {
   GtkWidget *swin;
   GtkTreeSelection *selection;
@@ -4044,7 +4581,7 @@ create_file_list (GtkFileChooserDefault *impl)
 
   swin = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
-                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
                                       GTK_SHADOW_IN);
 
@@ -4082,6 +4619,10 @@ create_file_list (GtkFileChooserDefault *impl)
   g_signal_connect (impl->browse_files_tree_view, "drag_motion",
                     G_CALLBACK (file_list_drag_motion_cb), impl);
 
+  g_object_set (impl->browse_files_tree_view, "has-tooltip", TRUE, NULL);
+  g_signal_connect (impl->browse_files_tree_view, "query-tooltip",
+                    G_CALLBACK (file_list_query_tooltip_cb), impl);
+
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
   gtk_tree_selection_set_select_function (selection,
                                          list_select_func,
@@ -4134,6 +4675,7 @@ create_file_list (GtkFileChooserDefault *impl)
   gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
 #endif
+
   /* Modification time column */
 
   column = gtk_tree_view_column_new ();
@@ -4144,8 +4686,11 @@ create_file_list (GtkFileChooserDefault *impl)
   gtk_tree_view_column_pack_start (column, renderer, TRUE);
   gtk_tree_view_column_set_cell_data_func (column, renderer,
                                           list_mtime_data_func, impl, NULL);
-  gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_MTIME);
   gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
+  impl->list_mtime_column = column;
+  
+  file_list_set_sort_column_ids (impl);
+
   gtk_widget_show_all (swin);
 
   return swin;
@@ -4162,29 +4707,6 @@ create_path_bar (GtkFileChooserDefault *impl)
   return path_bar;
 }
 
-static void
-set_filter_tooltip (GtkWidget *widget, 
-                   gpointer   data)
-{
-  GtkTooltips *tooltips = (GtkTooltips *)data;
-
-  if (GTK_IS_BUTTON (widget))
-    gtk_tooltips_set_tip (tooltips, widget,
-                         _("Select which types of files are shown"), 
-                         NULL);
-}
-
-static void
-realize_filter_combo (GtkWidget *combo,
-                     gpointer   data)
-{
-  GtkFileChooserDefault *impl = (GtkFileChooserDefault *)data;
-
-  gtk_container_forall (GTK_CONTAINER (combo),
-                       set_filter_tooltip,
-                       impl->tooltips);
-}
-
 /* Creates the widgets for the files/folders pane */
 static GtkWidget *
 file_pane_create (GtkFileChooserDefault *impl,
@@ -4220,9 +4742,6 @@ file_pane_create (GtkFileChooserDefault *impl,
 
   widget = filter_create (impl);
 
-  g_signal_connect (widget, "realize",
-                   G_CALLBACK (realize_filter_combo), impl);
-
   gtk_widget_show (widget);
   gtk_box_pack_end (GTK_BOX (impl->filter_combo_hbox), widget, FALSE, FALSE, 0);
 
@@ -4238,6 +4757,7 @@ expander_changed_cb (GtkExpander           *expander,
                     GParamSpec            *pspec,
                     GtkFileChooserDefault *impl)
 {
+  impl->expand_folders = gtk_expander_get_expanded(GTK_EXPANDER (impl->save_expander));
   update_appearance (impl);
 }
 
@@ -4252,9 +4772,66 @@ save_folder_combo_changed_cb (GtkComboBox           *combo,
     return;
 
   if (gtk_combo_box_get_active_iter (combo, &iter))
-    shortcuts_activate_iter (impl, &iter);
+    {
+      GtkTreeIter child_iter;
+      
+      gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
+                                                       &child_iter,
+                                                       &iter);
+      shortcuts_activate_iter (impl, &child_iter);
+    }
 }
 
+/* Filter function used to filter out the Search item and its separator.  
+ * Used for the "Save in folder" combo box, so that these items do not appear in it.
+ */
+static gboolean
+shortcuts_combo_filter_func (GtkTreeModel *model,
+                            GtkTreeIter  *iter,
+                            gpointer      data)
+{
+  GtkFileChooserDefault *impl;
+  GtkTreePath *tree_path;
+  gint *indices;
+  int idx;
+  gboolean retval;
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+  g_assert (model == GTK_TREE_MODEL (impl->shortcuts_model));
+
+  tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), iter);
+  g_assert (tree_path != NULL);
+
+  indices = gtk_tree_path_get_indices (tree_path);
+
+  retval = TRUE;
+
+  if (impl->has_search)
+    {
+      idx = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
+      if (idx == indices[0])
+        retval = FALSE;
+    }
+  
+  if (impl->has_recent)
+    {
+      idx = shortcuts_get_index (impl, SHORTCUTS_RECENT);
+      if (idx == indices[0])
+        retval = FALSE;
+      else
+        {
+          idx = shortcuts_get_index (impl, SHORTCUTS_RECENT_SEPARATOR);
+          if (idx == indices[0])
+            retval = FALSE;
+        }
+     }
+
+  gtk_tree_path_free (tree_path);
+
+  return retval;
+ }
+
 /* Creates the combo box with the save folders */
 static GtkWidget *
 save_folder_combo_create (GtkFileChooserDefault *impl)
@@ -4262,8 +4839,14 @@ save_folder_combo_create (GtkFileChooserDefault *impl)
   GtkWidget *combo;
   GtkCellRenderer *cell;
 
+  impl->shortcuts_combo_filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->shortcuts_model), NULL);
+  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
+                                         shortcuts_combo_filter_func,
+                                         impl,
+                                         NULL);
+
   combo = g_object_new (GTK_TYPE_COMBO_BOX,
-                       "model", impl->shortcuts_model,
+                       "model", impl->shortcuts_combo_filter_model,
                        "focus-on-click", FALSE,
                         NULL);
   gtk_widget_show (combo);
@@ -4285,8 +4868,7 @@ save_folder_combo_create (GtkFileChooserDefault *impl)
 
   gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
                                        shortcuts_row_separator_func,
-                                       GINT_TO_POINTER (SHORTCUTS_COL_NAME),
-                                       NULL);
+                                       NULL, NULL);
 
   g_signal_connect (combo, "changed",
                    G_CALLBACK (save_folder_combo_changed_cb), impl);
@@ -4460,6 +5042,14 @@ location_entry_set_initial_text (GtkFileChooserDefault *impl)
 static void
 location_switch_to_filename_entry (GtkFileChooserDefault *impl)
 {
+  /* when in search or recent files mode, we are not showing the
+   * location_entry_box container, so there's no point in switching
+   * to it.
+   */
+  if (impl->operation_mode == OPERATION_MODE_SEARCH ||
+      impl->operation_mode == OPERATION_MODE_RECENT)
+    return;
+
   if (impl->location_entry)
     gtk_widget_destroy (impl->location_entry);
 
@@ -4496,8 +5086,8 @@ 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)
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
     {
       GtkWindow *toplevel;
       GtkWidget *current_focus;
@@ -4554,6 +5144,29 @@ location_mode_set (GtkFileChooserDefault *impl,
   impl->location_mode = new_mode;
 }
 
+static void
+location_toggle_popup_handler (GtkFileChooserDefault *impl)
+{
+  /* If the file entry is not visible, show it.
+   * If it is visible, turn it off only if it is focused.  Otherwise, switch to the entry.
+   */
+  if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+    {
+      location_mode_set (impl, LOCATION_MODE_FILENAME_ENTRY, TRUE);
+    }
+  else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+    {
+      if (GTK_WIDGET_HAS_FOCUS (impl->location_entry))
+        {
+          location_mode_set (impl, LOCATION_MODE_PATH_BAR, TRUE);
+        }
+      else
+        {
+          gtk_widget_grab_focus (impl->location_entry);
+        }
+    }
+}
+
 /* Callback used when one of the location mode buttons is toggled */
 static void
 location_button_toggled_cb (GtkToggleButton *toggle,
@@ -4597,7 +5210,7 @@ location_button_create (GtkFileChooserDefault *impl)
 
   str = _("Type a file name");
 
-  gtk_tooltips_set_tip (impl->tooltips, impl->location_button, str, NULL);
+  gtk_widget_set_tooltip_text (impl->location_button, str);
   atk_object_set_name (gtk_widget_get_accessible (impl->location_button), str);
 }
 
@@ -4619,6 +5232,7 @@ browse_widgets_create (GtkFileChooserDefault *impl)
   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_hbox = hbox;
 
   location_button_create (impl);
   gtk_box_pack_start (GTK_BOX (hbox), impl->location_button, FALSE, FALSE, 0);
@@ -4648,7 +5262,6 @@ browse_widgets_create (GtkFileChooserDefault *impl)
   /* Paned widget */
   hpaned = gtk_hpaned_new ();
   gtk_widget_show (hpaned);
-  gtk_paned_set_position (GTK_PANED (hpaned), 200); /* FIXME: this sucks */
   gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
 
   widget = shortcuts_pane_create (impl, size_group);
@@ -4680,8 +5293,10 @@ gtk_file_chooser_default_constructor (GType                  type,
 
   gtk_widget_push_composite_child ();
 
-  /* Shortcuts model */
+  /* Recent files manager */
+  recent_manager_update (impl);
 
+  /* Shortcuts model */
   shortcuts_model_create (impl);
 
   /* The browse widgets */
@@ -4823,7 +5438,7 @@ set_file_system_backend (GtkFileChooserDefault *impl,
 
   impl->file_system = NULL;
   if (backend)
-    impl->file_system = _gtk_file_system_create (backend);
+    impl->file_system = gtk_file_system_create (backend);
   else
     {
       GtkSettings *settings = gtk_settings_get_default ();
@@ -4832,7 +5447,7 @@ set_file_system_backend (GtkFileChooserDefault *impl,
       g_object_get (settings, "gtk-file-chooser-backend", &default_backend, NULL);
       if (default_backend)
        {
-         impl->file_system = _gtk_file_system_create (default_backend);
+         impl->file_system = gtk_file_system_create (default_backend);
          g_free (default_backend);
        }
     }
@@ -4950,7 +5565,8 @@ gtk_file_chooser_default_set_property (GObject      *object,
          {
            gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
            
-           if ((action == GTK_FILE_CHOOSER_ACTION_SAVE || action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+           if ((action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+                 action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
                && impl->select_multiple)
              {
                g_warning ("Tried to change the file chooser action to SAVE or CREATE_FOLDER, but "
@@ -4960,6 +5576,7 @@ gtk_file_chooser_default_set_property (GObject      *object,
              }
            impl->action = action;
            update_appearance (impl);
+           settings_load (impl);
          }
       }
       break;
@@ -4997,7 +5614,8 @@ gtk_file_chooser_default_set_property (GObject      *object,
     case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
       {
        gboolean select_multiple = g_value_get_boolean (value);
-       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)
            && select_multiple)
          {
            g_warning ("Tried to set the file chooser to multiple selection mode, but this is "
@@ -5204,6 +5822,9 @@ gtk_file_chooser_default_dispose (GObject *object)
       impl->shortcuts_activate_iter_handle = NULL;
     }
 
+  search_stop_searching (impl, TRUE);
+  recent_stop_loading (impl);
+
   remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
 
   G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->dispose (object);
@@ -5300,8 +5921,8 @@ settings_notify_cb (GObject               *object,
 
   name = g_param_spec_get_name (pspec);
 
-  if (strcmp (name, "gtk-icon-theme-name") == 0
-      || strcmp (name, "gtk-icon-sizes") == 0)
+  if (strcmp (name, "gtk-icon-theme-name") == 0 ||
+      strcmp (name, "gtk-icon-sizes") == 0)
     change_icon_theme (impl);
 
   profile_end ("end", NULL);
@@ -5335,6 +5956,24 @@ check_icon_theme (GtkFileChooserDefault *impl)
   profile_end ("end", NULL);
 }
 
+static void
+recent_manager_update (GtkFileChooserDefault *impl)
+{
+  GtkRecentManager *manager;
+
+  profile_start ("start", NULL);
+
+  if (gtk_widget_has_screen (GTK_WIDGET (impl)))
+    manager = gtk_recent_manager_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
+  else
+    manager = gtk_recent_manager_get_default ();
+
+  if (impl->recent_manager != manager)
+    impl->recent_manager = manager;
+
+  profile_end ("end", NULL);
+}
+
 static void
 gtk_file_chooser_default_style_set (GtkWidget *widget,
                                    GtkStyle  *previous_style)
@@ -5375,12 +6014,44 @@ gtk_file_chooser_default_screen_changed (GtkWidget *widget,
 
   remove_settings_signal (impl, previous_screen);
   check_icon_theme (impl);
+  recent_manager_update (impl);
 
   g_signal_emit_by_name (widget, "default-size-changed");
 
   profile_end ("end", NULL);
 }
 
+static void
+gtk_file_chooser_default_size_allocate (GtkWidget     *widget,
+                                       GtkAllocation *allocation)
+{
+  GtkFileChooserDefault *impl;
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+  GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->size_allocate (widget, allocation);
+
+  if (!gtk_file_chooser_default_get_resizable (GTK_FILE_CHOOSER_EMBED (impl)))
+    {
+      /* The dialog is not resizable, we shouldn't
+       * trust in the size it has in this stage
+       */
+      return;
+    }
+
+  impl->default_width = allocation->width;
+  impl->default_height = allocation->height;
+
+  if (impl->preview_widget_active &&
+      impl->preview_widget &&
+      GTK_WIDGET_DRAWABLE (impl->preview_widget))
+    impl->default_width -= impl->preview_widget->allocation.width + PREVIEW_HBOX_SPACING;
+
+  if (impl->extra_widget &&
+      GTK_WIDGET_DRAWABLE (impl->extra_widget))
+    impl->default_height -= GTK_BOX (widget)->spacing + impl->extra_widget->allocation.height;
+}
+
 static gboolean
 get_is_file_filtered (GtkFileChooserDefault *impl,
                      const GtkFilePath     *path,
@@ -5434,16 +6105,21 @@ settings_load (GtkFileChooserDefault *impl)
   GtkFileChooserSettings *settings;
   LocationMode location_mode;
   gboolean show_hidden;
+  gboolean expand_folders;
 
   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);
+  expand_folders = _gtk_file_chooser_settings_get_expand_folders (settings);
 
   g_object_unref (settings);
 
   location_mode_set (impl, location_mode, TRUE);
   gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
+  impl->expand_folders = expand_folders;
+  if (impl->save_expander)
+    gtk_expander_set_expanded (GTK_EXPANDER (impl->save_expander), expand_folders);
 }
 
 static void
@@ -5455,6 +6131,7 @@ settings_save (GtkFileChooserDefault *impl)
 
   _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)));
+  _gtk_file_chooser_settings_set_expand_folders (settings, impl->expand_folders);
 
   /* NULL GError */
   _gtk_file_chooser_settings_save (settings, NULL);
@@ -5475,30 +6152,40 @@ gtk_file_chooser_default_map (GtkWidget *widget)
 
   GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->map (widget);
 
-  switch (impl->reload_state)
+  if (impl->operation_mode == OPERATION_MODE_BROWSE)
     {
-    case RELOAD_EMPTY:
-      /* The user didn't explicitly give us a folder to display, so we'll use the cwd */
-      current_working_dir = g_get_current_dir ();
-      gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl), current_working_dir);
-      g_free (current_working_dir);
-      break;
-
-    case RELOAD_HAS_FOLDER:
-      /* Nothing; we are already loading or loaded, so we don't need to reload */
-      break;
-
-    case RELOAD_WAS_UNMAPPED:
-      /* Just reload the current folder; else continue the pending load. */
-      if (impl->current_folder)
+      switch (impl->reload_state)
         {
-          pending_select_paths_store_selection (impl);
-          change_folder_and_display_error (impl, impl->current_folder);
-       }
-      break;
-
-    default:
-      g_assert_not_reached ();
+        case RELOAD_EMPTY:
+          /* The user didn't explicitly give us a folder to
+           * display, so we'll use the cwd
+           */
+          current_working_dir = g_get_current_dir ();
+          gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl),
+                                               current_working_dir);
+          g_free (current_working_dir);
+          break;
+        
+        case RELOAD_HAS_FOLDER:
+          /* Nothing; we are already loading or loaded, so we
+           * don't need to reload
+           */
+          break;
+
+        case RELOAD_WAS_UNMAPPED:
+          /* Just reload the current folder; else continue
+           * the pending load.
+           */
+          if (impl->current_folder)
+            {
+              pending_select_paths_store_selection (impl);
+              change_folder_and_display_error (impl, impl->current_folder, FALSE);
+            }
+          break;
+
+        default:
+          g_assert_not_reached ();
+      }
     }
 
   bookmarks_changed_cb (impl->file_system, impl);
@@ -5566,8 +6253,8 @@ install_list_model_filter (GtkFileChooserDefault *impl)
 
 #define COMPARE_DIRECTORIES                                                                                   \
   GtkFileChooserDefault *impl = user_data;                                                                    \
-  const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->browse_files_model, a);                          \
-  const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->browse_files_model, b);                          \
+  const GtkFileInfo *info_a = _gtk_file_system_model_get_info (impl->browse_files_model, a);                  \
+  const GtkFileInfo *info_b = _gtk_file_system_model_get_info (impl->browse_files_model, b);                  \
   gboolean dir_a, dir_b;                                                                                      \
                                                                                                               \
   if (info_a)                                                                                                 \
@@ -5966,12 +6653,6 @@ pending_select_paths_process (GtkFileChooserDefault *impl)
        * but rather on behalf of something else like GtkFileChooserButton.  In
        * that case, the chooser's selection should be what the caller expects,
        * as the user can't see that something else got selected.  See bug #165264.
-       *
-       * Also, we don't select the first file if we are not in OPEN mode.  Doing
-       * so would change the contents of the filename entry for SAVE or
-       * CREATE_FOLDER, which is undesired; in SELECT_FOLDER, we don't want to
-       * select a *different* folder from the one into which the user just
-       * navigated.
        */
       if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
        browse_files_select_first_row (impl);
@@ -6018,17 +6699,11 @@ browse_files_model_finished_loading_cb (GtkFileSystemModel    *model,
   profile_end ("end", NULL);
 }
 
-/* Gets rid of the old list model and creates a new one for the current folder */
-static gboolean
-set_list_model (GtkFileChooserDefault *impl,
-               GError               **error)
+static void
+stop_loading_and_clear_list_model (GtkFileChooserDefault *impl)
 {
-  g_assert (impl->current_folder != NULL);
-
-  profile_start ("start", NULL);
-
   load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
-
+  
   if (impl->browse_files_model)
     {
       g_object_unref (impl->browse_files_model);
@@ -6040,6 +6715,20 @@ set_list_model (GtkFileChooserDefault *impl,
       g_object_unref (impl->sort_model);
       impl->sort_model = NULL;
     }
+  
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+}
+
+/* Gets rid of the old list model and creates a new one for the current folder */
+static gboolean
+set_list_model (GtkFileChooserDefault *impl,
+               GError               **error)
+{
+  g_assert (impl->current_folder != NULL);
+
+  profile_start ("start", NULL);
+
+  stop_loading_and_clear_list_model (impl);
 
   set_busy_cursor (impl, TRUE);
   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
@@ -6114,6 +6803,12 @@ update_chooser_entry (GtkFileChooserDefault *impl)
   struct update_chooser_entry_selected_foreach_closure closure;
   const char *file_part;
 
+  /* no need to update the file chooser's entry if there's no entry */
+  if (impl->operation_mode == OPERATION_MODE_SEARCH ||
+      impl->operation_mode == OPERATION_MODE_RECENT ||
+      !impl->location_entry)
+    return;
+
   if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
        || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
        || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
@@ -6136,33 +6831,45 @@ update_chooser_entry (GtkFileChooserDefault *impl)
   else if (closure.num_selected == 1)
     {
       GtkTreeIter child_iter;
-      const GtkFileInfo *info;
-      gboolean change_entry;
+      
+      if (impl->operation_mode == OPERATION_MODE_BROWSE)
+        {
+          const GtkFileInfo *info;
+          gboolean change_entry;
 
-      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
-                                                     &child_iter,
-                                                     &closure.first_selected_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);
 
-      g_free (impl->browse_files_last_selected_name);
-      impl->browse_files_last_selected_name = g_strdup (gtk_file_info_get_display_name (info));
+          /* If the cursor moved to the row of the newly created folder, 
+           * retrieving info will return NULL.
+           */
+          if (!info)
+            return;
 
-      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 */
+          g_free (impl->browse_files_last_selected_name);
+          impl->browse_files_last_selected_name =
+            g_strdup (gtk_file_info_get_display_name (info));
 
-      if (change_entry)
-       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->browse_files_last_selected_name);
+          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 */
 
-      return;
+          if (change_entry)
+           _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+                                                   impl->browse_files_last_selected_name);
+
+          return;
+        }
     }
   else
     {
-      g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-                 || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
+      g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+                 impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
 
       /* Multiple selection, so just clear the entry. */
 
@@ -6212,7 +6919,7 @@ gtk_file_chooser_default_set_current_folder (GtkFileChooser    *chooser,
                                             const GtkFilePath *path,
                                             GError           **error)
 {
-  return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, error);
+  return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, FALSE, error);
 }
 
 
@@ -6221,6 +6928,7 @@ struct UpdateCurrentFolderData
   GtkFileChooserDefault *impl;
   GtkFilePath *path;
   gboolean keep_trail;
+  gboolean clear_entry;
   GtkFilePath *original_path;
   GError *original_error;
 };
@@ -6326,8 +7034,13 @@ update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
   /* Set the folder on the save entry */
 
   if (impl->location_entry)
-    _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
-                                            impl->current_folder);
+    {
+      _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+                                              impl->current_folder);
+
+      if (data->clear_entry)
+       _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+    }
 
   /* 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
@@ -6357,6 +7070,7 @@ static gboolean
 gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
                                                const GtkFilePath *path,
                                                gboolean           keep_trail,
+                                               gboolean           clear_entry,
                                                GError           **error)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
@@ -6364,6 +7078,18 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
 
   profile_start ("start", (char *) path);
 
+  switch (impl->operation_mode)
+    {
+    case OPERATION_MODE_SEARCH:
+      search_switch_to_browse_mode (impl);
+      break;
+    case OPERATION_MODE_RECENT:
+      recent_switch_to_browse_mode (impl);
+      break;
+    case OPERATION_MODE_BROWSE:
+      break;
+    }
+
   g_assert (path != NULL);
 
   if (impl->local_only &&
@@ -6386,6 +7112,7 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
   data->impl = impl;
   data->path = gtk_file_path_copy (path);
   data->keep_trail = keep_trail;
+  data->clear_entry = clear_entry;
 
   impl->reload_state = RELOAD_HAS_FOLDER;
 
@@ -6405,6 +7132,10 @@ gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
 
+  if (impl->operation_mode == OPERATION_MODE_SEARCH ||
+      impl->operation_mode == OPERATION_MODE_RECENT)
+    return NULL;
   if (impl->reload_state == RELOAD_EMPTY)
     {
       char *current_working_dir;
@@ -6429,8 +7160,8 @@ gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
 
-  g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-                   || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+  g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+                   impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
 
   pending_select_paths_free (impl);
   _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
@@ -6465,10 +7196,14 @@ gtk_file_chooser_default_select_path (GtkFileChooser    *chooser,
     return FALSE;
 
   if (!parent_path)
-    return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
+   return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
 
-  if (impl->load_state == LOAD_EMPTY)
-    same_path = FALSE;
+  if (impl->operation_mode == OPERATION_MODE_SEARCH ||
+      impl->operation_mode == OPERATION_MODE_RECENT ||
+      impl->load_state == LOAD_EMPTY)
+    {
+      same_path = FALSE;
+    }
   else
     {
       g_assert (impl->current_folder != NULL);
@@ -6563,6 +7298,17 @@ static void
 gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+
+  if (impl->operation_mode == OPERATION_MODE_SEARCH ||
+      impl->operation_mode == OPERATION_MODE_RECENT)
+    {
+      GtkTreeSelection *selection;
+      
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_selection_select_all (selection);
+      return;
+    }
+
   if (impl->select_multiple)
     gtk_tree_model_foreach (GTK_TREE_MODEL (impl->sort_model), 
                            maybe_select, impl);
@@ -6623,6 +7369,16 @@ check_save_entry (GtkFileChooserDefault *impl,
   *is_empty_ret = FALSE;
 
   current_folder = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
+  if (!current_folder)
+    {
+      *path_ret = NULL;
+      *is_well_formed_ret = FALSE;
+      *is_file_part_empty_ret = FALSE;
+      *is_folder = FALSE;
+
+      return;
+    }
+
   file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
 
   if (!file_part || file_part[0] == '\0')
@@ -6692,6 +7448,13 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
   struct get_paths_closure info;
   GtkWindow *toplevel;
   GtkWidget *current_focus;
+  gboolean file_list_seen;
+
+  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+    return search_get_selected_paths (impl);
+
+  if (impl->operation_mode == OPERATION_MODE_RECENT)
+    return recent_get_selected_paths (impl);
 
   info.impl = impl;
   info.result = NULL;
@@ -6703,12 +7466,14 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
   else
     current_focus = NULL;
 
+  file_list_seen = FALSE;
   if (current_focus == impl->browse_files_tree_view)
     {
       GtkTreeSelection *selection;
 
     file_list:
 
+      file_list_seen = TRUE;
       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
       gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
 
@@ -6743,8 +7508,12 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
          return NULL;
        }
 
-      g_assert (info.path_from_entry != NULL);
-      info.result = g_slist_prepend (info.result, info.path_from_entry);
+      if (info.path_from_entry)
+        info.result = g_slist_prepend (info.result, info.path_from_entry);
+      else if (!file_list_seen) 
+        goto file_list;
+      else
+        return NULL;
     }
   else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
     goto file_list;
@@ -6752,9 +7521,9 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
     goto file_entry;
   else
     {
-    /* The focus is on a dialog's action area button or something else */
-      if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-         || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+      /* 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; 
@@ -6913,7 +7682,7 @@ add_shortcut_get_info_cb (GtkFileSystemHandle *handle,
 
   pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
 
-  shortcuts_insert_path (data->impl, pos, FALSE, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
+  shortcuts_insert_path (data->impl, pos, SHORTCUT_TYPE_PATH, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
 
 out:
   g_object_unref (data->impl);
@@ -7027,15 +7796,15 @@ gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
   for (i = 0; i < impl->num_shortcuts; i++)
     {
       gpointer col_data;
-      gboolean is_volume;
+      ShortcutType shortcut_type;
       GtkFilePath *shortcut;
 
       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
                          SHORTCUTS_COL_DATA, &col_data,
-                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         SHORTCUTS_COL_TYPE, &shortcut_type,
                          -1);
       g_assert (col_data != NULL);
-      g_assert (!is_volume);
+      g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
 
       shortcut = col_data;
       if (gtk_file_path_compare (shortcut, path) == 0)
@@ -7084,15 +7853,15 @@ gtk_file_chooser_default_list_shortcut_folders (GtkFileChooser *chooser)
   for (i = 0; i < impl->num_shortcuts; i++)
     {
       gpointer col_data;
-      gboolean is_volume;
+      ShortcutType shortcut_type;
       GtkFilePath *shortcut;
 
       gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
                          SHORTCUTS_COL_DATA, &col_data,
-                         SHORTCUTS_COL_IS_VOLUME, &is_volume,
+                         SHORTCUTS_COL_TYPE, &shortcut_type,
                          -1);
       g_assert (col_data != NULL);
-      g_assert (!is_volume);
+      g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
 
       shortcut = col_data;
       list = g_slist_prepend (list, gtk_file_path_copy (shortcut));
@@ -7114,33 +7883,35 @@ find_good_size_from_style (GtkWidget *widget,
                           gint      *height)
 {
   GtkFileChooserDefault *impl;
-  gint default_width, default_height;
   int font_size;
-  GtkRequisition req;
-  GtkRequisition preview_req;
+  GdkScreen *screen;
+  double resolution;
 
   g_assert (widget->style != NULL);
   impl = GTK_FILE_CHOOSER_DEFAULT (widget);
 
-  font_size = pango_font_description_get_size (widget->style->font_desc);
-  font_size = PANGO_PIXELS (font_size);
-
-  default_width = font_size * NUM_CHARS;
-  default_height = font_size * NUM_LINES;
-
-  /* Use at least the requisition size not including the preview widget */
-  gtk_widget_size_request (widget, &req);
+  if (impl->default_width == 0 &&
+      impl->default_height == 0)
+    {
+      screen = gtk_widget_get_screen (widget);
+      if (screen)
+       {
+         resolution = gdk_screen_get_resolution (screen);
+         if (resolution < 0.0) /* will be -1 if the resolution is not defined in the GdkScreen */
+           resolution = 96.0;
+       }
+      else
+       resolution = 96.0; /* wheeee */
 
-  if (impl->preview_widget_active && impl->preview_widget)
-    gtk_widget_size_request (impl->preview_box, &preview_req);
-  else
-    preview_req.width = 0;
+      font_size = pango_font_description_get_size (widget->style->font_desc);
+      font_size = PANGO_PIXELS (font_size) * resolution / 72.0;
 
-  default_width = MAX (default_width, (req.width - (preview_req.width + PREVIEW_HBOX_SPACING)));
-  default_height = MAX (default_height, req.height);
+      impl->default_width = font_size * NUM_CHARS;
+      impl->default_height = font_size * NUM_LINES;
+    }
 
-  *width = default_width;
-  *height = default_height;
+  *width = impl->default_width;
+  *height = impl->default_height;
 }
 
 static void
@@ -7149,39 +7920,37 @@ gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
                                           gint                *default_height)
 {
   GtkFileChooserDefault *impl;
+  GtkRequisition req;
 
   impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
-
   find_good_size_from_style (GTK_WIDGET (chooser_embed), default_width, default_height);
 
-  if (impl->preview_widget_active && impl->preview_widget)
-    *default_width += impl->preview_box->requisition.width + PREVIEW_HBOX_SPACING;
+  if (impl->preview_widget_active &&
+      impl->preview_widget &&
+      GTK_WIDGET_VISIBLE (impl->preview_widget))
+    {
+      gtk_widget_size_request (impl->preview_box, &req);
+      *default_width += PREVIEW_HBOX_SPACING + req.width;
+    }
+
+  if (impl->extra_widget &&
+      GTK_WIDGET_VISIBLE (impl->extra_widget))
+    {
+      gtk_widget_size_request (impl->extra_align, &req);
+      *default_height += GTK_BOX (chooser_embed)->spacing + req.height;
+    }
 }
 
-static void
-gtk_file_chooser_default_get_resizable_hints (GtkFileChooserEmbed *chooser_embed,
-                                             gboolean            *resize_horizontally,
-                                             gboolean            *resize_vertically)
+static gboolean
+gtk_file_chooser_default_get_resizable (GtkFileChooserEmbed *chooser_embed)
 {
   GtkFileChooserDefault *impl;
 
-  g_return_if_fail (resize_horizontally != NULL);
-  g_return_if_fail (resize_vertically != NULL);
-
   impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
 
-  *resize_horizontally = TRUE;
-  *resize_vertically = TRUE;
-
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
-      impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-    {
-      if (! gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
-       {
-         *resize_horizontally = FALSE;
-         *resize_vertically = FALSE;
-       }
-    }
+  return (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+         impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+         gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)));
 }
 
 struct switch_folder_closure {
@@ -7228,7 +7997,7 @@ switch_to_selected_folder (GtkFileChooserDefault *impl)
 
   g_assert (closure.path && closure.num_selected == 1);
 
-  change_folder_and_display_error (impl, closure.path);
+  change_folder_and_display_error (impl, closure.path, FALSE);
 }
 
 /* Gets the GtkFileInfo for the selected row in the file list; assumes single
@@ -7427,6 +8196,23 @@ should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
     }
 }
 
+/* Gives the focus to the browse tree view only if it is visible */
+static void
+focus_browse_tree_view_if_possible (GtkFileChooserDefault *impl)
+{
+  gboolean do_focus;
+
+  if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+      && !gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
+    do_focus = FALSE;
+  else
+    do_focus = TRUE;
+
+  if (do_focus)
+    gtk_widget_grab_focus (impl->browse_files_tree_view);
+}
+
 static void
 action_create_folder_cb (GtkFileSystemHandle *handle,
                         const GtkFilePath   *path,
@@ -7523,7 +8309,7 @@ save_entry_get_info_cb (GtkFileSystemHandle *handle,
   else
     {
       /* This will display an error, which is what we want */
-      change_folder_and_display_error (data->impl, data->parent_path);
+      change_folder_and_display_error (data->impl, data->parent_path, FALSE);
     }
 
 out:
@@ -7692,6 +8478,12 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
 
       g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
 
+      if (impl->operation_mode == OPERATION_MODE_SEARCH)
+       return search_should_respond (impl);
+
+      if (impl->operation_mode == OPERATION_MODE_RECENT)
+        return recent_should_respond (impl);
+
       selection_check (impl, &num_selected, &all_files, &all_folders);
 
       if (num_selected > 2)
@@ -7765,15 +8557,14 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
       error = NULL;
       if (is_folder)
        {
-         if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
-             || 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);
+             change_folder_and_display_error (impl, path, TRUE);
              retval = FALSE;
            }
-         else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
-                  || GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+         else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+                  impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
            {
              /* The folder already exists, so we do not need to create it.
               * Just respond to terminate the dialog.
@@ -7816,25 +8607,6 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
       gtk_file_path_free (path);
       return retval;
     }
-  else if (impl->toplevel_last_focus_widget == impl->browse_shortcuts_tree_view)
-    {
-      /* The focus is on a dialog's action area button, *and* the widget that
-       * was focused immediately before it is the shortcuts list.  Switch to the
-       * selected shortcut and tell the caller not to respond.
-       */
-      GtkTreeIter iter;
-
-      if (shortcuts_get_selected (impl, &iter))
-       {
-         shortcuts_activate_iter (impl, &iter);
-         
-         gtk_widget_grab_focus (impl->browse_files_tree_view);
-       }
-      else
-       goto file_list;
-
-      return FALSE;
-    }
   else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
     {
       /* The focus is on a dialog's action area button, *and* the widget that
@@ -7842,6 +8614,11 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
        */
       goto file_list;
     }
+  else if (impl->operation_mode == OPERATION_MODE_SEARCH && impl->toplevel_last_focus_widget == impl->search_entry)
+    {
+      search_entry_activate_cb (GTK_ENTRY (impl->search_entry), impl);
+      return FALSE;
+    }
   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
@@ -7870,16 +8647,16 @@ gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
 
   impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
 
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
-      || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
     {
       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)
+  else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+          impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     widget = impl->location_entry;
   else
     {
@@ -7891,249 +8668,1774 @@ gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
   gtk_widget_grab_focus (widget);
 }
 
+/* Callback used from gtk_tree_selection_selected_foreach(); gets the selected GtkFilePaths */
 static void
-set_current_filter (GtkFileChooserDefault *impl,
-                   GtkFileFilter         *filter)
+search_selected_foreach_get_path_cb (GtkTreeModel *model,
+                                    GtkTreePath  *path,
+                                    GtkTreeIter  *iter,
+                                    gpointer      data)
 {
-  if (impl->current_filter != filter)
-    {
-      int filter_index;
-
-      /* NULL filters are allowed to reset to non-filtered status
-       */
-      filter_index = g_slist_index (impl->filters, filter);
-      if (impl->filters && filter && filter_index < 0)
-       return;
-
-      if (impl->current_filter)
-       g_object_unref (impl->current_filter);
-      impl->current_filter = filter;
-      if (impl->current_filter)
-       {
-         g_object_ref_sink (impl->current_filter);
-       }
-
-      if (impl->filters)
-       gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
-                                 filter_index);
-
-      if (impl->browse_files_model)
-       install_list_model_filter (impl);
-
-      g_object_notify (G_OBJECT (impl), "filter");
-    }
-}
+  GSList **list;
+  const GtkFilePath *file_path;
+  GtkFilePath *file_path_copy;
 
-static void
-filter_combo_changed (GtkComboBox           *combo_box,
-                     GtkFileChooserDefault *impl)
-{
-  gint new_index = gtk_combo_box_get_active (combo_box);
-  GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
+  list = data;
 
-  set_current_filter (impl, new_filter);
+  gtk_tree_model_get (model, iter, SEARCH_MODEL_COL_PATH, &file_path, -1);
+  file_path_copy = gtk_file_path_copy (file_path);
+  *list = g_slist_prepend (*list, file_path_copy);
 }
 
-static void
-check_preview_change (GtkFileChooserDefault *impl)
+/* Constructs a list of the selected paths in search mode */
+static GSList *
+search_get_selected_paths (GtkFileChooserDefault *impl)
 {
-  GtkTreePath *cursor_path;
-  const GtkFilePath *new_path;
-  const GtkFileInfo *new_info;
-
-  gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
-  if (cursor_path && impl->sort_model)
-    {
-      GtkTreeIter iter;
-      GtkTreeIter child_iter;
-
-      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);
+  GSList *result;
+  GtkTreeSelection *selection;
 
-      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
+  result = NULL;
 
-      new_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
-      new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
-    }
-  else
-    {
-      new_path = NULL;
-      new_info = NULL;
-    }
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  gtk_tree_selection_selected_foreach (selection, search_selected_foreach_get_path_cb, &result);
+  result = g_slist_reverse (result);
 
-  if (new_path != impl->preview_path &&
-      !(new_path && impl->preview_path &&
-       gtk_file_path_compare (new_path, impl->preview_path) == 0))
-    {
-      if (impl->preview_path)
-       {
-         gtk_file_path_free (impl->preview_path);
-         g_free (impl->preview_display_name);
-       }
+  return result;
+}
 
-      if (new_path)
-       {
-         impl->preview_path = gtk_file_path_copy (new_path);
-         impl->preview_display_name = g_strdup (gtk_file_info_get_display_name (new_info));
-       }
-      else
-       {
-         impl->preview_path = NULL;
-         impl->preview_display_name = NULL;
-       }
+/* Called from ::should_respond().  We return whether there are selected files
+ * in the search list.
+ */
+static gboolean
+search_should_respond (GtkFileChooserDefault *impl)
+{
+  GtkTreeSelection *selection;
 
-      if (impl->use_preview_label && impl->preview_label)
-       gtk_label_set_text (GTK_LABEL (impl->preview_label), impl->preview_display_name);
+  g_assert (impl->operation_mode == OPERATION_MODE_SEARCH);
 
-      g_signal_emit_by_name (impl, "update-preview");
-    }
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  return (gtk_tree_selection_count_selected_rows (selection) != 0);
 }
 
-static void
-shortcuts_activate_volume_mount_cb (GtkFileSystemHandle *handle,
-                                   GtkFileSystemVolume *volume,
-                                   const GError        *error,
-                                   gpointer             data)
+struct SearchHitInsertRequest
 {
+  GtkFileChooserDefault *impl;
   GtkFilePath *path;
+  GtkTreeRowReference *row_ref;
+};
+
+static void
+search_hit_get_info_cb (GtkFileSystemHandle *handle,
+                        const GtkFileInfo   *info,
+                        const GError        *error,
+                        gpointer             data)
+{
   gboolean cancelled = handle->cancelled;
-  GtkFileChooserDefault *impl = data;
+  GdkPixbuf *pixbuf = NULL;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GtkFileSystemHandle *model_handle;
+  gboolean is_folder = FALSE;
+  char *mime_type;
+  char *display_name;
+  struct SearchHitInsertRequest *request = data;
 
-  if (handle != impl->shortcuts_activate_iter_handle)
+  if (!request->impl->search_model)
     goto out;
 
-  impl->shortcuts_activate_iter_handle = NULL;
+  path = gtk_tree_row_reference_get_path (request->row_ref);
+  if (!path)
+    goto out;
 
-  set_busy_cursor (impl, FALSE);
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->search_model),
+                           &iter, path);
+  gtk_tree_path_free (path);
 
-  if (cancelled)
+  gtk_tree_model_get (GTK_TREE_MODEL (request->impl->search_model), &iter,
+                      SEARCH_MODEL_COL_HANDLE, &model_handle,
+                      -1);
+  if (handle != model_handle)
     goto out;
 
-  if (error)
-    {
-      char *msg;
+  /* set the handle to NULL in the model */
+  gtk_list_store_set (request->impl->search_model, &iter,
+                      SEARCH_MODEL_COL_HANDLE, NULL,
+                      -1);
 
-      msg = g_strdup_printf (_("Could not mount %s"),
-                            gtk_file_system_volume_get_display_name (impl->file_system, volume));
-      error_message (impl, msg, error->message);
-      g_free (msg);
+  if (cancelled)
+    goto out;
 
+  if (!info)
+    {
+      gtk_list_store_remove (request->impl->search_model, &iter);
       goto out;
     }
 
-  path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
-  if (path != NULL)
-    {
-      change_folder_and_display_error (impl, path);
-      gtk_file_path_free (path);
-    }
+  display_name = g_strdup (gtk_file_info_get_display_name (info));
+  mime_type = g_strdup (gtk_file_info_get_mime_type (info));
+  is_folder = gtk_file_info_get_is_folder (info);
+  pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
+                                      request->impl->icon_size, NULL);
+
+  gtk_list_store_set (request->impl->search_model, &iter,
+                      SEARCH_MODEL_COL_PIXBUF, pixbuf,
+                      SEARCH_MODEL_COL_DISPLAY_NAME, display_name,
+                      SEARCH_MODEL_COL_MIME_TYPE, mime_type,
+                      SEARCH_MODEL_COL_IS_FOLDER, is_folder,
+                      -1);
+
+  if (pixbuf)
+    g_object_unref (pixbuf);
 
 out:
-  g_object_unref (impl);
+  g_object_unref (request->impl);
+  gtk_file_path_free (request->path);
+  gtk_tree_row_reference_free (request->row_ref);
+  g_free (request);
+
   g_object_unref (handle);
 }
 
-
-/* Activates a volume by mounting it if necessary and then switching to its
- * base path.
- */
+/* Adds one hit from the search engine to the search_model */
 static void
-shortcuts_activate_volume (GtkFileChooserDefault *impl,
-                          GtkFileSystemVolume   *volume)
+search_add_hit (GtkFileChooserDefault *impl,
+               gchar                 *uri)
 {
   GtkFilePath *path;
+  char *filename;
+  char *tmp;
+  char *collation_key;
+  struct stat statbuf;
+  struct stat *statbuf_copy;
+  GtkTreeIter iter;
+  GtkTreePath *p;
+  GtkFileSystemHandle *handle;
+  struct SearchHitInsertRequest *request;
 
-  /* We ref the file chooser since volume_mount() may run a main loop, and the
-   * user could close the file chooser window in the meantime.
-   */
-  g_object_ref (impl);
+  path = gtk_file_system_uri_to_path (impl->file_system, uri);
+  if (!path)
+    return;
 
-  if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
+  filename = gtk_file_system_path_to_filename (impl->file_system, path);
+  if (!filename)
     {
-      set_busy_cursor (impl, TRUE);
-
-      impl->shortcuts_activate_iter_handle =
-        gtk_file_system_volume_mount (impl->file_system, volume,
-                                     shortcuts_activate_volume_mount_cb,
-                                     g_object_ref (impl));
+      gtk_file_path_free (path);
+      return;
     }
-  else
+
+  if (stat (filename, &statbuf) != 0)
     {
-      path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
-      if (path != NULL)
-        {
-          change_folder_and_display_error (impl, path);
-          gtk_file_path_free (path);
-        }
+      gtk_file_path_free (path);
+      g_free (filename);
+      return;
     }
 
-  g_object_unref (impl);
-}
-
-/* Opens the folder or volume at the specified iter in the shortcuts model */
-struct ShortcutsActivateData
-{
-  GtkFileChooserDefault *impl;
-  GtkFilePath *path;
-};
+  statbuf_copy = g_new (struct stat, 1);
+  *statbuf_copy = statbuf;
 
-static void
-shortcuts_activate_get_info_cb (GtkFileSystemHandle *handle,
-                               const GtkFileInfo   *info,
-                               const GError        *error,
-                               gpointer             user_data)
-{
-  gboolean cancelled = handle->cancelled;
-  struct ShortcutsActivateData *data = user_data;
+  tmp = g_filename_display_name (filename);
+  collation_key = g_utf8_collate_key_for_filename (tmp, -1);
+  g_free (tmp);
 
-  if (handle != data->impl->shortcuts_activate_iter_handle)
-    goto out;
+  request = g_new0 (struct SearchHitInsertRequest, 1);
+  request->impl = g_object_ref (impl);
+  request->path = gtk_file_path_copy (path);
 
-  data->impl->shortcuts_activate_iter_handle = NULL;
+  gtk_list_store_append (impl->search_model, &iter);
+  p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->search_model), &iter);
+  
+  request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->search_model), p);
+  gtk_tree_path_free (p);
 
-  if (cancelled)
-    goto out;
+  handle = gtk_file_system_get_info (impl->file_system, path,
+                                     GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_ICON | GTK_FILE_INFO_MIME_TYPE | GTK_FILE_INFO_DISPLAY_NAME,
+                                     search_hit_get_info_cb,
+                                     request);
 
-  if (!error && gtk_file_info_get_is_folder (info))
-    change_folder_and_display_error (data->impl, data->path);
-  else
-    gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl), data->path, NULL);
+  gtk_list_store_set (impl->search_model, &iter,
+                      SEARCH_MODEL_COL_PATH, path,
+                      SEARCH_MODEL_COL_COLLATION_KEY, collation_key,
+                      SEARCH_MODEL_COL_STAT, statbuf_copy,
+                      SEARCH_MODEL_COL_HANDLE, handle,
+                      -1);
+}
 
-out:
-  g_object_unref (data->impl);
-  gtk_file_path_free (data->path);
-  g_free (data);
+/* Callback used from GtkSearchEngine when we get new hits */
+static void
+search_engine_hits_added_cb (GtkSearchEngine *engine,
+                            GList           *hits,
+                            gpointer         data)
+{
+  GtkFileChooserDefault *impl;
+  GList *l;
+  
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
 
-  g_object_unref (handle);
+  for (l = hits; l; l = l->next)
+    search_add_hit (impl, (gchar*)l->data);
 }
 
+/* Callback used from GtkSearchEngine when the query is done running */
 static void
-shortcuts_activate_iter (GtkFileChooserDefault *impl,
-                        GtkTreeIter           *iter)
+search_engine_finished_cb (GtkSearchEngine *engine,
+                          gpointer         data)
 {
-  gpointer col_data;
-  gboolean is_volume;
+  GtkFileChooserDefault *impl;
+  
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
+  
+#if 0
+  /* EB: setting the model here will avoid loads of row events,
+   * but it'll make the search look like blocked.
+   */
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                           GTK_TREE_MODEL (impl->search_model_filter));
+#endif
 
-  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), "");
+  /* FMQ: if search was empty, say that we got no hits */
+  set_busy_cursor (impl, FALSE);
+}
+
+/* Displays a generic error when we cannot create a GtkSearchEngine.  
+ * It would be better if _gtk_search_engine_new() gave us a GError 
+ * with a better message, but it doesn't do that right now.
+ */
+static void
+search_error_could_not_create_client (GtkFileChooserDefault *impl)
+{
+  error_message (impl,
+                _("Could not start the search process"),
+                _("The program was not able to create a connection to the indexer "
+                  "daemon.  Please make sure it is running."));
+}
+
+static void
+search_engine_error_cb (GtkSearchEngine *engine,
+                       const gchar     *message,
+                       gpointer         data)
+{
+  GtkFileChooserDefault *impl;
+  
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+  search_stop_searching (impl, TRUE);
+  error_message (impl, _("Could not send the search request"), message);
+
+  set_busy_cursor (impl, FALSE);
+}
+
+/* Frees the data in the search_model */
+static void
+search_clear_model (GtkFileChooserDefault *impl, 
+                   gboolean               remove_from_treeview)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+
+  if (!impl->search_model)
+    return;
+
+  model = GTK_TREE_MODEL (impl->search_model);
+
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    do
+      {
+        GtkFilePath *path;
+        gchar *display_name;
+        gchar *collation_key;
+       struct stat *statbuf;
+        GtkFileSystemHandle *handle;
+
+       gtk_tree_model_get (model, &iter,
+                            SEARCH_MODEL_COL_PATH, &path,
+                            SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
+                            SEARCH_MODEL_COL_COLLATION_KEY, &collation_key,
+                           SEARCH_MODEL_COL_STAT, &statbuf,
+                            SEARCH_MODEL_COL_HANDLE, &handle,
+                           -1);
+        
+        if (handle)
+          gtk_file_system_cancel_operation (handle);
+
+        gtk_file_path_free (path);
+        g_free (display_name);
+        g_free (collation_key);
+       g_free (statbuf);
+      }
+    while (gtk_tree_model_iter_next (model, &iter));
+
+  g_object_unref (impl->search_model);
+  impl->search_model = NULL;
+  
+  g_object_unref (impl->search_model_filter);
+  impl->search_model_filter = NULL;
+  
+  g_object_unref (impl->search_model_sort);
+  impl->search_model_sort = NULL;
+
+  if (remove_from_treeview)
+    gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+}
+
+/* Stops any ongoing searches; does not touch the search_model */
+static void
+search_stop_searching (GtkFileChooserDefault *impl,
+                       gboolean               remove_query)
+{
+  if (remove_query && impl->search_query)
+    {
+      g_object_unref (impl->search_query);
+      impl->search_query = NULL;
+    }
+  
+  if (impl->search_engine)
+    {
+      _gtk_search_engine_stop (impl->search_engine);
+      
+      g_object_unref (impl->search_engine);
+      impl->search_engine = NULL;
+    }
+}
+
+/* Stops any pending searches, clears the file list, and switches back to OPERATION_MODE_BROWSE */
+static void
+search_switch_to_browse_mode (GtkFileChooserDefault *impl)
+{
+  g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
+
+  search_stop_searching (impl, FALSE);
+  search_clear_model (impl, TRUE);
+
+  gtk_widget_destroy (impl->search_hbox);
+  impl->search_hbox = NULL;
+  impl->search_entry = NULL;
+
+  gtk_widget_show (impl->browse_path_bar);
+  gtk_widget_show (impl->browse_new_folder_button);
+
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+    {
+      gtk_widget_show (impl->location_button);
+
+      if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+       gtk_widget_show (impl->location_entry_box);
+    }
+
+  impl->operation_mode = OPERATION_MODE_BROWSE;
+
+  file_list_set_sort_column_ids (impl);
+}
+
+/* Sort callback from the path column */
+static gint
+search_column_path_sort_func (GtkTreeModel *model,
+                             GtkTreeIter  *a,
+                             GtkTreeIter  *b,
+                             gpointer      user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+  GtkTreeIter child_a, child_b;
+  const char *collation_key_a, *collation_key_b;
+  gboolean is_folder_a, is_folder_b;
+
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
+
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_a,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
+                      SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_a,
+                      -1);
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_b,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
+                      SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_b,
+                      -1);
+
+  if (!collation_key_a)
+    return 1;
+
+  if (!collation_key_b)
+    return -1;
+
+  /* always show folders first */
+  if (is_folder_a != is_folder_b)
+    return is_folder_a ? 1 : -1;
+
+  return strcmp (collation_key_a, collation_key_b);
+}
+
+/* Sort callback from the modification time column */
+static gint
+search_column_mtime_sort_func (GtkTreeModel *model,
+                              GtkTreeIter  *a,
+                              GtkTreeIter  *b,
+                              gpointer      user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+  GtkTreeIter child_a, child_b;
+  const struct stat *statbuf_a, *statbuf_b;
+  gboolean is_folder_a, is_folder_b;
+
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
+
+  /* Note that although we store a whole struct stat in the model, we only
+   * compare the mtime here.  If we add another column relative to a struct stat
+   * (e.g. a file size column), we'll want another sort callback similar to this
+   * one as well.
+   */
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_a,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
+                      SEARCH_MODEL_COL_STAT, &statbuf_a,
+                      -1);
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_b,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
+                      SEARCH_MODEL_COL_STAT, &statbuf_b,
+                      -1);
+  
+  if (!statbuf_a)
+    return 1;
+
+  if (!statbuf_b)
+    return -1;
+
+  if (is_folder_a != is_folder_b)
+    return is_folder_a ? 1 : -1;
+
+  if (statbuf_a->st_mtime < statbuf_b->st_mtime)
+    return -1;
+  else if (statbuf_a->st_mtime > statbuf_b->st_mtime)
+    return 1;
+  else
+    return 0;
+}
+
+static gboolean
+search_get_is_filtered (GtkFileChooserDefault *impl,
+                        const GtkFilePath     *path,
+                        const gchar           *display_name,
+                        const gchar           *mime_type)
+{
+  GtkFileFilterInfo filter_info;
+  GtkFileFilterFlags needed;
+  gboolean result;
+
+  if (!impl->current_filter)
+    return FALSE;
+
+  filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
+  needed = gtk_file_filter_get_needed (impl->current_filter);
+
+  filter_info.display_name = display_name;
+  filter_info.mime_type = mime_type;
+
+  if (needed & GTK_FILE_FILTER_FILENAME)
+    {
+      filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
+      if (filter_info.filename)
+        filter_info.contains |= GTK_FILE_FILTER_FILENAME;
+    }
+  else
+    filter_info.filename = NULL;
+
+  if (needed & GTK_FILE_FILTER_URI)
+    {
+      filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
+      if (filter_info.uri)
+        filter_info.contains |= GTK_FILE_FILTER_URI;
+    }
+  else
+    filter_info.uri = NULL;
+
+  result = gtk_file_filter_filter (impl->current_filter, &filter_info);
+
+  if (filter_info.filename)
+    g_free ((gchar *) filter_info.filename);
+  if (filter_info.uri)
+    g_free ((gchar *) filter_info.uri);
+
+  return !result;
+
+}
+
+/* Visibility function for the recent filter model */
+static gboolean
+search_model_visible_func (GtkTreeModel *model,
+                           GtkTreeIter  *iter,
+                           gpointer      user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+  GtkFilePath *file_path;
+  gchar *display_name, *mime_type;
+  gboolean is_folder;
+
+  if (!impl->current_filter)
+    return TRUE;
+
+  gtk_tree_model_get (model, iter,
+                      SEARCH_MODEL_COL_PATH, &file_path,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                      SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
+                      SEARCH_MODEL_COL_MIME_TYPE, &mime_type,
+                      -1);
+
+  if (!display_name)
+    return TRUE;
+
+  if (is_folder)
+    return TRUE;
+
+  return !search_get_is_filtered (impl, file_path, display_name, mime_type);
+}
+
+/* Creates the search_model and puts it in the tree view */
+static void
+search_setup_model (GtkFileChooserDefault *impl)
+{
+  g_assert (impl->search_model == NULL);
+  g_assert (impl->search_model_filter == NULL);
+  g_assert (impl->search_model_sort == NULL);
+
+  /* We store these columns in the search model:
+   *
+   * SEARCH_MODEL_COL_PATH - a GtkFilePath for the hit's URI, stored as a
+   *   pointer not as a GTK_TYPE_FILE_PATH
+   * SEARCH_MODEL_COL_DISPLAY_NAME - a string with the display name, stored
+   *   as a pointer not as a G_TYPE_STRING
+   * SEARCH_MODEL_COL_COLLATION_KEY - collation key for the filename, stored
+   *   as a pointer not as a G_TYPE_STRING
+   * SEARCH_MODEL_COL_STAT - pointer to a struct stat
+   * SEARCH_MODEL_COL_HANDLE - handle used when getting the hit's info
+   * SEARCH_MODEL_COL_PIXBUF - GdkPixbuf for the hit's icon
+   * SEARCH_MODEL_COL_MIME_TYPE - a string with the hit's MIME type
+   * SEARCH_MODEL_COL_IS_FOLDER - a boolean flag for folders
+   *
+   * Keep this in sync with the enumeration defined near the beginning
+   * of this file.
+   */
+  impl->search_model = gtk_list_store_new (SEARCH_MODEL_COL_NUM_COLUMNS,
+                                          G_TYPE_POINTER,
+                                          G_TYPE_POINTER,
+                                          G_TYPE_POINTER,
+                                          G_TYPE_POINTER,
+                                           G_TYPE_POINTER,
+                                           GDK_TYPE_PIXBUF,
+                                           G_TYPE_POINTER,
+                                           G_TYPE_BOOLEAN);
+  
+  impl->search_model_filter =
+    GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->search_model), NULL));
+  gtk_tree_model_filter_set_visible_func (impl->search_model_filter,
+                                          search_model_visible_func,
+                                          impl, NULL);
+
+  impl->search_model_sort =
+    GTK_TREE_MODEL_SORT (search_model_sort_new (impl, GTK_TREE_MODEL (impl->search_model_filter)));
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model_sort),
+                                  SEARCH_MODEL_COL_PATH,
+                                  search_column_path_sort_func,
+                                  impl, NULL);
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model_sort),
+                                  SEARCH_MODEL_COL_STAT,
+                                  search_column_mtime_sort_func,
+                                  impl, NULL);
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->search_model_sort),
+                                       SEARCH_MODEL_COL_STAT,
+                                       GTK_SORT_DESCENDING);
+
+  /* EB: setting the model here will make the hits list update feel
+   * more "alive" than setting the model at the end of the search
+   * run
+   */
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                           GTK_TREE_MODEL (impl->search_model_sort));
+}
+
+static void
+search_get_valid_child_iter (GtkFileChooserDefault *impl,
+                             GtkTreeIter           *child_iter,
+                             GtkTreeIter           *iter)
+{
+  GtkTreeIter middle;
+
+  if (!impl->search_model)
+    return;
+
+  if (!impl->search_model_filter || !impl->search_model_sort)
+    return;
+
+  /* pass 1: get the iterator in the filter model */
+  gtk_tree_model_sort_convert_iter_to_child_iter (impl->search_model_sort,
+                                                  &middle, iter);
+  
+  /* pass 2: get the iterator in the real model */
+  gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
+                                                    child_iter, &middle);
+}
+
+/* Creates a new query with the specified text and launches it */
+static void
+search_start_query (GtkFileChooserDefault *impl,
+                   const gchar           *query_text)
+{
+  search_stop_searching (impl, FALSE);
+  search_clear_model (impl, TRUE);
+  search_setup_model (impl);
+  set_busy_cursor (impl, TRUE);
+
+  if (impl->search_engine == NULL)
+    impl->search_engine = _gtk_search_engine_new ();
+
+  if (!impl->search_engine)
+    {
+      set_busy_cursor (impl, FALSE);
+      search_error_could_not_create_client (impl); /* lame; we don't get an error code or anything */
+      return;
+    }
+
+  if (!impl->search_query)
+    {
+      impl->search_query = _gtk_query_new ();
+      _gtk_query_set_text (impl->search_query, query_text);
+    }
+  
+  _gtk_search_engine_set_query (impl->search_engine, impl->search_query);
+
+  g_signal_connect (impl->search_engine, "hits-added",
+                   G_CALLBACK (search_engine_hits_added_cb), impl);
+  g_signal_connect (impl->search_engine, "finished",
+                   G_CALLBACK (search_engine_finished_cb), impl);
+  g_signal_connect (impl->search_engine, "error",
+                   G_CALLBACK (search_engine_error_cb), impl);
+
+  _gtk_search_engine_start (impl->search_engine);
+}
+
+/* Callback used when the user presses Enter while typing on the search
+ * entry; starts the query
+ */
+static void
+search_entry_activate_cb (GtkEntry *entry,
+                         gpointer data)
+{
+  GtkFileChooserDefault *impl;
+  const char *text;
+
+  impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+  text = gtk_entry_get_text (GTK_ENTRY (impl->search_entry));
+  if (strlen (text) == 0)
+    return;
+
+  /* reset any existing query object */
+  if (impl->search_query)
+    {
+      g_object_unref (impl->search_query);
+      impl->search_query = NULL;
+    }
+
+  search_start_query (impl, text);
+}
+
+/* Hides the path bar and creates the search entry */
+static void
+search_setup_widgets (GtkFileChooserDefault *impl)
+{
+  GtkWidget *label;
+
+  impl->search_hbox = gtk_hbox_new (FALSE, 12);
+
+  /* Label */
+
+  label = gtk_label_new_with_mnemonic (_("_Search:"));
+  gtk_box_pack_start (GTK_BOX (impl->search_hbox), label, FALSE, FALSE, 0);
+
+  /* Entry */
+
+  impl->search_entry = gtk_entry_new ();
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->search_entry);
+  g_signal_connect (impl->search_entry, "activate",
+                   G_CALLBACK (search_entry_activate_cb),
+                   impl);
+  gtk_box_pack_start (GTK_BOX (impl->search_hbox), impl->search_entry, TRUE, TRUE, 0);
+
+  /* if there already is a query, restart it */
+  if (impl->search_query)
+    {
+      gchar *query = _gtk_query_get_text (impl->search_query);
+
+      if (query)
+        {
+          gtk_entry_set_text (GTK_ENTRY (impl->search_entry), query);
+          search_start_query (impl, query);
+
+          g_free (query);
+        }
+      else
+        {
+          g_object_unref (impl->search_query);
+          impl->search_query = NULL;
+        }
+    }
+
+  gtk_widget_hide (impl->browse_path_bar);
+  gtk_widget_hide (impl->browse_new_folder_button);
+
+  /* Box for search widgets */
+  gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->search_hbox, TRUE, TRUE, 0);
+  gtk_widget_show_all (impl->search_hbox);
+
+  /* Hide the location widgets temporarily */
+
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+    {
+      gtk_widget_hide (impl->location_button);
+      gtk_widget_hide (impl->location_entry_box);
+    }
+
+  gtk_widget_grab_focus (impl->search_entry);
+
+  /* FMQ: hide the filter combo? */
+}
+
+/* Main entry point to the searching functions; this gets called when the user
+ * activates the Search shortcut.
+ */
+static void
+search_activate (GtkFileChooserDefault *impl)
+{
+  OperationMode previous_mode;
+  
+  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+    {
+      gtk_widget_grab_focus (impl->search_entry);
+      return;
+    }
+
+  previous_mode = impl->operation_mode;
+  impl->operation_mode = OPERATION_MODE_SEARCH;
+
+  switch (previous_mode)
+    {
+    case OPERATION_MODE_RECENT:
+      recent_stop_loading (impl);
+      recent_clear_model (impl, TRUE);
+      break;
+
+    case OPERATION_MODE_BROWSE:
+      stop_loading_and_clear_list_model (impl);
+      break;
+
+    case OPERATION_MODE_SEARCH:
+      g_assert_not_reached ();
+      break;
+    }
+
+  g_assert (impl->search_hbox == NULL);
+  g_assert (impl->search_entry == NULL);
+  g_assert (impl->search_model == NULL);
+  g_assert (impl->search_model_filter == NULL);
+
+  search_setup_widgets (impl);
+  file_list_set_sort_column_ids (impl);
+}
+
+/*
+ * Recent files support
+ */
+
+/* Frees the data in the recent_model */
+static void
+recent_clear_model (GtkFileChooserDefault *impl,
+                    gboolean               remove_from_treeview)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+
+  if (!impl->recent_model)
+    return;
+
+  model = GTK_TREE_MODEL (impl->recent_model);
+  
+  if (remove_from_treeview)
+    gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+
+  if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      do
+        {
+          GtkFilePath *file_path;
+          GtkFileSystemHandle *handle;
+          GtkRecentInfo *recent_info;
+          gchar *display_name;
+
+          gtk_tree_model_get (model, &iter,
+                              RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
+                              RECENT_MODEL_COL_PATH, &file_path,
+                              RECENT_MODEL_COL_HANDLE, &handle,
+                              RECENT_MODEL_COL_INFO, &recent_info,
+                              -1);
+          
+          if (handle)
+            gtk_file_system_cancel_operation (handle);
+
+          gtk_file_path_free (file_path);
+          gtk_recent_info_unref (recent_info);
+          g_free (display_name);
+        }
+      while (gtk_tree_model_iter_next (model, &iter));
+    }
+
+  g_object_unref (impl->recent_model);
+  impl->recent_model = NULL;
+
+  g_object_unref (impl->recent_model_filter);
+  impl->recent_model_filter = NULL;
+
+  g_object_unref (impl->recent_model_sort);
+  impl->recent_model_sort = NULL;
+}
+
+/* Stops any ongoing loading of the recent files list; does
+ * not touch the recent_model
+ */
+static void
+recent_stop_loading (GtkFileChooserDefault *impl)
+{
+  if (impl->load_recent_id)
+    {
+      g_source_remove (impl->load_recent_id);
+      impl->load_recent_id = 0;
+    }
+}
+
+/* Stops any pending load, clears the file list, and switches
+ * back to OPERATION_MODE_BROWSE
+ */
+static void
+recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
+{
+  g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
+
+  recent_stop_loading (impl);
+  recent_clear_model (impl, TRUE);
+
+  gtk_widget_show (impl->browse_path_bar);
+  gtk_widget_show (impl->browse_new_folder_button);
+
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+    {
+      gtk_widget_show (impl->location_button);
+
+      if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+       gtk_widget_show (impl->location_entry_box);
+    }
+
+  impl->operation_mode = OPERATION_MODE_BROWSE;
+
+  file_list_set_sort_column_ids (impl);
+}
+
+/* Sort callback from the modification time column */
+static gint
+recent_column_mtime_sort_func (GtkTreeModel *model,
+                              GtkTreeIter  *a,
+                              GtkTreeIter  *b,
+                              gpointer      user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+  GtkTreeIter child_a, child_b;
+  GtkRecentInfo *info_a, *info_b;
+  gboolean is_folder_a, is_folder_b;
+
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
+
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_a,
+                      RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
+                      RECENT_MODEL_COL_INFO, &info_a,
+                      -1);
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_b,
+                      RECENT_MODEL_COL_IS_FOLDER, &is_folder_b,
+                      RECENT_MODEL_COL_INFO, &info_b,
+                      -1);
+  
+  if (!info_a)
+    return 1;
+
+  if (!info_b)
+    return -1;
+
+  /* folders always go first */
+  if (is_folder_a != is_folder_b)
+    return is_folder_a ? 1 : -1;
+
+  if (gtk_recent_info_get_modified (info_a) < gtk_recent_info_get_modified (info_b))
+    return -1;
+  else if (gtk_recent_info_get_modified (info_a) > gtk_recent_info_get_modified (info_b))
+    return 1;
+  else
+    return 0;
+}
+
+static gint
+recent_column_path_sort_func (GtkTreeModel *model,
+                              GtkTreeIter  *a,
+                              GtkTreeIter  *b,
+                              gpointer      user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+  GtkTreeIter child_a, child_b;
+  gboolean is_folder_a, is_folder_b;
+  gchar *name_a, *name_b;
+
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
+  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
+
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_a,
+                      RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
+                      RECENT_MODEL_COL_DISPLAY_NAME, &name_a,
+                      -1);
+  gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_b,
+                      RECENT_MODEL_COL_IS_FOLDER, &is_folder_b,
+                      RECENT_MODEL_COL_DISPLAY_NAME, &name_b,
+                      -1);
+
+  if (!name_a)
+    return 1;
+
+  if (!name_b)
+    return -1;
+
+  if (is_folder_a != is_folder_b)
+    return is_folder_a ? 1 : -1;
+
+  return strcmp (name_a, name_b);
+}
+
+static gboolean
+recent_get_is_filtered (GtkFileChooserDefault *impl,
+                        const GtkFilePath     *path,
+                        GtkRecentInfo         *recent_info)
+{
+  GtkFileFilterInfo filter_info;
+  GtkFileFilterFlags needed;
+  gboolean result;
+
+  if (!impl->current_filter)
+    return FALSE;
+
+  filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
+  needed = gtk_file_filter_get_needed (impl->current_filter);
+
+  filter_info.display_name = gtk_recent_info_get_display_name (recent_info);
+  filter_info.mime_type = gtk_recent_info_get_mime_type (recent_info);
+
+  if (needed & GTK_FILE_FILTER_FILENAME)
+    {
+      filter_info.filename = gtk_file_system_path_to_filename (impl->file_system, path);
+      if (filter_info.filename)
+        filter_info.contains |= GTK_FILE_FILTER_FILENAME;
+    }
+  else
+    filter_info.filename = NULL;
+
+  if (needed & GTK_FILE_FILTER_URI)
+    {
+      filter_info.uri = gtk_file_system_path_to_uri (impl->file_system, path);
+      if (filter_info.uri)
+        filter_info.contains |= GTK_FILE_FILTER_URI;
+    }
+  else
+    filter_info.uri = NULL;
+
+  result = gtk_file_filter_filter (impl->current_filter, &filter_info);
+
+  if (filter_info.filename)
+    g_free ((gchar *) filter_info.filename);
+  if (filter_info.uri)
+    g_free ((gchar *) filter_info.uri);
+
+  return !result;
+}
+
+/* Visibility function for the recent filter model */
+static gboolean
+recent_model_visible_func (GtkTreeModel *model,
+                           GtkTreeIter  *iter,
+                           gpointer      user_data)
+{
+  GtkFileChooserDefault *impl = user_data;
+  GtkFilePath *file_path;
+  GtkRecentInfo *recent_info;
+  gboolean is_folder;
+
+  if (!impl->current_filter)
+    return TRUE;
+
+  gtk_tree_model_get (model, iter,
+                      RECENT_MODEL_COL_INFO, &recent_info,
+                      RECENT_MODEL_COL_PATH, &file_path,
+                      RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                      -1);
+
+  if (!recent_info)
+    return TRUE;
+
+  if (is_folder)
+    return TRUE;
+
+  return !recent_get_is_filtered (impl, file_path, recent_info);
+}
+
+static void
+recent_setup_model (GtkFileChooserDefault *impl)
+{
+  g_assert (impl->recent_model == NULL);
+  g_assert (impl->recent_model_filter == NULL);
+  g_assert (impl->recent_model_sort == NULL);
+
+  /* We store these columns in the search model:
+   *
+   * RECENT_MODEL_COL_PATH - a pointer to GtkFilePath for the hit's URI,
+   *   stored as a pointer and not as a GTK_TYPE_FILE_PATH;
+   * RECENT_MODEL_COL_DISPLAY_NAME - a string with the display name,
+   *   stored as a pointer and not as a G_TYPE_STRING;
+   * RECENT_MODEL_COL_INFO - GtkRecentInfo, stored as a pointer and not
+   *   as a GTK_TYPE_RECENT_INFO;
+   * RECENT_MODEL_COL_IS_FOLDER - boolean flag;
+   * RECENT_MODEL_COL_HANDLE - GtkFileSystemHandle, stored as a pointer
+   *   and not as a GTK_TYPE_FILE_SYSTEM_HANDLE;
+   *
+   * Keep this in sync with the enumeration defined near the beginning of
+   * this file.
+   */
+  impl->recent_model = gtk_list_store_new (RECENT_MODEL_COL_NUM_COLUMNS,
+                                          G_TYPE_POINTER,
+                                          G_TYPE_POINTER,
+                                          G_TYPE_POINTER,
+                                           G_TYPE_BOOLEAN,
+                                           G_TYPE_POINTER);
+
+  impl->recent_model_filter =
+    GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->recent_model), NULL));
+  gtk_tree_model_filter_set_visible_func (impl->recent_model_filter,
+                                          recent_model_visible_func,
+                                          impl,
+                                          NULL);
+  
+  /* this is the model that will actually be added to
+   * the browse_files_tree_view widget; remember: we are
+   * stuffing the real model into a filter model and then
+   * into a sort model; this means we'll have to translate
+   * the child iterator *twice* to get from a path or an
+   * iterator coming from the tree view widget to the
+   * real data inside the model.
+   */
+  impl->recent_model_sort =
+    GTK_TREE_MODEL_SORT (recent_model_sort_new (impl, GTK_TREE_MODEL (impl->recent_model_filter)));
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model_sort),
+                                  RECENT_MODEL_COL_PATH,
+                                  recent_column_path_sort_func,
+                                  impl, NULL);
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model_sort),
+                                   RECENT_MODEL_COL_INFO,
+                                   recent_column_mtime_sort_func,
+                                   impl, NULL);
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->recent_model_sort),
+                                        RECENT_MODEL_COL_INFO,
+                                        GTK_SORT_DESCENDING);
+}
+
+typedef struct
+{
+  GtkFileChooserDefault *impl;
+  GList *items;
+  gint n_items;
+  gint n_loaded_items;
+  guint needs_sorting : 1;
+} RecentLoadData;
+
+static void
+recent_idle_cleanup (gpointer data)
+{
+  RecentLoadData *load_data = data;
+  GtkFileChooserDefault *impl = load_data->impl;
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                           GTK_TREE_MODEL (impl->recent_model_sort));
+
+  set_busy_cursor (impl, FALSE);
+  
+  impl->load_recent_id = 0;
+  
+  if (load_data->items)
+    {
+      g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
+      g_list_free (load_data->items);
+    }
+
+  g_free (load_data);
+}
+
+struct RecentItemInsertRequest
+{
+  GtkFileChooserDefault *impl;
+  GtkFilePath *path;
+  GtkTreeRowReference *row_ref;
+};
+
+static void
+recent_item_get_info_cb (GtkFileSystemHandle *handle,
+                         const GtkFileInfo   *info,
+                         const GError        *error,
+                         gpointer             data)
+{
+  gboolean cancelled = handle->cancelled;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GtkFileSystemHandle *model_handle;
+  gboolean is_folder = FALSE;
+  struct RecentItemInsertRequest *request = data;
+
+  if (!request->impl->recent_model)
+    goto out;
+
+  path = gtk_tree_row_reference_get_path (request->row_ref);
+  if (!path)
+    goto out;
+
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->recent_model),
+                           &iter, path);
+  gtk_tree_path_free (path);
+
+  gtk_tree_model_get (GTK_TREE_MODEL (request->impl->recent_model), &iter,
+                      RECENT_MODEL_COL_HANDLE, &model_handle,
+                      -1);
+  if (handle != model_handle)
+    goto out;
+
+  gtk_list_store_set (request->impl->recent_model, &iter,
+                      RECENT_MODEL_COL_HANDLE, NULL,
+                      -1);
+
+  if (cancelled)
+    goto out;
+
+  if (!info)
+    {
+      gtk_list_store_remove (request->impl->recent_model, &iter);
+      goto out;
+    }
+
+  is_folder = gtk_file_info_get_is_folder (info);
+
+  gtk_list_store_set (request->impl->recent_model, &iter,
+                      RECENT_MODEL_COL_IS_FOLDER, is_folder,
+                      -1);
+
+out:
+  g_object_unref (request->impl);
+  gtk_file_path_free (request->path);
+  gtk_tree_row_reference_free (request->row_ref);
+  g_free (request);
+
+  g_object_unref (handle);
+}
+
+static gint
+recent_sort_mru (gconstpointer a,
+                 gconstpointer b)
+{
+  GtkRecentInfo *info_a = (GtkRecentInfo *) a;
+  GtkRecentInfo *info_b = (GtkRecentInfo *) b;
+
+  return (gtk_recent_info_get_modified (info_b) - gtk_recent_info_get_modified (info_a));
+}
+
+static gint
+get_recent_files_limit (GtkWidget *widget)
+{
+  GtkSettings *settings;
+  gint limit;
+
+  if (gtk_widget_has_screen (widget))
+    settings = gtk_settings_get_for_screen (gtk_widget_get_screen (widget));
+  else
+    settings = gtk_settings_get_default ();
+
+  g_object_get (G_OBJECT (settings), "gtk-recent-files-limit", &limit, NULL);
+
+  return limit;
+}
+
+static gboolean
+recent_idle_load (gpointer data)
+{
+  RecentLoadData *load_data = data;
+  GtkFileChooserDefault *impl = load_data->impl;
+  GtkTreeIter iter;
+  GtkTreePath *p;
+  GtkRecentInfo *info;
+  const gchar *uri, *display_name;
+  GtkFilePath *path;
+  GtkFileSystemHandle *handle;
+  struct RecentItemInsertRequest *request;
+
+  if (!impl->recent_manager)
+    return FALSE;
+
+  /* first iteration: load all the items */
+  if (!load_data->items)
+    {
+      load_data->items = gtk_recent_manager_get_items (impl->recent_manager);
+      if (!load_data->items)
+        return FALSE;
+
+      load_data->needs_sorting = TRUE;
+
+      return TRUE;
+    }
+  
+  /* second iteration: preliminary MRU sorting and clamping */
+  if (load_data->needs_sorting)
+    {
+      gint limit;
+
+      load_data->items = g_list_sort (load_data->items, recent_sort_mru);
+      load_data->n_items = g_list_length (load_data->items);
+
+      limit = get_recent_files_limit (GTK_WIDGET (impl));
+      
+      if (limit != -1 && (load_data->n_items > limit))
+        {
+          GList *clamp, *l;
+
+          clamp = g_list_nth (load_data->items, limit - 1);
+          if (G_LIKELY (clamp))
+            {
+              l = clamp->next;
+              clamp->next = NULL;
+
+              g_list_foreach (l, (GFunc) gtk_recent_info_unref, NULL);
+              g_list_free (l);
+
+              load_data->n_items = limit;
+            }
+         }
+
+      load_data->n_loaded_items = 0;
+      load_data->needs_sorting = FALSE;
+
+      return TRUE;
+    }
+
+  info = g_list_nth_data (load_data->items, load_data->n_loaded_items);
+  g_assert (info != NULL);
+
+  uri = gtk_recent_info_get_uri (info);
+  display_name = gtk_recent_info_get_display_name (info);
+  path = gtk_file_system_uri_to_path (impl->file_system, uri);
+  if (!path)
+    goto load_next;
+
+  gtk_list_store_append (impl->recent_model, &iter);
+  p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->recent_model), &iter);
+
+  request = g_new0 (struct RecentItemInsertRequest, 1);
+  request->impl = g_object_ref (impl);
+  request->path = gtk_file_path_copy (path);
+  request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->recent_model), p);
+  gtk_tree_path_free (p);
+
+  handle = gtk_file_system_get_info (impl->file_system, path,
+                                     GTK_FILE_INFO_IS_FOLDER,
+                                     recent_item_get_info_cb,
+                                     request);
+
+  gtk_list_store_set (impl->recent_model, &iter,
+                      RECENT_MODEL_COL_PATH, path,
+                      RECENT_MODEL_COL_DISPLAY_NAME, g_strdup (display_name),
+                      RECENT_MODEL_COL_INFO, gtk_recent_info_ref (info),
+                      RECENT_MODEL_COL_HANDLE, handle,
+                      -1);
+
+load_next:
+
+  load_data->n_loaded_items += 1;
+
+  /* finished loading items */
+  if (load_data->n_loaded_items == load_data->n_items)
+    {
+      g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
+      g_list_free (load_data->items);
+      load_data->items = NULL;
+
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+recent_start_loading (GtkFileChooserDefault *impl)
+{
+  RecentLoadData *load_data;
+
+  recent_stop_loading (impl);
+  recent_clear_model (impl, TRUE);
+  recent_setup_model (impl);
+  set_busy_cursor (impl, TRUE);
+
+  if (!impl->recent_manager)
+    recent_manager_update (impl);
+
+  g_assert (impl->load_recent_id == 0);
+
+  load_data = g_new (RecentLoadData, 1);
+  load_data->impl = impl;
+  load_data->items = NULL;
+  load_data->n_items = 0;
+  load_data->n_loaded_items = 0;
+  load_data->needs_sorting = TRUE;
+
+  /* begin lazy loading the recent files into the model */
+  impl->load_recent_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30,
+                                                    recent_idle_load,
+                                                    load_data,
+                                                    recent_idle_cleanup);
+}
+
+static void
+recent_selected_foreach_get_path_cb (GtkTreeModel *model,
+                                    GtkTreePath  *path,
+                                    GtkTreeIter  *iter,
+                                    gpointer      data)
+{
+  GSList **list;
+  const GtkFilePath *file_path;
+  GtkFilePath *file_path_copy;
+
+  list = data;
+
+  gtk_tree_model_get (model, iter, RECENT_MODEL_COL_PATH, &file_path, -1);
+  file_path_copy = gtk_file_path_copy (file_path);
+  *list = g_slist_prepend (*list, file_path_copy);
+}
+
+/* Constructs a list of the selected paths in recent files mode */
+static GSList *
+recent_get_selected_paths (GtkFileChooserDefault *impl)
+{
+  GSList *result;
+  GtkTreeSelection *selection;
+
+  result = NULL;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  gtk_tree_selection_selected_foreach (selection, recent_selected_foreach_get_path_cb, &result);
+  result = g_slist_reverse (result);
+
+  return result;
+}
+
+/* Called from ::should_respond().  We return whether there are selected
+ * files in the recent files list.
+ */
+static gboolean
+recent_should_respond (GtkFileChooserDefault *impl)
+{
+  GtkTreeSelection *selection;
+
+  g_assert (impl->operation_mode == OPERATION_MODE_RECENT);
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  return (gtk_tree_selection_count_selected_rows (selection) != 0);
+}
+
+/* Hide the location widgets temporarily */
+static void
+recent_hide_entry (GtkFileChooserDefault *impl)
+{
+  gtk_widget_hide (impl->browse_path_bar);
+  gtk_widget_hide (impl->browse_new_folder_button);
+  
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+    {
+      gtk_widget_hide (impl->location_button);
+      gtk_widget_hide (impl->location_entry_box);
+    }
+}
+
+/* Main entry point to the recent files functions; this gets called when
+ * the user activates the Recently Used shortcut.
+ */
+static void
+recent_activate (GtkFileChooserDefault *impl)
+{
+  OperationMode previous_mode;
+
+  if (impl->operation_mode == OPERATION_MODE_RECENT)
+    return;
+
+  previous_mode = impl->operation_mode;
+  impl->operation_mode = OPERATION_MODE_RECENT;
+
+  switch (previous_mode)
+    {
+    case OPERATION_MODE_SEARCH:
+      search_stop_searching (impl, FALSE);
+      search_clear_model (impl, TRUE);
+
+      gtk_widget_destroy (impl->search_hbox);
+      impl->search_hbox = NULL;
+      impl->search_entry = NULL;
+      break;
+
+    case OPERATION_MODE_BROWSE:
+      stop_loading_and_clear_list_model (impl);
+      break;
+
+    case OPERATION_MODE_RECENT:
+      g_assert_not_reached ();
+      break;
+    }
+
+  recent_hide_entry (impl);
+  file_list_set_sort_column_ids (impl);
+  recent_start_loading (impl);
+}
+
+/* convert an iterator coming from the model bound to 
+ * browse_files_tree_view to an interator inside the
+ * real recent_model
+ */
+static void
+recent_get_valid_child_iter (GtkFileChooserDefault *impl,
+                             GtkTreeIter           *child_iter,
+                             GtkTreeIter           *iter)
+{
+  GtkTreeIter middle;
+
+  if (!impl->recent_model)
+    return;
+
+  if (!impl->recent_model_filter || !impl->recent_model_sort)
+    return;
+
+  /* pass 1: get the iterator in the filter model */
+  gtk_tree_model_sort_convert_iter_to_child_iter (impl->recent_model_sort,
+                                                  &middle, iter);
+  
+  /* pass 2: get the iterator in the real model */
+  gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
+                                                    child_iter,
+                                                    &middle);
+}
+
+
+static void
+set_current_filter (GtkFileChooserDefault *impl,
+                   GtkFileFilter         *filter)
+{
+  if (impl->current_filter != filter)
+    {
+      int filter_index;
+
+      /* NULL filters are allowed to reset to non-filtered status
+       */
+      filter_index = g_slist_index (impl->filters, filter);
+      if (impl->filters && filter && filter_index < 0)
+       return;
+
+      if (impl->current_filter)
+       g_object_unref (impl->current_filter);
+      impl->current_filter = filter;
+      if (impl->current_filter)
+       {
+         g_object_ref_sink (impl->current_filter);
+       }
+
+      if (impl->filters)
+       gtk_combo_box_set_active (GTK_COMBO_BOX (impl->filter_combo),
+                                 filter_index);
+
+      if (impl->browse_files_model)
+       install_list_model_filter (impl);
+
+      if (impl->search_model_filter)
+        gtk_tree_model_filter_refilter (impl->search_model_filter);
+
+      if (impl->recent_model_filter)
+        gtk_tree_model_filter_refilter (impl->recent_model_filter);
+
+      g_object_notify (G_OBJECT (impl), "filter");
+    }
+}
+
+static void
+filter_combo_changed (GtkComboBox           *combo_box,
+                     GtkFileChooserDefault *impl)
+{
+  gint new_index = gtk_combo_box_get_active (combo_box);
+  GtkFileFilter *new_filter = g_slist_nth_data (impl->filters, new_index);
+
+  set_current_filter (impl, new_filter);
+}
+
+static void
+check_preview_change (GtkFileChooserDefault *impl)
+{
+  GtkTreePath *cursor_path;
+  const GtkFilePath *new_path;
+  const char *new_display_name;
+
+  gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
+  new_path = NULL;
+  new_display_name = NULL;
+  if (cursor_path)
+    {
+      GtkTreeIter child_iter;
+
+      if (impl->operation_mode == OPERATION_MODE_BROWSE)
+       {
+         if (impl->sort_model)
+           {
+             GtkTreeIter iter;
+             const GtkFileInfo *new_info;
+
+             gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
+             gtk_tree_path_free (cursor_path);
+
+             gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
+
+             new_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
+             new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+              if (new_info)
+               new_display_name = gtk_file_info_get_display_name (new_info);
+           }
+       }
+      else if (impl->operation_mode == OPERATION_MODE_SEARCH)
+       {
+         GtkTreeIter iter;
+
+         gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort),
+                                   &iter, cursor_path);
+         gtk_tree_path_free (cursor_path);
+
+         search_get_valid_child_iter (impl, &child_iter, &iter);
+          gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                             SEARCH_MODEL_COL_PATH, &new_path,
+                             SEARCH_MODEL_COL_DISPLAY_NAME, &new_display_name,
+                             -1);
+       }
+      else if (impl->operation_mode == OPERATION_MODE_RECENT)
+        {
+          GtkTreeIter iter;
+
+          gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort),
+                                   &iter, cursor_path);
+          gtk_tree_path_free (cursor_path);
+
+          recent_get_valid_child_iter (impl, &child_iter, &iter);
+          gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                              RECENT_MODEL_COL_PATH, &new_path,
+                              RECENT_MODEL_COL_DISPLAY_NAME, &new_display_name,
+                              -1);
+        }
+    }
+
+  if (new_path != impl->preview_path &&
+      !(new_path && impl->preview_path &&
+       gtk_file_path_compare (new_path, impl->preview_path) == 0))
+    {
+      if (impl->preview_path)
+       {
+         gtk_file_path_free (impl->preview_path);
+         g_free (impl->preview_display_name);
+       }
+
+      if (new_path)
+       {
+         impl->preview_path = gtk_file_path_copy (new_path);
+         impl->preview_display_name = g_strdup (new_display_name);
+       }
+      else
+       {
+         impl->preview_path = NULL;
+         impl->preview_display_name = NULL;
+       }
+
+      if (impl->use_preview_label && impl->preview_label)
+       gtk_label_set_text (GTK_LABEL (impl->preview_label), impl->preview_display_name);
+
+      g_signal_emit_by_name (impl, "update-preview");
+    }
+}
+
+static void
+shortcuts_activate_volume_mount_cb (GtkFileSystemHandle *handle,
+                                   GtkFileSystemVolume *volume,
+                                   const GError        *error,
+                                   gpointer             data)
+{
+  GtkFilePath *path;
+  gboolean cancelled = handle->cancelled;
+  GtkFileChooserDefault *impl = data;
+
+  if (handle != impl->shortcuts_activate_iter_handle)
+    goto out;
+
+  impl->shortcuts_activate_iter_handle = NULL;
+
+  set_busy_cursor (impl, FALSE);
+
+  if (cancelled)
+    goto out;
+
+  if (error)
+    {
+      char *msg;
+
+      msg = g_strdup_printf (_("Could not mount %s"),
+                            gtk_file_system_volume_get_display_name (impl->file_system, volume));
+      error_message (impl, msg, error->message);
+      g_free (msg);
+
+      goto out;
+    }
+
+  path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+  if (path != NULL)
+    {
+      change_folder_and_display_error (impl, path, FALSE);
+      focus_browse_tree_view_if_possible (impl);
+      
+      gtk_file_path_free (path);
+    }
+
+out:
+  g_object_unref (impl);
+  g_object_unref (handle);
+}
+
+
+/* Activates a volume by mounting it if necessary and then switching to its
+ * base path.
+ */
+static void
+shortcuts_activate_volume (GtkFileChooserDefault *impl,
+                          GtkFileSystemVolume   *volume)
+{
+  GtkFilePath *path;
+
+  switch (impl->operation_mode)
+    {
+    case OPERATION_MODE_BROWSE:
+      break;
+    case OPERATION_MODE_SEARCH:
+      search_switch_to_browse_mode (impl);
+      break;
+    case OPERATION_MODE_RECENT:
+      recent_switch_to_browse_mode (impl);
+      break;
+    }
+
+  /* We ref the file chooser since volume_mount() may run a main loop, and the
+   * user could close the file chooser window in the meantime.
+   */
+  g_object_ref (impl);
+
+  if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
+    {
+      set_busy_cursor (impl, TRUE);
+
+      impl->shortcuts_activate_iter_handle =
+        gtk_file_system_volume_mount (impl->file_system, volume,
+                                     shortcuts_activate_volume_mount_cb,
+                                     g_object_ref (impl));
+    }
+  else
+    {
+      path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+      if (path != NULL)
+        {
+          change_folder_and_display_error (impl, path, FALSE);
+          gtk_file_path_free (path);
+        }
+    }
+
+  g_object_unref (impl);
+}
+
+/* Opens the folder or volume at the specified iter in the shortcuts model */
+struct ShortcutsActivateData
+{
+  GtkFileChooserDefault *impl;
+  GtkFilePath *path;
+};
+
+static void
+shortcuts_activate_get_info_cb (GtkFileSystemHandle *handle,
+                               const GtkFileInfo   *info,
+                               const GError        *error,
+                               gpointer             user_data)
+{
+  gboolean cancelled = handle->cancelled;
+  struct ShortcutsActivateData *data = user_data;
+
+  if (handle != data->impl->shortcuts_activate_iter_handle)
+    goto out;
+
+  data->impl->shortcuts_activate_iter_handle = NULL;
+
+  if (cancelled)
+    goto out;
+
+  if (!error && gtk_file_info_get_is_folder (info))
+    {
+      change_folder_and_display_error (data->impl, data->path, FALSE);
+      focus_browse_tree_view_if_possible (data->impl);
+    }
+  else
+    gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl),
+                                          data->path,
+                                          NULL);
+
+out:
+  g_object_unref (data->impl);
+  gtk_file_path_free (data->path);
+  g_free (data);
+
+  g_object_unref (handle);
+}
+
+static void
+shortcuts_activate_iter (GtkFileChooserDefault *impl,
+                        GtkTreeIter           *iter)
+{
+  gpointer col_data;
+  ShortcutType shortcut_type;
+
+  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,
+                     SHORTCUTS_COL_TYPE, &shortcut_type,
                      -1);
 
-  if (!col_data)
-    return; /* We are on a separator */
-
   if (impl->shortcuts_activate_iter_handle)
     {
       gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
       impl->shortcuts_activate_iter_handle = NULL;
     }
 
-  if (is_volume)
+  if (shortcut_type == SHORTCUT_TYPE_SEPARATOR)
+    return;
+  else if (shortcut_type == SHORTCUT_TYPE_VOLUME)
     {
       GtkFileSystemVolume *volume;
 
@@ -8141,7 +10443,7 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
 
       shortcuts_activate_volume (impl, volume);
     }
-  else
+  else if (shortcut_type == SHORTCUT_TYPE_PATH)
     {
       struct ShortcutsActivateData *data;
 
@@ -8154,27 +10456,14 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
                                  GTK_FILE_INFO_IS_FOLDER,
                                  shortcuts_activate_get_info_cb, data);
     }
-}
-
-/* Callback used when a row in the shortcuts list is activated */
-static void
-shortcuts_row_activated_cb (GtkTreeView           *tree_view,
-                           GtkTreePath           *path,
-                           GtkTreeViewColumn     *column,
-                           GtkFileChooserDefault *impl)
-{
-  GtkTreeIter iter;
-  GtkTreeIter child_iter;
-
-  if (!gtk_tree_model_get_iter (impl->shortcuts_filter_model, &iter, path))
-    return;
-
-  gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
-                                                   &child_iter,
-                                                   &iter);
-  shortcuts_activate_iter (impl, &child_iter);
-
-  gtk_widget_grab_focus (impl->browse_files_tree_view);
+  else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
+    {
+      search_activate (impl);
+    }
+  else if (shortcut_type == SHORTCUT_TYPE_RECENT)
+    {
+      recent_activate (impl);
+    }
 }
 
 /* Handler for GtkWidget::key-press-event on the shortcuts list */
@@ -8214,8 +10503,15 @@ shortcuts_select_func  (GtkTreeSelection  *selection,
                        gpointer           data)
 {
   GtkFileChooserDefault *impl = data;
+  GtkTreeIter filter_iter;
+  ShortcutType shortcut_type;
+
+  if (!gtk_tree_model_get_iter (impl->shortcuts_pane_filter_model, &filter_iter, path))
+    g_assert_not_reached ();
 
-  return (*gtk_tree_path_get_indices (path) != shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR));
+  gtk_tree_model_get (impl->shortcuts_pane_filter_model, &filter_iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
+
+  return shortcut_type != SHORTCUT_TYPE_SEPARATOR;
 }
 
 static gboolean
@@ -8231,17 +10527,55 @@ list_select_func  (GtkTreeSelection  *selection,
       impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     {
       GtkTreeIter iter, child_iter;
-      const GtkFileInfo *info;
-
-      if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
-       return FALSE;
-      
-      gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
-
-      info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
 
-      if (info && !gtk_file_info_get_is_folder (info))
-       return FALSE;
+      switch (impl->operation_mode)
+        {
+        case OPERATION_MODE_SEARCH:
+          {
+            gboolean is_folder;
+
+            if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
+              return FALSE;
+
+            search_get_valid_child_iter (impl, &child_iter, &iter);
+            gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                                SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                                -1);
+            if (!is_folder)
+              return FALSE;
+          }
+          break;
+
+        case OPERATION_MODE_RECENT:
+          {
+            gboolean is_folder;
+
+            if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
+              return FALSE;
+
+            recent_get_valid_child_iter (impl, &child_iter, &iter);
+            gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                                RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                                -1);
+            if (!is_folder)
+              return FALSE;
+          }
+          break;
+
+        case OPERATION_MODE_BROWSE:
+          {
+            const GtkFileInfo *info;
+
+            if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
+              return FALSE;
+
+            gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
+            info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+            if (info && !gtk_file_info_get_is_folder (info))
+              return FALSE;
+          }
+          break;
+        }
     }
     
   return TRUE;
@@ -8252,7 +10586,8 @@ list_selection_changed (GtkTreeSelection      *selection,
                        GtkFileChooserDefault *impl)
 {
   /* See if we are in the new folder editable row for Save mode */
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+  if (impl->operation_mode == OPERATION_MODE_BROWSE &&
+      impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
     {
       const GtkFileInfo *info;
       gboolean had_selection;
@@ -8267,7 +10602,9 @@ list_selection_changed (GtkTreeSelection      *selection,
 
  out:
 
-  update_chooser_entry (impl);
+  if (impl->location_entry)
+    update_chooser_entry (impl);
+
   check_preview_change (impl);
   bookmarks_check_add_sensitivity (impl);
 
@@ -8281,29 +10618,86 @@ list_row_activated (GtkTreeView           *tree_view,
                    GtkTreeViewColumn     *column,
                    GtkFileChooserDefault *impl)
 {
-  GtkTreeIter iter, child_iter;
-  const GtkFileInfo *info;
+  GtkTreeIter iter;
+  GtkTreeIter child_iter;
 
-  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
-    return;
+  switch (impl->operation_mode)
+    {
+    case OPERATION_MODE_SEARCH:
+      {
+        GtkFilePath *file_path;
+        gboolean is_folder;
 
-  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
+        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
+          return;
 
-  info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+        search_get_valid_child_iter (impl, &child_iter, &iter);
+        gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                            SEARCH_MODEL_COL_PATH, &file_path,
+                            SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                            -1);
+        
+        if (is_folder)
+          {
+            change_folder_and_display_error (impl, file_path, FALSE);
+            return;
+          }
 
-  if (gtk_file_info_get_is_folder (info))
-    {
-      const GtkFilePath *file_path;
+        g_signal_emit_by_name (impl, "file-activated");
+      }
+      break;
 
-      file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
-      change_folder_and_display_error (impl, file_path);
+    case OPERATION_MODE_RECENT:
+      {
+        GtkFilePath *file_path;
+        gboolean is_folder;
+
+        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
+          return;
+        
+        recent_get_valid_child_iter (impl, &child_iter, &iter);
+        gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                            RECENT_MODEL_COL_PATH, &file_path,
+                            RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                            -1);
+
+        if (is_folder)
+          {
+            change_folder_and_display_error (impl, file_path, FALSE);
+            return;
+          }
+        
+        g_signal_emit_by_name (impl, "file-activated");
+      }
+      break;
+    
+    case OPERATION_MODE_BROWSE:
+      {
+        const GtkFileInfo *info;
 
-      return;
+        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
+          return;
+        
+        gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+                                                        &child_iter, &iter);
+        info = _gtk_file_system_model_get_info (impl->browse_files_model,
+                                                &child_iter);
+
+        if (gtk_file_info_get_is_folder (info))
+          {
+            const GtkFilePath *file_path;
+            
+            file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
+            change_folder_and_display_error (impl, file_path, FALSE);
+            return;
+          }
+
+        if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+            impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+          g_signal_emit_by_name (impl, "file-activated");
+      }
+      break;
     }
-
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
-      impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
-    g_signal_emit_by_name (impl, "file-activated");
 }
 
 static void
@@ -8316,7 +10710,7 @@ path_bar_clicked (GtkPathBar            *path_bar,
   if (child_path)
     pending_select_paths_add (impl, child_path);
 
-  if (!change_folder_and_display_error (impl, file_path))
+  if (!change_folder_and_display_error (impl, file_path, FALSE))
     return;
 
   /* Say we have "/foo/bar/[.baz]" and the user clicks on "bar".  We should then
@@ -8349,40 +10743,83 @@ list_icon_data_func (GtkTreeViewColumn *tree_column,
 {
   GtkFileChooserDefault *impl = data;
   GtkTreeIter child_iter;
-  const GtkFilePath *path;
-  GdkPixbuf *pixbuf;
-  const GtkFileInfo *info; 
+  GdkPixbuf *pixbuf = NULL;
   gboolean sensitive = TRUE;
 
   profile_start ("start", NULL);
   
-  info = get_list_file_info (impl, iter);
-
-  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
-                                                 &child_iter,
-                                                 iter);
-  path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
-
-  if (path)
+  switch (impl->operation_mode)
     {
-      pixbuf = NULL;
+    case OPERATION_MODE_SEARCH:
+      {
+        GtkTreeIter child_iter;
+        gboolean is_folder;
+
+        search_get_valid_child_iter (impl, &child_iter, iter);
+        gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                            SEARCH_MODEL_COL_PIXBUF, &pixbuf,
+                            SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                            -1);
+        
+        if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+            impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+          sensitive = is_folder;
+      }
+      break;
 
-      if (info)
-        {
-          /* FIXME: NULL GError */
-         pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
-                                             impl->icon_size, NULL);
-       }
-    }
-  else
-    {
-      /* We are on the editable row */
-      pixbuf = NULL;
+    case OPERATION_MODE_RECENT:
+      {
+        GtkTreeIter child_iter;
+        GtkRecentInfo *info;
+        gboolean is_folder;
+
+        recent_get_valid_child_iter (impl, &child_iter, iter);
+        gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                            RECENT_MODEL_COL_INFO, &info,
+                            RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                            -1);
+        
+        pixbuf = gtk_recent_info_get_icon (info, impl->icon_size);
+      
+        if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER || 
+            impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+          sensitive = is_folder;
+      }
+      break;
+    
+    case OPERATION_MODE_BROWSE:
+      {
+        const GtkFileInfo *info;
+        const GtkFilePath *path;
+
+        info = get_list_file_info (impl, iter);
+
+        gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+                                                        &child_iter,
+                                                        iter);
+        path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
+        if (path)
+          {
+            if (info)
+              {
+                /* FIXME: NULL GError */
+                pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
+                                                    impl->icon_size, NULL);
+             }
+          }
+        else
+          {
+            /* We are on the editable row */
+            pixbuf = NULL;
+          }
+
+        if (info &&
+            (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+             impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
+          sensitive =  gtk_file_info_get_is_folder (info);
+      }
+      break;
     }
-
-  if (info && (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
-              impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
-    sensitive =  gtk_file_info_get_is_folder (info);    
     
   g_object_set (cell,
                "pixbuf", pixbuf,
@@ -8403,21 +10840,85 @@ list_name_data_func (GtkTreeViewColumn *tree_column,
                     gpointer           data)
 {
   GtkFileChooserDefault *impl = data;
-  const GtkFileInfo *info = get_list_file_info (impl, iter);
+  const GtkFileInfo *info;
   gboolean sensitive = TRUE;
 
+  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+    {
+      GtkTreeIter child_iter;
+      gchar *display_name;
+      gboolean is_folder;
+
+      search_get_valid_child_iter (impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                          SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
+                          SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                         -1);
+
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+          impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+        {
+          sensitive = is_folder;
+        }
+
+      g_object_set (cell,
+                   "text", display_name,
+                   "sensitive", sensitive,
+                   "ellipsize", PANGO_ELLIPSIZE_END,
+                   NULL);
+      
+      return;
+    }
+
+  if (impl->operation_mode == OPERATION_MODE_RECENT)
+    {
+      GtkTreeIter child_iter;
+      GtkRecentInfo *recent_info;
+      gchar *display_name;
+      gboolean is_folder;
+
+      recent_get_valid_child_iter (impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                          RECENT_MODEL_COL_INFO, &recent_info,
+                          RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                          -1);
+      
+      display_name = gtk_recent_info_get_short_name (recent_info);
+
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+          impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+        {
+          sensitive = is_folder;
+        }
+
+      g_object_set (cell,
+                    "text", display_name,
+                    "sensitive", sensitive,
+                    "ellipsize", PANGO_ELLIPSIZE_END,
+                    NULL);
+
+      g_free (display_name);
+
+      return;
+    }
+
+  info = get_list_file_info (impl, iter);
+  sensitive = TRUE;
+
   if (!info)
     {
       g_object_set (cell,
                    "text", _("Type name of new folder"),
+                   "sensitive", TRUE,
+                   "ellipsize", PANGO_ELLIPSIZE_NONE,
                    NULL);
 
       return;
     }
 
 
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
-        || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     {
       sensitive = gtk_file_info_get_is_folder (info);
     } 
@@ -8425,6 +10926,7 @@ list_name_data_func (GtkTreeViewColumn *tree_column,
   g_object_set (cell,
                "text", gtk_file_info_get_display_name (info),
                "sensitive", sensitive,
+               "ellipsize", PANGO_ELLIPSIZE_END,
                NULL);
 }
 
@@ -8486,64 +10988,142 @@ list_mtime_data_func (GtkTreeViewColumn *tree_column,
                      gpointer           data)
 {
   GtkFileChooserDefault *impl;
-  const GtkFileInfo *info;
-  GtkFileTime time_mtime;
-  GDate mtime, now;
-  int days_diff;
-  char buf[256];
+  time_t time_mtime;
+  gchar *date_str = NULL;
   gboolean sensitive = TRUE;
 
   impl = data;
 
-  info = get_list_file_info (impl, iter);
-  if (!info)
+  if (impl->operation_mode == OPERATION_MODE_SEARCH)
     {
-      g_object_set (cell,
-                   "text", "",
-                   "sensitive", TRUE,
-                   NULL);
-      return;
+      GtkTreeIter child_iter;
+      struct stat *statbuf;
+      gboolean is_folder;
+
+      search_get_valid_child_iter (impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
+                          SEARCH_MODEL_COL_STAT, &statbuf,
+                          SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                         -1);
+      if (statbuf)
+        time_mtime = statbuf->st_mtime;
+      else
+        time_mtime = 0;
+
+
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+          impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+        sensitive = is_folder;
+    }
+  else if (impl->operation_mode == OPERATION_MODE_RECENT)
+    {
+      GtkTreeIter child_iter;
+      GtkRecentInfo *info;
+      gboolean is_folder;
+
+      recent_get_valid_child_iter (impl, &child_iter, iter);
+      gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                          RECENT_MODEL_COL_INFO, &info,
+                          RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                          -1);
+
+      if (info)
+        time_mtime = gtk_recent_info_get_modified (info);
+      else
+        time_mtime = 0;
+
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+          impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+        sensitive = is_folder;
     }
+  else
+    {
+      const GtkFileInfo *info;
+
+      info = get_list_file_info (impl, iter);
+      if (!info)
+       {
+         g_object_set (cell,
+                       "text", "",
+                       "sensitive", TRUE,
+                       NULL);
+         return;
+       }
+
+      time_mtime = (time_t) gtk_file_info_get_modification_time (info);
 
-  time_mtime = gtk_file_info_get_modification_time (info);
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+         impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+       sensitive = gtk_file_info_get_is_folder (info);
+    }
 
-  if (time_mtime == 0)
-    strcpy (buf, _("Unknown"));
+  if (G_UNLIKELY (time_mtime == 0))
+    date_str = g_strdup (_("Unknown"));
   else
     {
+      GDate mtime, now;
+      gint days_diff;
+      struct tm tm_mtime;
       time_t time_now;
+      const gchar *format;
+      gchar *locale_format = NULL;
+      gchar buf[256];
+
+#ifdef HAVE_LOCALTIME_R
+      localtime_r ((time_t *) &time_mtime, &tm_mtime);
+#else
+      {
+        struct tm *ptm = localtime ((time_t *) &time_mtime);
+
+        if (!ptm)
+          {
+            g_warning ("ptm != NULL failed");
+            
+            g_object_set (cell,
+                          "text", _("Unknown"),
+                          "sensitive", sensitive,
+                          NULL);
+            return;
+          }
+        else
+          memcpy ((void *) &tm_mtime, (void *) ptm, sizeof (struct tm));
+      }
+#endif /* HAVE_LOCALTIME_R */
+
       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);
 
+      /* Translators: %H means "hours" and %M means "minutes" */
       if (days_diff == 0)
-       strcpy (buf, _("Today"));
+        format = _("Today at %H:%M");
       else if (days_diff == 1)
-       strcpy (buf, _("Yesterday"));
+       format = _("Yesterday at %H:%M");
       else
        {
-         char *format;
-
          if (days_diff > 1 && days_diff < 7)
            format = "%A"; /* Days from last week */
          else
            format = "%x"; /* Any other date */
-
-         if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
-           strcpy (buf, _("Unknown"));
        }
-    }
 
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
-      impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
-    sensitive = gtk_file_info_get_is_folder (info);
+      locale_format = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
+
+      if (strftime (buf, sizeof (buf), locale_format, &tm_mtime) != 0)
+        date_str = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+      else
+       date_str = g_strdup (_("Unknown"));
+
+      g_free (locale_format);
+    }
 
   g_object_set (cell,
-               "text", buf,
+               "text", date_str,
                "sensitive", sensitive,
                NULL);
+  g_free (date_str);
 }
 
 GtkWidget *
@@ -8565,9 +11145,39 @@ location_set_user_text (GtkFileChooserDefault *impl,
 static void
 location_popup_handler (GtkFileChooserDefault *impl,
                        const gchar           *path)
-{
-  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
-      || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+{ 
+  if (impl->operation_mode != OPERATION_MODE_BROWSE)
+    {
+      GtkWidget *widget_to_focus;
+      
+      /* This will give us the location widgets back */
+      switch (impl->operation_mode)
+        {
+        case OPERATION_MODE_SEARCH:
+          search_switch_to_browse_mode (impl);
+          break;
+        case OPERATION_MODE_RECENT:
+          recent_switch_to_browse_mode (impl);
+          break;
+        case OPERATION_MODE_BROWSE:
+          g_assert_not_reached ();
+          break;
+        }
+
+      if (impl->current_folder)
+        change_folder_and_display_error (impl, impl->current_folder, FALSE);
+
+      if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+        widget_to_focus = impl->browse_files_tree_view;
+      else
+        widget_to_focus = impl->location_entry;
+
+      gtk_widget_grab_focus (widget_to_focus);
+      return; 
+    }
+  
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
     {
       LocationMode new_mode;
 
@@ -8598,8 +11208,8 @@ location_popup_handler (GtkFileChooserDefault *impl,
            }
        }
     }
-  else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
-          || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+  else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+          impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
     {
       gtk_widget_grab_focus (impl->location_entry);
       if (path != NULL)
@@ -8634,6 +11244,7 @@ switch_to_shortcut (GtkFileChooserDefault *impl,
     g_assert_not_reached ();
 
   shortcuts_activate_iter (impl, &iter);
+  focus_browse_tree_view_if_possible (impl);
 }
 
 /* Handler for the "home-folder" keybinding signal */
@@ -8652,6 +11263,30 @@ desktop_folder_handler (GtkFileChooserDefault *impl)
     switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_DESKTOP));
 }
 
+/* Handler for the "search-shortcut" keybinding signal */
+static void
+search_shortcut_handler (GtkFileChooserDefault *impl)
+{
+  if (impl->has_search)
+    {
+      switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_SEARCH));
+
+      /* we want the entry widget to grab the focus the first
+       * time, not the browse_files_tree_view widget.
+       */
+      if (impl->search_entry)
+        gtk_widget_grab_focus (impl->search_entry);
+    }
+}
+
+/* Handler for the "recent-shortcut" keybinding signal */
+static void
+recent_shortcut_handler (GtkFileChooserDefault *impl)
+{
+  if (impl->has_recent)
+    switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_RECENT));
+}
+
 static void
 quick_bookmark_handler (GtkFileChooserDefault *impl,
                        gint bookmark_index)
@@ -8673,31 +11308,38 @@ quick_bookmark_handler (GtkFileChooserDefault *impl,
   switch_to_shortcut (impl, bookmark_pos);
 }
 
-\f
+static void
+show_hidden_handler (GtkFileChooserDefault *impl)
+{
+  g_object_set (impl,
+               "show-hidden", !impl->show_hidden,
+               NULL);
+}
+
 
 /* Drag and drop interfaces */
 
 static void
-_shortcuts_model_filter_class_init (ShortcutsModelFilterClass *class)
+_shortcuts_pane_model_filter_class_init (ShortcutsPaneModelFilterClass *class)
 {
 }
 
 static void
-_shortcuts_model_filter_init (ShortcutsModelFilter *model)
+_shortcuts_pane_model_filter_init (ShortcutsPaneModelFilter *model)
 {
   model->impl = NULL;
 }
 
 /* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */
 static gboolean
-shortcuts_model_filter_row_draggable (GtkTreeDragSource *drag_source,
-                                     GtkTreePath       *path)
+shortcuts_pane_model_filter_row_draggable (GtkTreeDragSource *drag_source,
+                                          GtkTreePath       *path)
 {
-  ShortcutsModelFilter *model;
+  ShortcutsPaneModelFilter *model;
   int pos;
   int bookmarks_pos;
 
-  model = SHORTCUTS_MODEL_FILTER (drag_source);
+  model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
 
   pos = *gtk_tree_path_get_indices (path);
   bookmarks_pos = shortcuts_get_index (model->impl, SHORTCUTS_BOOKMARKS);
@@ -8707,13 +11349,13 @@ shortcuts_model_filter_row_draggable (GtkTreeDragSource *drag_source,
 
 /* GtkTreeDragSource::drag_data_get implementation for the shortcuts filter model */
 static gboolean
-shortcuts_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
-                                     GtkTreePath       *path,
-                                     GtkSelectionData  *selection_data)
+shortcuts_pane_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
+                                          GtkTreePath       *path,
+                                          GtkSelectionData  *selection_data)
 {
-  ShortcutsModelFilter *model;
+  ShortcutsPaneModelFilter *model;
 
-  model = SHORTCUTS_MODEL_FILTER (drag_source);
+  model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
 
   /* FIXME */
 
@@ -8722,30 +11364,30 @@ shortcuts_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
 
 /* Fill the GtkTreeDragSourceIface vtable */
 static void
-shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface)
+shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface)
 {
-  iface->row_draggable = shortcuts_model_filter_row_draggable;
-  iface->drag_data_get = shortcuts_model_filter_drag_data_get;
+  iface->row_draggable = shortcuts_pane_model_filter_row_draggable;
+  iface->drag_data_get = shortcuts_pane_model_filter_drag_data_get;
 }
 
 #if 0
 /* Fill the GtkTreeDragDestIface vtable */
 static void
-shortcuts_model_filter_drag_dest_iface_init (GtkTreeDragDestIface *iface)
+shortcuts_pane_model_filter_drag_dest_iface_init (GtkTreeDragDestIface *iface)
 {
-  iface->drag_data_received = shortcuts_model_filter_drag_data_received;
-  iface->row_drop_possible = shortcuts_model_filter_row_drop_possible;
+  iface->drag_data_received = shortcuts_pane_model_filter_drag_data_received;
+  iface->row_drop_possible = shortcuts_pane_model_filter_row_drop_possible;
 }
 #endif
 
 static GtkTreeModel *
-shortcuts_model_filter_new (GtkFileChooserDefault *impl,
-                           GtkTreeModel          *child_model,
-                           GtkTreePath           *root)
+shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
+                                GtkTreeModel          *child_model,
+                                GtkTreePath           *root)
 {
-  ShortcutsModelFilter *model;
+  ShortcutsPaneModelFilter *model;
 
-  model = g_object_new (SHORTCUTS_MODEL_FILTER_TYPE,
+  model = g_object_new (SHORTCUTS_PANE_MODEL_FILTER_TYPE,
                        "child-model", child_model,
                        "virtual-root", root,
                        NULL);
@@ -8754,3 +11396,173 @@ shortcuts_model_filter_new (GtkFileChooserDefault *impl,
 
   return GTK_TREE_MODEL (model);
 }
+
+\f
+
+static gboolean
+recent_model_sort_row_draggable (GtkTreeDragSource *drag_source,
+                                 GtkTreePath       *path)
+{
+  RecentModelSort *model;
+  GtkTreeIter iter, child_iter;
+  gboolean is_folder;
+
+  model = RECENT_MODEL_SORT (drag_source);
+  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
+    return FALSE;
+
+  recent_get_valid_child_iter (model->impl, &child_iter, &iter);
+  gtk_tree_model_get (GTK_TREE_MODEL (model->impl->recent_model), &child_iter,
+                      RECENT_MODEL_COL_IS_FOLDER, &is_folder,
+                      -1);
+
+  return is_folder;
+}
+
+static gboolean
+recent_model_sort_drag_data_get (GtkTreeDragSource *drag_source,
+                                 GtkTreePath       *path,
+                                GtkSelectionData  *selection_data)
+{
+  RecentModelSort *model;
+  GtkTreeIter iter, child_iter;
+  GtkFilePath *file_path;
+  gchar *uris[2];
+
+  model = RECENT_MODEL_SORT (drag_source);
+  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
+    return FALSE;
+
+  recent_get_valid_child_iter (model->impl, &child_iter, &iter);
+  gtk_tree_model_get (GTK_TREE_MODEL (model->impl->recent_model), &child_iter,
+                      RECENT_MODEL_COL_PATH, &file_path,
+                      -1);
+  g_assert (file_path != NULL);
+
+  uris[0] = gtk_file_system_path_to_uri (model->impl->file_system, file_path);
+  uris[1] = NULL;
+
+  gtk_selection_data_set_uris (selection_data, uris);
+
+  g_free (uris[0]);
+
+  return TRUE;
+}
+
+static void
+recent_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface)
+{
+  iface->row_draggable = recent_model_sort_row_draggable;
+  iface->drag_data_get = recent_model_sort_drag_data_get;
+}
+
+static void
+_recent_model_sort_class_init (RecentModelSortClass *klass)
+{
+
+}
+
+static void
+_recent_model_sort_init (RecentModelSort *model)
+{
+  model->impl = NULL;
+}
+
+static GtkTreeModel *
+recent_model_sort_new (GtkFileChooserDefault *impl,
+                       GtkTreeModel          *child_model)
+{
+  RecentModelSort *model;
+
+  model = g_object_new (RECENT_MODEL_SORT_TYPE,
+                        "model", child_model,
+                        NULL);
+  model->impl = impl;
+
+  return GTK_TREE_MODEL (model);
+}
+
+\f
+
+static gboolean
+search_model_sort_row_draggable (GtkTreeDragSource *drag_source,
+                                 GtkTreePath       *path)
+{
+  SearchModelSort *model;
+  GtkTreeIter iter, child_iter;
+  gboolean is_folder;
+
+  model = SEARCH_MODEL_SORT (drag_source);
+  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
+    return FALSE;
+
+  search_get_valid_child_iter (model->impl, &child_iter, &iter);
+  gtk_tree_model_get (GTK_TREE_MODEL (model->impl->search_model), &child_iter,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
+                      -1);
+
+  return is_folder;
+}
+
+static gboolean
+search_model_sort_drag_data_get (GtkTreeDragSource *drag_source,
+                                 GtkTreePath       *path,
+                                GtkSelectionData  *selection_data)
+{
+  SearchModelSort *model;
+  GtkTreeIter iter, child_iter;
+  GtkFilePath *file_path;
+  gchar *uris[2];
+
+  model = SEARCH_MODEL_SORT (drag_source);
+  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
+    return FALSE;
+
+  search_get_valid_child_iter (model->impl, &child_iter, &iter);
+  gtk_tree_model_get (GTK_TREE_MODEL (model->impl->search_model), &child_iter,
+                      RECENT_MODEL_COL_PATH, &file_path,
+                      -1);
+  g_assert (file_path != NULL);
+
+  uris[0] = gtk_file_system_path_to_uri (model->impl->file_system, file_path);
+  uris[1] = NULL;
+
+  gtk_selection_data_set_uris (selection_data, uris);
+
+  g_free (uris[0]);
+
+  return TRUE;
+}
+
+static void
+search_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface)
+{
+  iface->row_draggable = search_model_sort_row_draggable;
+  iface->drag_data_get = search_model_sort_drag_data_get;
+}
+
+static void
+_search_model_sort_class_init (SearchModelSortClass *klass)
+{
+
+}
+
+static void
+_search_model_sort_init (SearchModelSort *model)
+{
+  model->impl = NULL;
+}
+
+static GtkTreeModel *
+search_model_sort_new (GtkFileChooserDefault *impl,
+                       GtkTreeModel          *child_model)
+{
+  SearchModelSort *model;
+
+  model = g_object_new (SEARCH_MODEL_SORT_TYPE,
+                        "model", child_model,
+                        NULL);
+  model->impl = impl;
+
+  return GTK_TREE_MODEL (model);
+}