diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index d54e1d6..0ad4b6c 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -56,6 +56,8 @@
 #include "gtkpathbar.h"
 #include "gtkprivate.h"
 #include "gtkradiobutton.h"
+#include "gtkrecentfilter.h"
+#include "gtkrecentmanager.h"
 #include "gtkscrolledwindow.h"
 #include "gtkseparatormenuitem.h"
 #include "gtksizegroup.h"
@@ -164,6 +166,9 @@ enum {
   QUICK_BOOKMARK,
   LOCATION_TOGGLE_POPUP,
   SHOW_HIDDEN,
+  SEARCH_SHORTCUT,
+  RECENT_SHORTCUT,
+
   LAST_SIGNAL
 };
 
@@ -185,7 +190,8 @@ typedef enum {
   SHORTCUT_TYPE_PATH,
   SHORTCUT_TYPE_VOLUME,
   SHORTCUT_TYPE_SEPARATOR,
-  SHORTCUT_TYPE_SEARCH
+  SHORTCUT_TYPE_SEARCH,
+  SHORTCUT_TYPE_RECENT
 } ShortcutType;
 
 /* Column numbers for the file list */
@@ -203,7 +209,21 @@ enum {
   SEARCH_MODEL_COL_PATH,
   SEARCH_MODEL_COL_DISPLAY_NAME,
   SEARCH_MODEL_COL_COLLATION_KEY,
-  SEARCH_MODEL_COL_STAT
+  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 */
@@ -217,8 +237,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[] = {
@@ -226,24 +245,21 @@ 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); 
 
 static gboolean
 search_is_possible (GtkFileChooserDefault *impl)
@@ -258,6 +274,8 @@ search_is_possible (GtkFileChooserDefault *impl)
 typedef enum {
   SHORTCUTS_SEARCH,
   SHORTCUTS_SEARCH_SEPARATOR,
+  SHORTCUTS_RECENT,
+  SHORTCUTS_RECENT_SEPARATOR,
   SHORTCUTS_HOME,
   SHORTCUTS_DESKTOP,
   SHORTCUTS_VOLUMES,
@@ -344,18 +362,20 @@ static void           gtk_file_chooser_default_get_resizable_hints    (GtkFileCh
 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 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 update_appearance      (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);
@@ -406,11 +426,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);
@@ -452,7 +472,8 @@ 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);
+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);
@@ -460,6 +481,21 @@ 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     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);
+
 
 
 
@@ -594,6 +630,22 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
 			     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);
 
@@ -660,6 +712,14 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
 				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,
@@ -809,7 +869,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() */
@@ -892,6 +953,7 @@ gtk_file_chooser_default_finalize (GObject *object)
     g_object_unref (impl->sort_model);
 
   search_clear_model (impl, FALSE);
+  recent_clear_model (impl, FALSE);
 
   g_free (impl->preview_display_name);
 
@@ -955,7 +1017,7 @@ error_dialog (GtkFileChooserDefault *impl,
 	      const GtkFilePath     *path,
 	      GError                *error)
 {
-  if (error)
+  if (G_LIKELY (error))
     {
       char *uri = NULL;
       char *text;
@@ -1025,9 +1087,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);
 }
 
@@ -1149,7 +1211,13 @@ set_preview_widget (GtkFileChooserDefault *impl,
 static GdkPixbuf *
 render_search_icon (GtkFileChooserDefault *impl)
 {
-  return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FIND, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
+  return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FIND, GTK_ICON_SIZE_MENU, NULL);
+}
+
+static GdkPixbuf *
+render_recent_icon (GtkFileChooserDefault *impl)
+{
+  return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
 }
 
 
@@ -1298,7 +1366,11 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl)
 	  else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
 	    {
 	      pixbuf = render_search_icon (impl);
-	    }
+            }
+	  else if (shortcut_type == SHORTCUT_TYPE_RECENT)
+            {
+              pixbuf = render_recent_icon (impl);
+            }
 	}
     }
   while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
@@ -1757,6 +1829,30 @@ shortcuts_append_search (GtkFileChooserDefault *impl)
   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)
@@ -1880,6 +1976,16 @@ shortcuts_get_index (GtkFileChooserDefault *impl,
 
   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;
 
@@ -2002,7 +2108,8 @@ shortcuts_insert_separator (GtkFileChooserDefault *impl,
   GtkTreeIter iter;
 
   g_assert (where == SHORTCUTS_SEARCH_SEPARATOR || 
-	    where == SHORTCUTS_BOOKMARKS_SEPARATOR || 
+	    where == SHORTCUTS_RECENT_SEPARATOR ||
+            where == SHORTCUTS_BOOKMARKS_SEPARATOR || 
 	    where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
 
   gtk_list_store_insert (impl->shortcuts_model, &iter,
@@ -2217,6 +2324,12 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
       shortcuts_append_search (impl);
       shortcuts_insert_separator (impl, SHORTCUTS_SEARCH_SEPARATOR);
     }
+
+  if (impl->recent_manager)
+    {
+      shortcuts_append_recent (impl);
+      shortcuts_insert_separator (impl, SHORTCUTS_RECENT_SEPARATOR);
+    }
   
   if (impl->file_system)
     {
@@ -2369,10 +2482,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
@@ -2382,10 +2495,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 */
@@ -2403,11 +2516,11 @@ filter_create (GtkFileChooserDefault *impl)
 
 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;
@@ -2530,10 +2643,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;
 
-  file_path = _gtk_file_system_model_get_path (fs_model, &child_iter);
+    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;
+
+    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);
 }
 
@@ -2645,10 +2777,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;
@@ -2702,8 +2852,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 */
@@ -2741,13 +2910,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);
     }
 }
 
@@ -2764,16 +2955,6 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
   gboolean active;
   gchar *tip;
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
-    {
-      gtk_widget_set_sensitive (impl->browse_shortcuts_add_button, FALSE);
-      
-      if (impl->browse_files_popup_menu_add_shortcut_item)
-	gtk_widget_set_sensitive (impl->browse_files_popup_menu_add_shortcut_item, FALSE);
-      
-      return;
-    }
-
   selection_check (impl, &num_selected, NULL, &all_folders);
 
   if (num_selected == 0)
@@ -2792,26 +2973,26 @@ 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;
-	  
-	}
+        {
+          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);
       g_free (tip);
     }
@@ -3193,9 +3374,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
     {
@@ -4092,7 +4275,7 @@ file_list_update_popup_menu (GtkFileChooserDefault *impl)
 {
   file_list_build_popup_menu (impl);
 
-  /* FMQ: handle OPERATION_MODE_SEARCH */
+  /* FIXME - handle OPERATION_MODE_SEARCH and OPERATION_MODE_RECENT */
 
   /* The sensitivity of the Add to Bookmarks item is set in
    * bookmarks_check_add_sensitivity()
@@ -4199,15 +4382,22 @@ file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
 {
   int name_id, mtime_id;
 
-  if (impl->operation_mode == OPERATION_MODE_BROWSE)
+  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;
-    }
-  else
-    {
+      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);
@@ -4488,6 +4678,19 @@ shortcuts_combo_filter_func (GtkTreeModel *model,
 	    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);
 
@@ -4704,6 +4907,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);
 
@@ -4740,8 +4951,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;
@@ -4936,8 +5147,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 */
@@ -5206,7 +5419,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 "
@@ -5253,7 +5467,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 "
@@ -5460,8 +5675,8 @@ gtk_file_chooser_default_dispose (GObject *object)
       impl->shortcuts_activate_iter_handle = NULL;
     }
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
-    search_stop_searching (impl);
+  search_stop_searching (impl, TRUE);
+  recent_stop_loading (impl);
 
   remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
 
@@ -5559,8 +5774,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);
@@ -5595,6 +5810,24 @@ check_icon_theme (GtkFileChooserDefault *impl)
 }
 
 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)
 {
@@ -5634,6 +5867,7 @@ 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");
 
@@ -5841,8 +6075,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)												       \
@@ -6391,7 +6625,9 @@ update_chooser_entry (GtkFileChooserDefault *impl)
   struct update_chooser_entry_selected_foreach_closure closure;
   const char *file_part;
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH || !impl->location_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
@@ -6415,9 +6651,10 @@ update_chooser_entry (GtkFileChooserDefault *impl)
     }
   else if (closure.num_selected == 1)
     {
+      GtkTreeIter child_iter;
+      
       if (impl->operation_mode == OPERATION_MODE_BROWSE)
         {
-          GtkTreeIter child_iter;
           const GtkFileInfo *info;
           gboolean change_entry;
 
@@ -6448,18 +6685,25 @@ update_chooser_entry (GtkFileChooserDefault *impl)
                                                    impl->browse_files_last_selected_name);
 
         }
-      else
+      else if (impl->operation_mode == OPERATION_MODE_SEARCH)
         {
-          gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model),
-                              &closure.first_selected_iter,
+          search_get_valid_child_iter (impl, &child_iter, &closure.first_selected_iter);
+          gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
                               SEARCH_MODEL_COL_DISPLAY_NAME, &file_part,
                               -1);
         }
+      else if (impl->operation_mode == OPERATION_MODE_RECENT)
+        {
+          recent_get_valid_child_iter (impl, &child_iter, &closure.first_selected_iter);
+          gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
+                              RECENT_MODEL_COL_DISPLAY_NAME, &file_part,
+                              -1);
+        }
     }
   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. */
 
@@ -6668,7 +6912,17 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
 
   profile_start ("start", (char *) path);
 
- search_switch_to_browse_mode (impl);
+  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);
 
@@ -6712,7 +6966,8 @@ gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+  if (impl->operation_mode == OPERATION_MODE_SEARCH ||
+      impl->operation_mode == OPERATION_MODE_RECENT)
     return NULL;
  
   if (impl->reload_state == RELOAD_EMPTY)
@@ -6739,8 +6994,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);
@@ -6777,8 +7032,12 @@ gtk_file_chooser_default_select_path (GtkFileChooser    *chooser,
   if (!parent_path)
    return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH || 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);
@@ -6874,7 +7133,8 @@ gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+  if (impl->operation_mode == OPERATION_MODE_SEARCH ||
+      impl->operation_mode == OPERATION_MODE_RECENT)
     {
       GtkTreeSelection *selection;
       
@@ -7027,6 +7287,9 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
   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;
   info.path_from_entry = NULL;
@@ -7092,9 +7355,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; 
@@ -7785,8 +8048,8 @@ 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)
+  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
@@ -8064,6 +8327,9 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
       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)
@@ -8137,14 +8403,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)
 	    {
 	      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.
@@ -8246,16 +8512,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
     {
@@ -8315,6 +8581,81 @@ search_should_respond (GtkFileChooserDefault *impl)
   return (gtk_tree_selection_count_selected_rows (selection) != 0);
 }
 
+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;
+  GdkPixbuf *pixbuf = NULL;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  GtkFileSystemHandle *model_handle;
+  gboolean is_folder = FALSE;
+  char *mime_type;
+  char *display_name;
+  struct SearchHitInsertRequest *request = data;
+
+  path = gtk_tree_row_reference_get_path (request->row_ref);
+  if (!path)
+    goto out;
+
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->search_model),
+                           &iter, path);
+  gtk_tree_path_free (path);
+
+  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;
+
+  /* set the handle to NULL in the model */
+  gtk_list_store_set (request->impl->search_model, &iter,
+                      SEARCH_MODEL_COL_HANDLE, NULL,
+                      -1);
+
+  if (cancelled)
+    goto out;
+
+  if (!info)
+    {
+      gtk_list_store_remove (request->impl->search_model, &iter);
+      goto out;
+    }
+
+  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 (request->impl);
+  gtk_file_path_free (request->path);
+  gtk_tree_row_reference_free (request->row_ref);
+  g_free (request);
+
+  g_object_unref (handle);
+}
 
 /* Adds one hit from the search engine to the search_model */
 static void
@@ -8323,11 +8664,14 @@ search_add_hit (GtkFileChooserDefault *impl,
 {
   GtkFilePath *path;
   char *filename;
-  char *display_name;
+  char *tmp;
   char *collation_key;
   struct stat statbuf;
   struct stat *statbuf_copy;
   GtkTreeIter iter;
+  GtkTreePath *p;
+  GtkFileSystemHandle *handle;
+  struct SearchHitInsertRequest *request;
 
   path = gtk_file_system_uri_to_path (impl->file_system, uri);
   if (!path)
@@ -8350,15 +8694,31 @@ search_add_hit (GtkFileChooserDefault *impl,
   statbuf_copy = g_new (struct stat, 1);
   *statbuf_copy = statbuf;
 
-  display_name = g_filename_display_name (filename);
-  collation_key = g_utf8_collate_key_for_filename (display_name, -1);
+  tmp = g_filename_display_name (filename);
+  collation_key = g_utf8_collate_key_for_filename (tmp, -1);
+  g_free (tmp);
+
+  request = g_new0 (struct SearchHitInsertRequest, 1);
+  request->impl = g_object_ref (impl);
+  request->path = gtk_file_path_copy (path);
+
+  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);
+
+  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);
 
-  gtk_list_store_insert_with_values (impl->search_model, &iter, -1,
-				     SEARCH_MODEL_COL_PATH, path,
-				     SEARCH_MODEL_COL_DISPLAY_NAME, display_name,
-				     SEARCH_MODEL_COL_COLLATION_KEY, collation_key,
-				     SEARCH_MODEL_COL_STAT, statbuf_copy,
-				     -1);
+  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);
 }
 
 /* Callback used from GtkSearchEngine when we get new hits */
@@ -8385,8 +8745,15 @@ search_engine_finished_cb (GtkSearchEngine *engine,
   
   impl = GTK_FILE_CHOOSER_DEFAULT (data);
   
-  /* FMQ: if search was empty, say that we got no hits */
+#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
 
+  /* FMQ: if search was empty, say that we got no hits */
   set_busy_cursor (impl, FALSE);
 }
 
@@ -8412,7 +8779,7 @@ search_engine_error_cb (GtkSearchEngine *engine,
   
   impl = GTK_FILE_CHOOSER_DEFAULT (data);
 
-  search_stop_searching (impl);
+  search_stop_searching (impl, TRUE);
   error_message (impl, _("Could not send the search request"), message);
 
   set_busy_cursor (impl, FALSE);
@@ -8423,35 +8790,49 @@ static void
 search_clear_model (GtkFileChooserDefault *impl, 
 		    gboolean               remove_from_treeview)
 {
+  GtkTreeModel *model;
   GtkTreeIter iter;
 
   if (!impl->search_model)
     return;
 
-  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->search_model), &iter))
+  model = GTK_TREE_MODEL (impl->search_model);
+
+  if (gtk_tree_model_get_iter_first (model, &iter))
     do
       {
-	GtkFilePath *path;
-	char *display_name;
-	char *collation_key;
+        GtkFilePath *path;
+        gchar *display_name;
+        gchar *collation_key;
 	struct stat *statbuf;
+        GtkFileSystemHandle *handle;
 
-	gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &iter,
-			    SEARCH_MODEL_COL_PATH, &path,
-			    SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
-			    SEARCH_MODEL_COL_COLLATION_KEY, &collation_key,
+	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);
+        gtk_file_path_free (path);
+        g_free (display_name);
+        g_free (collation_key);
 	g_free (statbuf);
       }
-    while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->search_model), &iter));
+    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);
@@ -8459,14 +8840,15 @@ search_clear_model (GtkFileChooserDefault *impl,
 
 /* Stops any ongoing searches; does not touch the search_model */
 static void
-search_stop_searching (GtkFileChooserDefault *impl)
+search_stop_searching (GtkFileChooserDefault *impl,
+                       gboolean               remove_query)
 {
-  if (impl->search_query)
+  if (remove_query && impl->search_query)
     {
       g_object_unref (impl->search_query);
       impl->search_query = NULL;
     }
-
+  
   if (impl->search_engine)
     {
       g_object_unref (impl->search_engine);
@@ -8478,10 +8860,9 @@ search_stop_searching (GtkFileChooserDefault *impl)
 static void
 search_switch_to_browse_mode (GtkFileChooserDefault *impl)
 {
-  if (impl->operation_mode == OPERATION_MODE_BROWSE)
-    return;
+  g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
 
-  search_stop_searching (impl);
+  search_stop_searching (impl, FALSE);
   search_clear_model (impl, TRUE);
 
   gtk_widget_destroy (impl->search_hbox);
@@ -8491,8 +8872,8 @@ search_switch_to_browse_mode (GtkFileChooserDefault *impl)
   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)
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
     {
       gtk_widget_show (impl->location_button);
 
@@ -8513,9 +8894,26 @@ search_column_path_sort_func (GtkTreeModel *model,
 			      gpointer      user_data)
 {
   const char *collation_key_a, *collation_key_b;
+  gboolean is_folder_a, is_folder_b;
+
+  gtk_tree_model_get (model, a,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
+                      SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_a,
+                      -1);
+  gtk_tree_model_get (model, b,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
+                      SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_b,
+                      -1);
+
+  if (!collation_key_a)
+    return 1;
 
-  gtk_tree_model_get (model, a, SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_a, -1);
-  gtk_tree_model_get (model, b, SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_b, -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);
 }
@@ -8528,6 +8926,7 @@ search_column_mtime_sort_func (GtkTreeModel *model,
 			       gpointer      user_data)
 {
   const struct stat *statbuf_a, *statbuf_b;
+  gboolean is_folder_a, is_folder_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
@@ -8535,8 +8934,23 @@ search_column_mtime_sort_func (GtkTreeModel *model,
    * one as well.
    */
 
-  gtk_tree_model_get (model, a, SEARCH_MODEL_COL_STAT, &statbuf_a, -1);
-  gtk_tree_model_get (model, b, SEARCH_MODEL_COL_STAT, &statbuf_b, -1);
+  gtk_tree_model_get (model, a,
+                      SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
+                      SEARCH_MODEL_COL_STAT, &statbuf_a,
+                      -1);
+  gtk_tree_model_get (model, 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;
@@ -8546,42 +8960,169 @@ search_column_mtime_sort_func (GtkTreeModel *model,
     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_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.
+   * Keep this in sync with the enumeration defined near the beginning
+   * of this file.
    */
-  impl->search_model = gtk_list_store_new (4,
+  impl->search_model = gtk_list_store_new (SEARCH_MODEL_COL_NUM_COLUMNS,
 					   G_TYPE_POINTER,
 					   G_TYPE_POINTER,
 					   G_TYPE_POINTER,
-					   G_TYPE_POINTER);
-  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
+					   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 (gtk_tree_model_sort_new_with_model (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),
+  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),
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->search_model_sort),
 					SEARCH_MODEL_COL_STAT,
 					GTK_SORT_DESCENDING);
 
-  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), GTK_TREE_MODEL (impl->search_model));
+  /* 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 */
@@ -8589,7 +9130,7 @@ static void
 search_start_query (GtkFileChooserDefault *impl,
 		    const gchar           *query_text)
 {
-  search_stop_searching (impl);
+  search_stop_searching (impl, FALSE);
   search_clear_model (impl, TRUE);
   search_setup_model (impl);
   set_busy_cursor (impl, TRUE);
@@ -8604,8 +9145,12 @@ search_start_query (GtkFileChooserDefault *impl,
       return;
     }
 
-  impl->search_query = _gtk_query_new ();
-  _gtk_query_set_text (impl->search_query, query_text);
+  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",
@@ -8618,7 +9163,9 @@ search_start_query (GtkFileChooserDefault *impl,
   _gtk_search_engine_start (impl->search_engine);
 }
 
-/* Callback used when the user presses Enter while typing on the search entry; starts the query */
+/* 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)
@@ -8632,6 +9179,13 @@ search_entry_activate_cb (GtkEntry *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);
 }
 
@@ -8640,38 +9194,53 @@ static void
 search_setup_widgets (GtkFileChooserDefault *impl)
 {
   GtkWidget *label;
-  gchar *text;
 
   impl->search_hbox = gtk_hbox_new (FALSE, 12);
 
   /* Label */
 
-  label = gtk_label_new (NULL);
-  text = g_strdup_printf ("<b>%s</b>", _("Search:"));
-  gtk_label_set_markup (GTK_LABEL (label), text);
-  g_free (text);
+  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)
+  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);
@@ -8688,23 +9257,651 @@ search_setup_widgets (GtkFileChooserDefault *impl)
 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);
 
-  stop_loading_and_clear_list_model (impl);
   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 (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;
+
+  if (remove_from_treeview)
+    gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), 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)
+{
+  GtkRecentInfo *info_a, *info_b;
+  gboolean is_folder_a, is_folder_b;
+
+  gtk_tree_model_get (model, a,
+                      RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
+                      RECENT_MODEL_COL_INFO, &info_a,
+                      -1);
+  gtk_tree_model_get (model, 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)
+{
+  gchar *name_a, *name_b;
+
+  gtk_tree_model_get (model, a, RECENT_MODEL_COL_DISPLAY_NAME, &name_a, -1);
+  gtk_tree_model_get (model, b, RECENT_MODEL_COL_DISPLAY_NAME, &name_b, -1);
+
+  if (!name_a)
+    return 1;
+
+  if (!name_b);
+    return -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 (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->recent_model_filter)));
+  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_func (GTK_TREE_SORTABLE (impl->recent_model_sort),
+                                   RECENT_MODEL_COL_PATH,
+                                   recent_column_path_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;
+} 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;
+
+  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 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;
+
+  if (!load_data->items)
+    {
+      load_data->items = gtk_recent_manager_get_items (impl->recent_manager);
+      load_data->n_items = g_list_length (load_data->items);
+      load_data->n_loaded_items = 0;
+
+      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;
+
+  /* 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)
@@ -8734,6 +9931,12 @@ set_current_filter (GtkFileChooserDefault *impl,
       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");
     }
 }
@@ -8760,12 +9963,13 @@ check_preview_change (GtkFileChooserDefault *impl)
   new_display_name = NULL;
   if (cursor_path)
     {
+      GtkTreeIter child_iter;
+
       if (impl->operation_mode == OPERATION_MODE_BROWSE)
 	{
 	  if (impl->sort_model)
 	    {
 	      GtkTreeIter iter;
-	      GtkTreeIter child_iter;
 	      const GtkFileInfo *new_info;
 
 	      gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
@@ -8779,18 +9983,34 @@ check_preview_change (GtkFileChooserDefault *impl)
 	        new_display_name = gtk_file_info_get_display_name (new_info);
 	    }
 	}
-      else
+      else if (impl->operation_mode == OPERATION_MODE_SEARCH)
 	{
 	  GtkTreeIter iter;
 
-	  gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model), &iter, cursor_path);
+	  gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort),
+                                   &iter, cursor_path);
 	  gtk_tree_path_free (cursor_path);
 
-	  gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &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, &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 &&
@@ -8877,7 +10097,17 @@ shortcuts_activate_volume (GtkFileChooserDefault *impl,
 {
   GtkFilePath *path;
 
-  search_switch_to_browse_mode (impl);
+  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.
@@ -8996,6 +10226,10 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
     {
       search_activate (impl);
     }
+  else if (shortcut_type == SHORTCUT_TYPE_RECENT)
+    {
+      recent_activate (impl);
+    }
 }
 
 /* Callback used when a row in the shortcuts list is activated */
@@ -9102,7 +10336,8 @@ list_selection_changed (GtkTreeSelection      *selection,
 			GtkFileChooserDefault *impl)
 {
   /* See if we are in the new folder editable row for Save mode */
-  if (impl->operation_mode == OPERATION_MODE_BROWSE && 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;
@@ -9134,35 +10369,86 @@ list_row_activated (GtkTreeView           *tree_view,
 		    GtkTreeViewColumn     *column,
 		    GtkFileChooserDefault *impl)
 {
-  GtkTreeIter iter, child_iter;
-  const GtkFileInfo *info;
+  GtkTreeIter iter;
+  GtkTreeIter child_iter;
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+  switch (impl->operation_mode)
     {
-      g_signal_emit_by_name (impl, "file-activated");
-      return;
-    }
+    case OPERATION_MODE_SEARCH:
+      {
+        GtkFilePath *file_path;
+        gboolean is_folder;
 
-  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
-    return;
+        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
+          return;
 
-  gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &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;
+          }
 
-  info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+        g_signal_emit_by_name (impl, "file-activated");
+      }
+      break;
 
-  if (gtk_file_info_get_is_folder (info))
-    {
-      const GtkFilePath *file_path;
+    case OPERATION_MODE_RECENT:
+      {
+        GtkFilePath *file_path;
+        gboolean is_folder;
 
-      file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
-      change_folder_and_display_error (impl, file_path, FALSE);
+        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");
+        if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+            impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+          g_signal_emit_by_name (impl, "file-activated");
+      }
+      break;
+    }
 }
 
 static void
@@ -9208,49 +10494,75 @@ 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;
 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
-    {
-      g_object_set (cell,
-		    "pixbuf", NULL,
-		    "sensitive", TRUE,
-		    NULL);
-      return;
-    }
-  
   profile_start ("start", NULL);
   
-  info = get_list_file_info (impl, iter);
+  switch (impl->operation_mode)
+    {
+    case OPERATION_MODE_SEARCH:
+      {
+        GtkTreeIter child_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);
+        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,
+                            -1);
+        sensitive = TRUE;
+      }
+      break;
 
-  if (path)
-    {
-      pixbuf = NULL;
+    case OPERATION_MODE_RECENT:
+      {
+        GtkTreeIter child_iter;
+        GtkRecentInfo *info;
 
-      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;
+        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,
+                            -1);
+        
+        pixbuf = gtk_recent_info_get_icon (info, impl->icon_size);
+        
+        if (impl->local_only && !gtk_recent_info_is_local (info))
+          sensitive = FALSE;
+      }
+      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,
@@ -9276,16 +10588,56 @@ list_name_data_func (GtkTreeViewColumn *tree_column,
 
   if (impl->operation_mode == OPERATION_MODE_SEARCH)
     {
-      char *display_name;
+      GtkTreeIter child_iter;
+      GtkFilePath *file_path;
+      gchar *display_name, *tmp;
+      gchar *text;
 
-      gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), iter,
-			  SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
+      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_DISPLAY_NAME, &display_name,
 			  -1);
+
+      tmp = gtk_file_system_path_to_filename (impl->file_system, file_path);
+      text = g_strdup_printf ("<b>%s</b>\n%s", display_name, tmp);
+      g_free (tmp);
+
       g_object_set (cell,
-		    "text", display_name,
+		    "markup", text,
 		    "sensitive", TRUE,
-		    "ellipsize", PANGO_ELLIPSIZE_START,
+		    "ellipsize", PANGO_ELLIPSIZE_END,
 		    NULL);
+      
+      g_free (text);
+
+      return;
+    }
+
+  if (impl->operation_mode == OPERATION_MODE_RECENT)
+    {
+      GtkTreeIter child_iter;
+      GtkRecentInfo *recent_info;
+      char *tmp, *text;
+
+      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,
+                          -1);
+      
+      tmp = gtk_recent_info_get_short_name (recent_info);
+      text = g_strdup_printf ("<b>%s</b>\n%s",
+                              tmp,
+                              gtk_recent_info_get_uri_display (recent_info));
+      g_free (tmp);
+
+      g_object_set (cell,
+                    "markup", text,
+                    "sensitive", TRUE,
+                    "ellipsize", PANGO_ELLIPSIZE_END,
+                    NULL);
+      g_free (text);
+
       return;
     }
 
@@ -9304,8 +10656,8 @@ list_name_data_func (GtkTreeViewColumn *tree_column,
     }
 
 
-  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);
     } 
@@ -9385,12 +10737,31 @@ list_mtime_data_func (GtkTreeViewColumn *tree_column,
 
   if (impl->operation_mode == OPERATION_MODE_SEARCH)
     {
+      GtkTreeIter child_iter;
       struct stat *statbuf;
 
-      gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), iter,
-			  SEARCH_MODEL_COL_STAT, &statbuf,
+      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,
 			  -1);
-      time_mtime = statbuf->st_mtime;
+      if (statbuf)
+        time_mtime = statbuf->st_mtime;
+      else
+        time_mtime = 0;
+    }
+  else if (impl->operation_mode == OPERATION_MODE_RECENT)
+    {
+      GtkTreeIter child_iter;
+      GtkRecentInfo *info;
+
+      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,
+                          -1);
+      time_mtime = (GtkFileTime) gtk_recent_info_get_modified (info);
+
+      if (impl->local_only && !gtk_recent_info_is_local (info))
+        sensitive = FALSE;
     }
   else
     {
@@ -9468,12 +10839,24 @@ static void
 location_popup_handler (GtkFileChooserDefault *impl,
 			const gchar           *path)
 { 
-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+  if (impl->operation_mode != OPERATION_MODE_BROWSE)
     {
       GtkWidget *widget_to_focus;
       
       /* This will give us the location widgets back */
-      search_switch_to_browse_mode (impl);
+      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);
 
@@ -9485,8 +10868,9 @@ location_popup_handler (GtkFileChooserDefault *impl,
       gtk_widget_grab_focus (widget_to_focus);
       return; 
     }
-  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)
     {
       LocationMode new_mode;
 
@@ -9517,8 +10901,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)
@@ -9572,6 +10956,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)
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index 3a7416c..32d1536 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -25,6 +25,7 @@
 #include "gtkfilesystem.h"
 #include "gtkfilesystemmodel.h"
 #include "gtkliststore.h"
+#include "gtkrecentmanager.h"
 #include "gtksearchengine.h"
 #include "gtkquery.h"
 #include "gtktooltips.h"
@@ -151,7 +152,8 @@ typedef enum {
 
 typedef enum {
   OPERATION_MODE_BROWSE,
-  OPERATION_MODE_SEARCH
+  OPERATION_MODE_SEARCH,
+  OPERATION_MODE_RECENT
 } OperationMode;
 
 struct _GtkFileChooserDefault
@@ -188,12 +190,21 @@ struct _GtkFileChooserDefault
   GtkFileSystemModel *browse_files_model;
   char *browse_files_last_selected_name;
 
-  /* Widgets for searching */
+  /* OPERATION_MODE_SEARCH */
   GtkWidget *search_hbox;
   GtkWidget *search_entry;
   GtkSearchEngine *search_engine;
   GtkQuery *search_query;
   GtkListStore *search_model;
+  GtkTreeModelFilter *search_model_filter;
+  GtkTreeModelSort *search_model_sort;
+
+  /* OPERATION_MODE_RECENT */
+  GtkRecentManager *recent_manager;
+  GtkListStore *recent_model;
+  guint load_recent_id;
+  GtkTreeModelFilter *recent_model_filter;
+  GtkTreeModelSort *recent_model_sort;
 
   GtkWidget *filter_combo_hbox;
   GtkWidget *filter_combo;
@@ -293,6 +304,7 @@ struct _GtkFileChooserDefault
   guint has_home : 1;
   guint has_desktop : 1;
   guint has_search : 1;
+  guint has_recent : 1;
 
 #if 0
   guint shortcuts_drag_outside : 1;
