File gtk2-filechooser-icon-view.patch of Package gtk2

diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index c11354248e..a994aa9c6f 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -80,6 +80,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <locale.h>
+#include <math.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -205,7 +206,8 @@ enum {
   MODEL_COL_NAME_COLLATED,
   MODEL_COL_IS_FOLDER,
   MODEL_COL_IS_SENSITIVE,
-  MODEL_COL_PIXBUF,
+  MODEL_COL_LIST_PIXBUF,
+  MODEL_COL_ICON_PIXBUF,
   MODEL_COL_SIZE_TEXT,
   MODEL_COL_MTIME_TEXT,
   MODEL_COL_ELLIPSIZE,
@@ -222,7 +224,8 @@ enum {
 	G_TYPE_STRING,		  /* MODEL_COL_NAME_COLLATED */	\
 	G_TYPE_BOOLEAN,		  /* MODEL_COL_IS_FOLDER */	\
 	G_TYPE_BOOLEAN,		  /* MODEL_COL_IS_SENSITIVE */	\
-	GDK_TYPE_PIXBUF,	  /* MODEL_COL_PIXBUF */	\
+	GDK_TYPE_PIXBUF,	  /* MODEL_COL_LIST_PIXBUF */	\
+	GDK_TYPE_PIXBUF,	  /* MODEL_COL_ICON_PIXBUF */	\
 	G_TYPE_STRING,		  /* MODEL_COL_SIZE_TEXT */	\
 	G_TYPE_STRING,		  /* MODEL_COL_MTIME_TEXT */	\
 	PANGO_TYPE_ELLIPSIZE_MODE /* MODEL_COL_ELLIPSIZE */
@@ -249,7 +252,10 @@ typedef enum {
 } ShortcutsIndex;
 
 /* Icon size for if we can't get it from the theme */
-#define FALLBACK_ICON_SIZE 16
+#define FALLBACK_LIST_VIEW_ICON_SIZE 16
+#define FALLBACK_ICON_VIEW_ICON_SIZE 48
+
+#define ICON_VIEW_ITEM_WIDTH 128
 
 #define PREVIEW_HBOX_SPACING 12
 #define NUM_LINES 45
@@ -337,6 +343,7 @@ 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_sort_column         (GtkFileChooserDefault *impl);
 
 static void set_current_filter   (GtkFileChooserDefault *impl,
 				  GtkFileFilter         *filter);
@@ -371,12 +378,18 @@ static gboolean list_select_func   (GtkTreeSelection      *selection,
 				    gboolean               path_currently_selected,
 				    gpointer               data);
 
-static void list_selection_changed     (GtkTreeSelection      *tree_selection,
+static void list_selection_changed     (void      *tree_or_icon_selection,
 					GtkFileChooserDefault *impl);
 static void list_row_activated         (GtkTreeView           *tree_view,
 					GtkTreePath           *path,
 					GtkTreeViewColumn     *column,
 					GtkFileChooserDefault *impl);
+static void icon_item_activated        (GtkIconView           *icon_view,
+                                        GtkTreePath           *path,
+                                        GtkFileChooserDefault *impl);
+static void item_activated             (GtkTreeModel          *model,
+                                        GtkTreePath           *path,
+                                        GtkFileChooserDefault *impl);
 
 static void path_bar_clicked (GtkPathBar            *path_bar,
 			      GFile                 *file,
@@ -394,6 +407,13 @@ static void update_cell_renderer_attributes (GtkFileChooserDefault *impl);
 static void load_remove_timer (GtkFileChooserDefault *impl, LoadState new_load_state);
 static void browse_files_center_selected_row (GtkFileChooserDefault *impl);
 
+static void view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode);
+static void view_mode_combo_box_changed_cb (GtkComboBox           *combo,
+                                            GtkFileChooserDefault *impl);
+
+static void icon_view_scale_value_changed_cb (GtkRange              *range,
+                                              GtkFileChooserDefault *impl);
+
 static void location_button_toggled_cb (GtkToggleButton *toggle,
 					GtkFileChooserDefault *impl);
 static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
@@ -422,7 +442,27 @@ static GSList * recent_get_selected_files    (GtkFileChooserDefault *impl);
 static void     set_file_system_backend      (GtkFileChooserDefault *impl);
 static void     unset_file_system_backend    (GtkFileChooserDefault *impl);
 
-
+static gboolean get_selected_tree_iter_from_icon_view (GtkFileChooserDefault *impl,
+                                                       GtkTreeIter           *iter_out);
+static void     current_selection_selected_foreach    (GtkFileChooserDefault       *impl,
+                                                       GtkTreeSelectionForeachFunc func,
+                                                       gpointer                    data);
+static guint    current_selection_count_selected_rows (GtkFileChooserDefault *impl);
+static void     current_selection_select_iter         (GtkFileChooserDefault *impl,
+                                                       GtkTreeIter           *iter);
+static void     copy_old_selection_to_current_view    (GtkFileChooserDefault *impl,
+                                                       ViewMode               old_view_mode);
+static void     current_selection_unselect_iter       (GtkFileChooserDefault *impl,
+                                                       GtkTreeIter           *iter);
+static void     current_selection_unselect_all        (GtkFileChooserDefault *impl);
+static void     current_view_set_file_model           (GtkFileChooserDefault *impl,
+                                                       GtkTreeModel          *model);
+static void     current_view_set_cursor               (GtkFileChooserDefault *impl,
+                                                       GtkTreePath           *path);
+static void     current_view_set_select_multiple      (GtkFileChooserDefault *impl,
+                                                       gboolean select_multiple);
+
+static GSource *add_idle_while_impl_is_alive (GtkFileChooserDefault *impl, GCallback callback);
 
 
 
@@ -723,7 +763,8 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
   impl->select_multiple = FALSE;
   impl->show_hidden = FALSE;
   impl->show_size_column = TRUE;
-  impl->icon_size = FALLBACK_ICON_SIZE;
+  impl->list_view_icon_size = FALLBACK_LIST_VIEW_ICON_SIZE;
+  impl->icon_view_icon_size = FALLBACK_ICON_VIEW_ICON_SIZE;
   impl->load_state = LOAD_EMPTY;
   impl->reload_state = RELOAD_EMPTY;
   impl->pending_select_files = NULL;
@@ -733,6 +774,7 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
   impl->sort_order = GTK_SORT_ASCENDING;
   impl->recent_manager = gtk_recent_manager_get_default ();
   impl->create_folders = TRUE;
+  impl->view_mode = VIEW_MODE_LIST;
 
   gtk_box_set_spacing (GTK_BOX (impl), 12);
 
@@ -1159,7 +1201,7 @@ render_recent_icon (GtkFileChooserDefault *impl)
     theme = gtk_icon_theme_get_default ();
 
   retval = gtk_icon_theme_load_icon (theme, "document-open-recent",
-                                     impl->icon_size, 0,
+                                     impl->list_view_icon_size, 0,
                                      NULL);
 
   /* fallback */
@@ -1197,7 +1239,7 @@ shortcuts_reload_icons_get_info_cb (GCancellable *cancellable,
   if (cancelled || error)
     goto out;
 
-  pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (data->impl), data->impl->icon_size);
+  pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (data->impl), data->impl->list_view_icon_size);
 
   path = gtk_tree_row_reference_get_path (data->row_ref);
   if (path)
@@ -1261,7 +1303,7 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl)
 
 	      volume = data;
 	      pixbuf = _gtk_file_system_volume_render_icon (volume, GTK_WIDGET (impl),
-						 	    impl->icon_size, NULL);
+                                                            impl->list_view_icon_size, NULL);
 	    }
 	  else if (shortcut_type == SHORTCUT_TYPE_FILE)
             {
@@ -1297,7 +1339,7 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl)
 	           */
 	          icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
 	          pixbuf = gtk_icon_theme_load_icon (icon_theme, "folder-remote", 
-						     impl->icon_size, 0, NULL);
+						     impl->list_view_icon_size, 0, NULL);
 	        }
             }
 	  else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
@@ -1508,7 +1550,7 @@ get_file_info_finished (GCancellable *cancellable,
   if (!request->label_copy)
     request->label_copy = g_strdup (g_file_info_get_display_name (info));
   pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
-				       request->impl->icon_size);
+				       request->impl->list_view_icon_size);
 
   gtk_list_store_set (request->impl->shortcuts_model, &iter,
 		      SHORTCUTS_COL_PIXBUF, pixbuf,
@@ -1616,7 +1658,7 @@ shortcuts_insert_file (GtkFileChooserDefault *impl,
       data = volume;
       label_copy = _gtk_file_system_volume_get_display_name (volume);
       pixbuf = _gtk_file_system_volume_render_icon (volume, GTK_WIDGET (impl),
-				 		    impl->icon_size, NULL);
+                                                    impl->list_view_icon_size, NULL);
     }
   else if (shortcut_type == SHORTCUT_TYPE_FILE)
     {
@@ -1675,7 +1717,7 @@ shortcuts_insert_file (GtkFileChooserDefault *impl,
            */
           icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
           pixbuf = gtk_icon_theme_load_icon (icon_theme, "folder-remote", 
-					     impl->icon_size, 0, NULL);
+					     impl->list_view_icon_size, 0, NULL);
         }
     }
    else
@@ -2235,6 +2277,52 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
 					  NULL);
 }
 
+static gboolean
+start_editing_icon_view_idle_cb (GtkFileChooserDefault *impl)
+{
+  GDK_THREADS_ENTER ();
+
+  g_source_destroy (impl->start_editing_icon_view_idle);
+  impl->start_editing_icon_view_idle = NULL;
+
+  gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (impl->browse_files_icon_view),
+                               impl->start_editing_icon_view_path,
+                               TRUE,
+                               0.5,
+                               0.0);
+
+  g_object_set (impl->list_name_renderer, "editable", TRUE, NULL);
+  gtk_icon_view_set_cursor (GTK_ICON_VIEW (impl->browse_files_icon_view),
+                           impl->start_editing_icon_view_path,
+                           impl->list_name_renderer,
+                           TRUE);
+
+  gtk_tree_path_free (impl->start_editing_icon_view_path);
+  impl->start_editing_icon_view_path = NULL;
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+static void
+add_idle_to_edit_icon_view (GtkFileChooserDefault *impl, GtkTreePath *path)
+{
+  /* Normally we would run the code in the start_editing_icon_view_idle_cb() synchronously,
+   * but GtkIconView doesn't like to start editing itself immediately after getting an item
+   * added - it wants to run its layout loop first.  So, we add the editable item first, and
+   * only start editing it until an idle handler.
+   */
+
+  g_assert (impl->start_editing_icon_view_idle == NULL);
+  g_assert (impl->start_editing_icon_view_path == NULL);
+
+  impl->start_editing_icon_view_path = path;
+  impl->start_editing_icon_view_idle = add_idle_while_impl_is_alive (impl,
+                                                                    G_CALLBACK (start_editing_icon_view_idle_cb));
+}
+
+
 /* Callback used when the "New Folder" button is clicked */
 static void
 new_folder_button_clicked (GtkButton             *button,
@@ -2252,17 +2340,26 @@ new_folder_button_clicked (GtkButton             *button,
   _gtk_file_system_model_add_editable (impl->browse_files_model, &iter);
 
   path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->browse_files_model), &iter);
-  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view),
-				path, impl->list_name_column,
-				FALSE, 0.0, 0.0);
 
-  g_object_set (impl->list_name_renderer, "editable", TRUE, NULL);
-  gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view),
-			    path,
-			    impl->list_name_column,
-			    TRUE);
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                                    path, impl->list_name_column,
+                                    FALSE, 0.0, 0.0);
 
-  gtk_tree_path_free (path);
+      g_object_set (impl->list_name_renderer, "editable", TRUE, NULL);
+      gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                                path,
+                                impl->list_name_column,
+                                TRUE);
+      gtk_tree_path_free (path);
+    }
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    {
+      add_idle_to_edit_icon_view (impl, path);
+    }
+  else
+    g_assert_not_reached ();
 }
 
 static GSource *
@@ -2355,6 +2452,17 @@ renderer_edited_cb (GtkCellRendererText   *cell_renderer_text,
   queue_edited_idle (impl, new_text);
 }
 
+/* Callback used from the icon view text renderer to center editable text */
+static void
+renderer_editing_started_cb (GtkCellRendererText   *cell_renderer_text,
+                             GtkCellEditable       *editable,
+                             const gchar           *path,
+                             GtkFileChooserDefault *impl)
+{
+  if (GTK_IS_ENTRY (editable))
+      gtk_entry_set_alignment (GTK_ENTRY (editable), 0.5);
+}
+
 /* Callback used from the text cell renderer when the new folder edition gets
  * canceled.
  */
@@ -2525,16 +2633,10 @@ add_bookmark_foreach_cb (GtkTreeModel *model,
 static void
 bookmarks_add_selected_folder (GtkFileChooserDefault *impl)
 {
-  GtkTreeSelection *selection;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-
-  if (gtk_tree_selection_count_selected_rows (selection) == 0)
+  if (current_selection_count_selected_rows (impl) == 0)
     shortcuts_add_bookmark_from_file (impl, impl->current_folder, -1);
   else
-    gtk_tree_selection_selected_foreach (selection,
-					 add_bookmark_foreach_cb,
-					 impl);
+	current_selection_selected_foreach (impl, add_bookmark_foreach_cb, impl);
 }
 
 /* Callback used when the "Add bookmark" button is clicked */
@@ -2650,17 +2752,16 @@ selection_check (GtkFileChooserDefault *impl,
 		 gboolean              *all_folders)
 {
   struct selection_check_closure closure;
-  GtkTreeSelection *selection;
 
   closure.impl = impl;
   closure.num_selected = 0;
   closure.all_files = TRUE;
   closure.all_folders = TRUE;
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  gtk_tree_selection_selected_foreach (selection,
-				       selection_check_foreach_cb,
-				       &closure);
+  current_selection_selected_foreach (impl,
+                                      selection_check_foreach_cb,
+                                      &closure);
+
 
   g_assert (closure.num_selected == 0 || !(closure.all_files && closure.all_folders));
 
@@ -2704,15 +2805,13 @@ static GFile *
 get_selected_file (GtkFileChooserDefault *impl)
 {
   struct get_selected_file_closure closure;
-  GtkTreeSelection *selection;
 
   closure.impl = impl;
   closure.file = NULL;
 
-  selection =  gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  gtk_tree_selection_selected_foreach (selection,
-				       get_selected_file_foreach_cb,
-				       &closure);
+  current_selection_selected_foreach(impl,
+                                     get_selected_file_foreach_cb,
+                                     &closure);
 
   return closure.file;
 }
@@ -2787,13 +2886,11 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
         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);
+          current_selection_selected_foreach(impl, update_tooltip, &data);
           tip = data.tip;
         }
 
@@ -3775,7 +3872,7 @@ browse_files_key_press_event_cb (GtkWidget   *widget,
       return TRUE;
     }
 
-  if (key_is_left_or_right (event))
+  if (impl->view_mode == VIEW_MODE_LIST && key_is_left_or_right (event))
     {
       gtk_widget_grab_focus (impl->browse_shortcuts_tree_view);
       return TRUE;
@@ -3857,6 +3954,145 @@ show_size_column_toggled_cb (GtkCheckMenuItem *item,
                                     impl->show_size_column);
 }
 
+/* Callback used when "Sort by Name" menu item is toggled */
+static void
+sort_by_name_toggled_cb (GtkCheckMenuItem *item,
+                         GtkFileChooserDefault *impl)
+{
+  GtkCheckMenuItem *size_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_size_item),
+                   *mtime_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_mtime_item);
+
+  // This could be avoided if we used GtkAction's
+  if (!gtk_check_menu_item_get_active (item) &&
+      !gtk_check_menu_item_get_active (size_item) &&
+      !gtk_check_menu_item_get_active (mtime_item))
+    {
+      gtk_check_menu_item_set_active (item, TRUE);
+      return;
+    }
+
+  if (gtk_check_menu_item_get_active (item))
+    {
+      gtk_check_menu_item_set_active (size_item, FALSE);
+      gtk_check_menu_item_set_active (mtime_item, FALSE);
+
+      impl->sort_column = MODEL_COL_NAME;
+      set_sort_column (impl);
+    }
+}
+
+/* Callback used when "Sort by Size" menu item is toggled */
+static void
+sort_by_size_toggled_cb (GtkCheckMenuItem *item,
+                         GtkFileChooserDefault *impl)
+{
+  GtkCheckMenuItem *name_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_name_item),
+                   *mtime_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_mtime_item);
+
+  // This could be avoided if we used GtkAction's
+  if (!gtk_check_menu_item_get_active (item) &&
+      !gtk_check_menu_item_get_active (name_item) &&
+      !gtk_check_menu_item_get_active (mtime_item))
+    {
+      gtk_check_menu_item_set_active (item, TRUE);
+      return;
+    }
+
+  if (gtk_check_menu_item_get_active (item))
+    {
+      gtk_check_menu_item_set_active (name_item, FALSE);
+      gtk_check_menu_item_set_active (mtime_item, FALSE);
+
+      impl->sort_column = MODEL_COL_SIZE;
+      set_sort_column (impl);
+    }
+}
+
+/* Callback used when "Sort by Modification Date" menu item is toggled */
+static void
+sort_by_mtime_toggled_cb (GtkCheckMenuItem *item,
+                         GtkFileChooserDefault *impl)
+{
+  GtkCheckMenuItem *name_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_name_item),
+                   *size_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_size_item);
+
+  // This could be avoided if we used GtkAction's
+  if (!gtk_check_menu_item_get_active (item) &&
+      !gtk_check_menu_item_get_active (name_item) &&
+      !gtk_check_menu_item_get_active (size_item))
+    {
+      gtk_check_menu_item_set_active (item, TRUE);
+      return;
+    }
+
+  if (gtk_check_menu_item_get_active (item))
+    {
+      gtk_check_menu_item_set_active (name_item, FALSE);
+      gtk_check_menu_item_set_active (size_item, FALSE);
+
+      impl->sort_column = MODEL_COL_MTIME;
+      set_sort_column (impl);
+    }
+}
+
+/* Callback used when "Ascending" menu item is toggled */
+static void
+sort_ascending_toggled_cb (GtkCheckMenuItem *item,
+                         GtkFileChooserDefault *impl)
+{
+  GtkCheckMenuItem *desc_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_descending_item);
+
+  // This could be avoided if we used GtkAction's
+  if (!gtk_check_menu_item_get_active (item) &&
+      !gtk_check_menu_item_get_active (desc_item))
+    {
+      gtk_check_menu_item_set_active (item, TRUE);
+      return;
+    }
+
+  if (gtk_check_menu_item_get_active (item))
+    {
+      gtk_check_menu_item_set_active (desc_item, FALSE);
+
+      // The sort column is explicitly set to mtime for the recent model
+      // This prevents it from switching when changing sort order
+      if (impl->view_mode == VIEW_MODE_ICON && impl->current_model == GTK_TREE_MODEL (impl->recent_model))
+          gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (impl->current_model), &impl->sort_column, NULL);
+
+      impl->sort_order = GTK_SORT_ASCENDING;
+      set_sort_column (impl);
+    }
+}
+
+/* Callback used when "Descending" menu item is toggled */
+static void
+sort_descending_toggled_cb (GtkCheckMenuItem *item,
+                         GtkFileChooserDefault *impl)
+{
+  GtkCheckMenuItem *asc_item = GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_ascending_item);
+
+  // This could be avoided if we used GtkAction's
+  if (!gtk_check_menu_item_get_active (item) &&
+      !gtk_check_menu_item_get_active (asc_item))
+    {
+      gtk_check_menu_item_set_active (item, TRUE);
+      return;
+    }
+
+  if (gtk_check_menu_item_get_active (item))
+    {
+      gtk_check_menu_item_set_active (asc_item, FALSE);
+
+      // The sort column is explicitly set to mtime for the recent model
+      // This prevents it from switching when changing sort order
+      if (impl->view_mode == VIEW_MODE_ICON && impl->current_model == GTK_TREE_MODEL (impl->recent_model))
+          gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (impl->current_model), &impl->sort_column, NULL);
+
+      impl->sort_order = GTK_SORT_DESCENDING;
+      set_sort_column (impl);
+    }
+}
+
 /* Shows an error dialog about not being able to select a dragged file */
 static void
 error_selecting_dragged_file_dialog (GtkFileChooserDefault *impl,
@@ -3928,9 +4164,9 @@ file_list_drag_data_received_get_info_cb (GCancellable *cancellable,
       gtk_file_chooser_default_unselect_all (chooser);
       gtk_file_chooser_default_select_file (chooser, data->file, &error);
       if (error)
-	error_selecting_dragged_file_dialog (data->impl, data->file, error);
+        error_selecting_dragged_file_dialog (data->impl, data->file, error);
       else
-	browse_files_center_selected_row (data->impl);
+        browse_files_center_selected_row (data->impl);
     }
 
   if (data->impl->select_multiple)
@@ -4034,7 +4270,7 @@ file_list_build_popup_menu (GtkFileChooserDefault *impl)
 
   impl->browse_files_popup_menu = gtk_menu_new ();
   gtk_menu_attach_to_widget (GTK_MENU (impl->browse_files_popup_menu),
-			     impl->browse_files_tree_view,
+			     impl->browse_files_current_view,
 			     popup_menu_detach_cb);
 
   item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Bookmarks"));
@@ -4057,12 +4293,72 @@ file_list_build_popup_menu (GtkFileChooserDefault *impl)
   gtk_widget_show (item);
   gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
 
-  item = gtk_check_menu_item_new_with_mnemonic (_("Show _Size Column"));
-  impl->browse_files_popup_menu_size_column_item = item;
-  g_signal_connect (item, "toggled",
-                    G_CALLBACK (show_size_column_toggled_cb), impl);
-  gtk_widget_show (item);
-  gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      item = gtk_check_menu_item_new_with_mnemonic (_("Show _Size Column"));
+      impl->browse_files_popup_menu_size_column_item = item;
+      g_signal_connect (item, "toggled",
+                        G_CALLBACK (show_size_column_toggled_cb), impl);
+      gtk_widget_show (item);
+      gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
+    }
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    {
+      GtkWidget *menu, *subitem;
+
+      item = gtk_menu_item_new_with_label (_("Arrange Items"));
+      menu = gtk_menu_new ();
+      gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
+
+      subitem = gtk_check_menu_item_new_with_mnemonic (_("Sort by _Name"));
+      impl->browse_files_popup_menu_sort_by_name_item = subitem;
+      gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE);
+      g_signal_connect (subitem, "toggled",
+                        G_CALLBACK (sort_by_name_toggled_cb), impl);
+      gtk_widget_show (subitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem);
+
+      subitem = gtk_check_menu_item_new_with_mnemonic (_("Sort by _Size"));
+      impl->browse_files_popup_menu_sort_by_size_item = subitem;
+      gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE);
+      g_signal_connect (subitem, "toggled",
+                        G_CALLBACK (sort_by_size_toggled_cb), impl);
+      gtk_widget_show (subitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem);
+
+      subitem = gtk_check_menu_item_new_with_mnemonic (_("Sort by Modification _Date"));
+      impl->browse_files_popup_menu_sort_by_mtime_item = subitem;
+      gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE);
+      g_signal_connect (subitem, "toggled",
+                        G_CALLBACK (sort_by_mtime_toggled_cb), impl);
+      gtk_widget_show (subitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem);
+
+      subitem = gtk_separator_menu_item_new ();
+      gtk_widget_show (subitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem);
+
+      subitem = gtk_check_menu_item_new_with_mnemonic (_("_Ascending"));
+      impl->browse_files_popup_menu_sort_ascending_item = subitem;
+      gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE);
+      g_signal_connect (subitem, "toggled",
+                        G_CALLBACK (sort_ascending_toggled_cb), impl);
+      gtk_widget_show (subitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem);
+
+      subitem = gtk_check_menu_item_new_with_mnemonic (_("_Descending"));
+      impl->browse_files_popup_menu_sort_descending_item = subitem;
+      gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (subitem), TRUE);
+      g_signal_connect (subitem, "toggled",
+                        G_CALLBACK (sort_descending_toggled_cb), impl);
+      gtk_widget_show (subitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem);
+
+      gtk_widget_show (item);
+      gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
+    }
+  else
+    g_assert_not_reached ();
 
   bookmarks_check_add_sensitivity (impl);
 }
@@ -4087,13 +4383,61 @@ file_list_update_popup_menu (GtkFileChooserDefault *impl)
   g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_hidden_files_item,
 				     G_CALLBACK (show_hidden_toggled_cb), impl);
 
-  /* 'Show Size Column' */
-  g_signal_handlers_block_by_func (impl->browse_files_popup_menu_size_column_item,
-				   G_CALLBACK (show_size_column_toggled_cb), impl);
-  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_size_column_item),
-				  impl->show_size_column);
-  g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_size_column_item,
-				     G_CALLBACK (show_size_column_toggled_cb), impl);
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      /* 'Show Size Column' */
+      g_signal_handlers_block_by_func (impl->browse_files_popup_menu_size_column_item,
+               G_CALLBACK (show_size_column_toggled_cb), impl);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_size_column_item),
+              impl->show_size_column);
+      g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_size_column_item,
+                 G_CALLBACK (show_size_column_toggled_cb), impl);
+    }
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    {
+      gint column = impl->sort_column;
+      GtkSortType order = impl->sort_order;
+
+      if (impl->current_model == GTK_TREE_MODEL (impl->recent_model))
+        gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (impl->current_model), &column, &order);
+
+      g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_by_name_item,
+               G_CALLBACK (sort_by_name_toggled_cb), impl);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_name_item),
+              column == MODEL_COL_NAME);
+      g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_by_name_item,
+                 G_CALLBACK (sort_by_name_toggled_cb), impl);
+
+      g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_by_size_item,
+               G_CALLBACK (sort_by_size_toggled_cb), impl);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_size_item),
+              column == MODEL_COL_SIZE);
+      g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_by_size_item,
+                 G_CALLBACK (sort_by_size_toggled_cb), impl);
+
+      g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_by_mtime_item,
+               G_CALLBACK (sort_by_mtime_toggled_cb), impl);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_by_mtime_item),
+              column == MODEL_COL_MTIME);
+      g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_by_mtime_item,
+                 G_CALLBACK (sort_by_mtime_toggled_cb), impl);
+
+      g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_ascending_item,
+               G_CALLBACK (sort_ascending_toggled_cb), impl);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_ascending_item),
+              order == GTK_SORT_ASCENDING);
+      g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_ascending_item,
+                 G_CALLBACK (sort_ascending_toggled_cb), impl);
+
+      g_signal_handlers_block_by_func (impl->browse_files_popup_menu_sort_descending_item,
+               G_CALLBACK (sort_descending_toggled_cb), impl);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (impl->browse_files_popup_menu_sort_descending_item),
+              order == GTK_SORT_DESCENDING);
+      g_signal_handlers_unblock_by_func (impl->browse_files_popup_menu_sort_descending_item,
+                 G_CALLBACK (sort_descending_toggled_cb), impl);
+    }
+  else
+    g_assert_not_reached ();
 }
 
 static void
@@ -4141,7 +4485,7 @@ file_list_popup_menu (GtkFileChooserDefault *impl,
     {
       gtk_menu_popup (GTK_MENU (impl->browse_files_popup_menu),
 		      NULL, NULL,
-		      popup_position_func, impl->browse_files_tree_view,
+			  popup_position_func, impl->browse_files_current_view,
 		      0, GDK_CURRENT_TIME);
       gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_files_popup_menu),
 				   FALSE);
@@ -4175,28 +4519,25 @@ list_button_press_event_cb (GtkWidget             *widget,
     return FALSE;
 
   in_press = TRUE;
-  gtk_widget_event (impl->browse_files_tree_view, (GdkEvent *) event);
+  gtk_widget_event (widget, (GdkEvent *) event);
   in_press = FALSE;
 
   file_list_popup_menu (impl, event);
   return TRUE;
 }
 
-typedef struct {
-  OperationMode operation_mode;
-  gint general_column;
-  gint model_column;
-} ColumnMap;
-
 /* Sets the sort column IDs for the file list; needs to be done whenever we
  * change the model on the treeview.
  */
 static void
 file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
 {
-  gtk_tree_view_column_set_sort_column_id (impl->list_name_column, MODEL_COL_NAME);
-  gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, MODEL_COL_MTIME);
-  gtk_tree_view_column_set_sort_column_id (impl->list_size_column, MODEL_COL_SIZE);
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      gtk_tree_view_column_set_sort_column_id (impl->list_name_column, MODEL_COL_NAME);
+      gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, MODEL_COL_MTIME);
+      gtk_tree_view_column_set_sort_column_id (impl->list_size_column, MODEL_COL_SIZE);
+    }
 }
 
 static gboolean
@@ -4248,32 +4589,34 @@ file_list_query_tooltip_cb (GtkWidget  *widget,
 }
 
 static void
-set_icon_cell_renderer_fixed_size (GtkFileChooserDefault *impl, GtkCellRenderer *renderer)
+set_icon_cell_renderer_fixed_size (GtkFileChooserDefault *impl,
+                                   GtkCellRenderer *renderer,
+                                   ViewMode view_mode)
 {
+  int icon_size;
   gint xpad, ypad;
 
+  if (view_mode == VIEW_MODE_LIST)
+    icon_size = impl->list_view_icon_size;
+  else if (view_mode == VIEW_MODE_ICON)
+    icon_size = impl->icon_view_icon_size;
+  else
+    g_assert_not_reached ();
+
   gtk_cell_renderer_get_padding (renderer, &xpad, &ypad);
   gtk_cell_renderer_set_fixed_size (renderer, 
-                                    xpad * 2 + impl->icon_size,
-                                    ypad * 2 + impl->icon_size);
+                                    xpad * 2 + icon_size,
+                                    ypad * 2 + icon_size);
 }
 
-/* Creates the widgets for the file list */
+/* Creates the list view */
 static GtkWidget *
-create_file_list (GtkFileChooserDefault *impl)
+create_browse_files_tree_view (GtkFileChooserDefault *impl)
 {
-  GtkWidget *swin;
   GtkTreeSelection *selection;
   GtkTreeViewColumn *column;
   GtkCellRenderer *renderer;
 
-  /* Scrolled window */
-  swin = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
-				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
-				       GTK_SHADOW_IN);
-
   /* Tree/list view */
 
   impl->browse_files_tree_view = gtk_tree_view_new ();
@@ -4284,7 +4627,6 @@ create_file_list (GtkFileChooserDefault *impl)
   atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files"));
 
   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE);
-  gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
 
   gtk_drag_dest_set (impl->browse_files_tree_view,
                      GTK_DEST_DEFAULT_ALL,
@@ -4336,7 +4678,7 @@ create_file_list (GtkFileChooserDefault *impl)
 
   renderer = gtk_cell_renderer_pixbuf_new ();
   /* We set a fixed size so that we get an empty slot even if no icons are loaded yet */
-  set_icon_cell_renderer_fixed_size (impl, renderer);
+  set_icon_cell_renderer_fixed_size (impl, renderer, VIEW_MODE_LIST);
   gtk_tree_view_column_pack_start (impl->list_name_column, renderer, FALSE);
 
   impl->list_name_renderer = gtk_cell_renderer_text_new ();
@@ -4379,6 +4721,101 @@ create_file_list (GtkFileChooserDefault *impl)
   file_list_set_sort_column_ids (impl);
   update_cell_renderer_attributes (impl);
 
+  return impl->browse_files_tree_view;
+}
+
+/* Creates icon view (alternative for the list view) */
+static GtkWidget *
+create_browse_files_icon_view (GtkFileChooserDefault *impl)
+{
+  impl->browse_files_icon_view = gtk_icon_view_new ();
+
+  g_object_set_data (G_OBJECT (impl->browse_files_icon_view), I_("GtkFileChooserDefault"), impl);
+  gtk_icon_view_set_item_padding (GTK_ICON_VIEW (impl->browse_files_icon_view), 0);
+
+  g_signal_connect (impl->browse_files_icon_view, "item-activated",
+                    G_CALLBACK (icon_item_activated), impl);
+  g_signal_connect (impl->browse_files_icon_view, "key-press-event",
+                    G_CALLBACK (browse_files_key_press_event_cb), impl);
+  g_signal_connect (impl->browse_files_icon_view, "selection-changed",
+                    G_CALLBACK (list_selection_changed), impl);
+  g_signal_connect (impl->browse_files_icon_view, "popup-menu",
+                    G_CALLBACK (list_popup_menu_cb), impl);
+  g_signal_connect (impl->browse_files_icon_view, "button-press-event",
+                    G_CALLBACK (list_button_press_event_cb), impl);
+
+  gtk_drag_dest_set (impl->browse_files_icon_view,
+                     GTK_DEST_DEFAULT_ALL,
+                     NULL, 0,
+                     GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  gtk_drag_dest_add_uri_targets (impl->browse_files_icon_view);
+  g_signal_connect (impl->browse_files_icon_view, "drag-data-received",
+                    G_CALLBACK (file_list_drag_data_received_cb), impl);
+  g_signal_connect (impl->browse_files_icon_view, "drag-drop",
+                    G_CALLBACK (file_list_drag_drop_cb), impl);
+  g_signal_connect (impl->browse_files_icon_view, "drag-motion",
+                    G_CALLBACK (file_list_drag_motion_cb), impl);
+  gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (impl->browse_files_icon_view),
+                                          GDK_BUTTON1_MASK,
+                                          NULL, 0,
+                                          GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  gtk_drag_source_add_uri_targets (impl->browse_files_icon_view);
+
+  impl->list_icon_renderer = gtk_cell_renderer_pixbuf_new ();
+  g_object_set (G_OBJECT (impl->list_icon_renderer),
+                "ypad", 3u,
+                NULL);
+
+  set_icon_cell_renderer_fixed_size (impl, GTK_CELL_RENDERER (impl->list_icon_renderer),
+                                     VIEW_MODE_ICON);
+
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (impl->browse_files_icon_view),
+                              impl->list_icon_renderer, TRUE);
+  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (impl->browse_files_icon_view),
+                                 impl->list_icon_renderer, "pixbuf", MODEL_COL_ICON_PIXBUF);
+
+  impl->list_name_renderer = gtk_cell_renderer_text_new ();
+  g_object_set (G_OBJECT (impl->list_name_renderer),
+                "alignment", PANGO_ALIGN_CENTER,
+                "wrap-mode", PANGO_WRAP_WORD_CHAR,
+                "wrap-width", ICON_VIEW_ITEM_WIDTH - 6,
+                "yalign", 0.0f,
+                NULL);
+  gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (impl->list_name_renderer), ICON_VIEW_ITEM_WIDTH, -1);
+
+  g_signal_connect (impl->list_name_renderer, "edited",
+                    G_CALLBACK (renderer_edited_cb), impl);
+  g_signal_connect (impl->list_name_renderer, "editing-started",
+                    G_CALLBACK (renderer_editing_started_cb), impl);
+  g_signal_connect (impl->list_name_renderer, "editing-canceled",
+                    G_CALLBACK (renderer_editing_canceled_cb), impl);
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (impl->browse_files_icon_view),
+                              impl->list_name_renderer, TRUE);
+  gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (impl->browse_files_icon_view),
+                                 impl->list_name_renderer, "text", MODEL_COL_NAME);
+
+  return impl->browse_files_icon_view;
+}
+
+/* Creates the widgets for the file list */
+static GtkWidget *
+create_file_list (GtkFileChooserDefault *impl)
+{
+  GtkWidget *swin;
+
+  /* Scrolled window */
+  swin = gtk_scrolled_window_new (NULL, NULL);
+  impl->browse_files_scrolled_window = swin;
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
+				       GTK_SHADOW_IN);
+
+  /* Initially VIEW_MODE_LIST is used, settings_load may change this later. */
+  create_browse_files_tree_view (impl);
+  impl->browse_files_current_view = impl->browse_files_tree_view;
+  gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
+
   gtk_widget_show_all (swin);
 
   return swin;
@@ -4601,7 +5038,7 @@ location_mode_set (GtkFileChooserDefault *impl,
 	  location_switch_to_path_bar (impl);
 
 	  if (switch_to_file_list)
-	    gtk_widget_grab_focus (impl->browse_files_tree_view);
+	    gtk_widget_grab_focus (impl->browse_files_current_view);
 
 	  break;
 
@@ -4661,6 +5098,108 @@ location_toggle_popup_handler (GtkFileChooserDefault *impl)
     }
 }
 
+static void
+view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode)
+{
+  GtkWidget *old_view = NULL;
+  ViewMode old_view_mode = impl->view_mode;
+
+  if (old_view_mode == view_mode)
+    return;
+
+  impl->view_mode = view_mode;
+  gtk_combo_box_set_active (GTK_COMBO_BOX (impl->view_mode_combo_box),
+                            view_mode);
+
+  /* Creating the target view */
+  if (view_mode == VIEW_MODE_ICON)
+    {
+      create_browse_files_icon_view (impl);
+      impl->browse_files_current_view = impl->browse_files_icon_view;
+      old_view = impl->browse_files_tree_view;
+    }
+  else if (view_mode == VIEW_MODE_LIST)
+    {
+      create_browse_files_tree_view (impl);
+      impl->browse_files_current_view = impl->browse_files_tree_view;
+      old_view = impl->browse_files_icon_view;
+    }
+  else
+    g_assert_not_reached ();
+
+  /* Set model and selection */
+  current_view_set_file_model (impl, impl->current_model);
+  current_view_set_select_multiple (impl, impl->select_multiple);
+  copy_old_selection_to_current_view (impl, old_view_mode);
+
+  /* Destroy the old view */
+  if (view_mode == VIEW_MODE_ICON)
+    {
+      impl->browse_files_tree_view = NULL;
+      impl->list_name_column = NULL;
+      impl->list_mtime_column = NULL;
+      impl->list_size_column = NULL;
+      gtk_widget_show (impl->icon_view_scale_hbox);
+    }
+  else if (view_mode == VIEW_MODE_LIST)
+    {
+      impl->browse_files_icon_view = NULL;
+      gtk_widget_hide (impl->icon_view_scale_hbox);
+    }
+  else
+    g_assert_not_reached ();
+
+  if (impl->browse_files_popup_menu)
+    gtk_menu_detach (GTK_MENU (impl->browse_files_popup_menu));
+
+  gtk_widget_destroy (old_view);
+
+  /* Display the new view */
+  gtk_container_add (GTK_CONTAINER (impl->browse_files_scrolled_window),
+                                    impl->browse_files_current_view);
+  gtk_widget_show (impl->browse_files_current_view);
+
+  browse_files_center_selected_row (impl);
+}
+
+/* Callback used when view mode combo box active item is changed */
+static void
+view_mode_combo_box_changed_cb (GtkComboBox *combo,
+                                GtkFileChooserDefault *impl)
+{
+  ViewMode target = gtk_combo_box_get_active (combo);
+
+  view_mode_set (impl, target);
+}
+
+/* Callback used when the icon view scale is changed */
+static void
+icon_view_scale_value_changed_cb (GtkRange *range,
+                                  GtkFileChooserDefault *impl)
+{
+  gdouble value = gtk_range_get_value (range);
+  value = round (value / 16) * 16;
+
+  if (impl->icon_view_icon_size == (gint)value)
+    return;
+
+  impl->icon_view_icon_size = (gint)value;
+
+  if (impl->view_mode != VIEW_MODE_ICON)
+    return;
+
+  set_icon_cell_renderer_fixed_size (impl, impl->list_icon_renderer, VIEW_MODE_ICON);
+
+  if (impl->browse_files_model)
+    _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_ICON_PIXBUF);
+  if (impl->search_model)
+    _gtk_file_system_model_clear_cache (impl->search_model, MODEL_COL_ICON_PIXBUF);
+  if (impl->recent_model)
+    _gtk_file_system_model_clear_cache (impl->recent_model, MODEL_COL_ICON_PIXBUF);
+
+  gtk_widget_queue_resize (impl->browse_files_current_view);
+}
+
 /* Callback used when one of the location mode buttons is toggled */
 static void
 location_button_toggled_cb (GtkToggleButton *toggle,
@@ -4685,6 +5224,53 @@ location_button_toggled_cb (GtkToggleButton *toggle,
   location_mode_set (impl, new_mode, FALSE);
 }
 
+/* Creates a combo box with two items: List View and Icon View. */
+static void
+view_mode_combo_box_create (GtkFileChooserDefault *impl)
+{
+  impl->view_mode_combo_box = gtk_combo_box_text_new ();
+  gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(impl->view_mode_combo_box),
+                                  _("List View")); /* VIEW_MODE_LIST */
+  gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(impl->view_mode_combo_box),
+                                  _("Icon View")); /* VIEW_MODE_ICON */
+  gtk_combo_box_set_active (GTK_COMBO_BOX(impl->view_mode_combo_box),
+                            VIEW_MODE_LIST);
+
+  g_signal_connect (impl->view_mode_combo_box, "changed",
+                    G_CALLBACK (view_mode_combo_box_changed_cb), impl);
+}
+
+/* Creates a hscale for the icon view. */
+static void
+icon_view_scale_create (GtkFileChooserDefault *impl)
+{
+  GtkObject *adj;
+
+  impl->icon_view_scale_hbox = gtk_hbox_new (FALSE, 12);
+
+  impl->icon_view_scale_zoom_out_icon = gtk_image_new_from_stock (GTK_STOCK_ZOOM_OUT, GTK_ICON_SIZE_BUTTON);
+  gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->icon_view_scale_zoom_out_icon);
+  gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale_zoom_out_icon, FALSE, FALSE, 0);
+  gtk_widget_show (impl->icon_view_scale_zoom_out_icon);
+
+  adj = gtk_adjustment_new (32, 32, 256, 16, 16, 0);
+  impl->icon_view_scale = gtk_hscale_new (GTK_ADJUSTMENT (adj));
+  gtk_scale_set_draw_value (GTK_SCALE (impl->icon_view_scale), FALSE);
+  gtk_widget_set_size_request (impl->icon_view_scale, 100, -1);
+  gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale, FALSE, FALSE, 0);
+  gtk_widget_show (impl->icon_view_scale);
+
+  impl->icon_view_scale_zoom_in_icon = gtk_image_new_from_stock (GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_BUTTON);
+  gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->icon_view_scale_zoom_in_icon);
+  gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale_zoom_in_icon, FALSE, FALSE, 0);
+  gtk_widget_show (impl->icon_view_scale_zoom_in_icon);
+
+  g_signal_connect (impl->icon_view_scale, "value-changed",
+                    G_CALLBACK (icon_view_scale_value_changed_cb), impl);
+
+}
+
+
 /* Creates a toggle button for the location entry. */
 static void
 location_button_create (GtkFileChooserDefault *impl)
@@ -4804,6 +5390,10 @@ path_bar_widgets_create (GtkFileChooserDefault *impl)
   impl->browse_path_bar_size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
   gtk_size_group_set_ignore_hidden (impl->browse_path_bar_size_group, FALSE);
 
+  /* View mode combo box */
+  view_mode_combo_box_create (impl);
+  gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->view_mode_combo_box, FALSE, FALSE, 0);
+
   /* Location button */
   location_button_create (impl);
   gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->location_button);
@@ -4825,6 +5415,10 @@ path_bar_widgets_create (GtkFileChooserDefault *impl)
   /* Widgets for special modes (recently-used in Open mode, Search mode) */
   special_mode_widgets_create (impl);
 
+  /* Icon view scale */
+  icon_view_scale_create (impl);
+  gtk_box_pack_end (GTK_BOX (impl->browse_path_bar_hbox), impl->icon_view_scale_hbox, FALSE, FALSE, 0);
+
   /* Create Folder */
   impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
   g_signal_connect (impl->browse_new_folder_button, "clicked",
@@ -5067,18 +5661,10 @@ set_select_multiple (GtkFileChooserDefault *impl,
 		     gboolean               select_multiple,
 		     gboolean               property_notify)
 {
-  GtkTreeSelection *selection;
-  GtkSelectionMode mode;
-
   if (select_multiple == impl->select_multiple)
     return;
 
-  mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  gtk_tree_selection_set_mode (selection, mode);
-
-  gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (impl->browse_files_tree_view), select_multiple);
+  current_view_set_select_multiple (impl, select_multiple);
 
   impl->select_multiple = select_multiple;
   g_object_notify (G_OBJECT (impl), "select-multiple");
@@ -5186,27 +5772,27 @@ path_bar_update (GtkFileChooserDefault *impl)
       break;
 
     case OPERATION_MODE_RECENT:
-      if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
-	{
-	  GtkTreeSelection *selection;
-	  gboolean have_selected;
-	  GtkTreeIter iter;
+      if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE && impl->view_mode == VIEW_MODE_LIST)
+        {
+          GtkTreeSelection *selection;
+          gboolean have_selected;
+          GtkTreeIter iter;
 
-	  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+          selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
 
-	  /* Save mode means single-selection mode, so the following is valid */
-	  have_selected = gtk_tree_selection_get_selected (selection, NULL, &iter);
+          /* Save mode means single-selection mode, so the following is valid */
+          have_selected = gtk_tree_selection_get_selected (selection, NULL, &iter);
 
-	  if (have_selected)
-	    {
-	      mode = PATH_BAR_FOLDER_PATH;
-	      put_recent_folder_in_pathbar (impl, &iter);
-	    }
-	  else
-	    mode = PATH_BAR_SELECT_A_FOLDER;
-	}
+          if (have_selected)
+            {
+              mode = PATH_BAR_FOLDER_PATH;
+              put_recent_folder_in_pathbar (impl, &iter);
+            }
+          else
+            mode = PATH_BAR_SELECT_A_FOLDER;
+        }
       else
-	mode = PATH_BAR_RECENTLY_USED;
+        mode = PATH_BAR_RECENTLY_USED;
 
       break;
 
@@ -5396,6 +5982,12 @@ update_appearance (GtkFileChooserDefault *impl)
       location_mode_set (impl, impl->location_mode, TRUE);
     }
 
+  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+      impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+    gtk_widget_show (impl->view_mode_combo_box);
+  else
+    gtk_widget_hide (impl->view_mode_combo_box);
+
   if (impl->location_entry)
     _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
 
@@ -5405,7 +5997,7 @@ update_appearance (GtkFileChooserDefault *impl)
   /* This *is* needed; we need to redraw the file list because the "sensitivity"
    * of files may change depending whether we are in a file or folder-only mode.
    */
-  gtk_widget_queue_draw (impl->browse_files_tree_view);
+  gtk_widget_queue_draw (impl->browse_files_current_view);
 
   emit_default_size_changed (impl);
 }
@@ -5787,20 +6379,36 @@ change_icon_theme (GtkFileChooserDefault *impl)
   settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
 
   if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
-    impl->icon_size = MAX (width, height);
+    impl->list_view_icon_size = MAX (width, height);
   else
-    impl->icon_size = FALLBACK_ICON_SIZE;
+    impl->list_view_icon_size = FALLBACK_LIST_VIEW_ICON_SIZE;
 
   shortcuts_reload_icons (impl);
   /* the first cell in the first column is the icon column, and we have a fixed size there */
-  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (
-        gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 0)));
-  renderer = GTK_CELL_RENDERER (cells->data);
-  set_icon_cell_renderer_fixed_size (impl, renderer);
-  g_list_free (cells);
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (
+            gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 0)));
+      renderer = GTK_CELL_RENDERER (cells->data);
+      set_icon_cell_renderer_fixed_size (impl, renderer, VIEW_MODE_LIST);
+      g_list_free (cells);
+    }
   if (impl->browse_files_model)
-    _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_PIXBUF);
-  gtk_widget_queue_resize (impl->browse_files_tree_view);
+    {
+      _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_LIST_PIXBUF);
+      _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_ICON_PIXBUF);
+    }
+ if (impl->search_model)
+    {
+      _gtk_file_system_model_clear_cache (impl->search_model, MODEL_COL_LIST_PIXBUF);
+      _gtk_file_system_model_clear_cache (impl->search_model, MODEL_COL_ICON_PIXBUF);
+    }
+ if (impl->recent_model)
+    {
+      _gtk_file_system_model_clear_cache (impl->recent_model, MODEL_COL_LIST_PIXBUF);
+      _gtk_file_system_model_clear_cache (impl->recent_model, MODEL_COL_ICON_PIXBUF);
+    }
+  gtk_widget_queue_resize (impl->browse_files_current_view);
 
   profile_end ("end", NULL);
 }
@@ -5900,7 +6508,7 @@ set_sort_column (GtkFileChooserDefault *impl)
 {
   GtkTreeSortable *sortable;
 
-  sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)));
+  sortable = GTK_TREE_SORTABLE (impl->current_model);
   /* can happen when we're still populating the model */
   if (sortable == NULL)
     return;
@@ -5915,15 +6523,18 @@ settings_load (GtkFileChooserDefault *impl)
 {
   GtkFileChooserSettings *settings;
   LocationMode location_mode;
+  ViewMode view_mode;
   gboolean show_hidden;
   gboolean show_size_column;
-  gint sort_column;
+  gint sort_column, icon_view_scale;
   GtkSortType sort_order;
   StartupMode startup_mode;
 
   settings = _gtk_file_chooser_settings_new ();
 
   location_mode = _gtk_file_chooser_settings_get_location_mode (settings);
+  view_mode = _gtk_file_chooser_settings_get_view_mode (settings);
+  icon_view_scale = _gtk_file_chooser_settings_get_icon_view_scale (settings);
   show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings);
   show_size_column = _gtk_file_chooser_settings_get_show_size_column (settings);
   sort_column = _gtk_file_chooser_settings_get_sort_column (settings);
@@ -5933,11 +6544,16 @@ settings_load (GtkFileChooserDefault *impl)
   g_object_unref (settings);
 
   location_mode_set (impl, location_mode, TRUE);
+  view_mode_set (impl, view_mode);
+
+  gtk_range_set_value (GTK_RANGE (impl->icon_view_scale), icon_view_scale);
+  impl->icon_view_icon_size = icon_view_scale;
 
   gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
 
   impl->show_size_column = show_size_column;
-  gtk_tree_view_column_set_visible (impl->list_size_column, show_size_column);
+  if (impl->list_size_column)
+    gtk_tree_view_column_set_visible (impl->list_size_column, show_size_column);
 
   impl->sort_column = sort_column;
   impl->sort_order = sort_order;
@@ -5976,6 +6592,8 @@ settings_save (GtkFileChooserDefault *impl)
   /* All the other state */
 
   _gtk_file_chooser_settings_set_location_mode (settings, impl->location_mode);
+  _gtk_file_chooser_settings_set_view_mode (settings, impl->view_mode);
+  _gtk_file_chooser_settings_set_icon_view_scale (settings, impl->icon_view_icon_size);
   _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl)));
   _gtk_file_chooser_settings_set_show_size_column (settings, impl->show_size_column);
   _gtk_file_chooser_settings_set_sort_column (settings, impl->sort_column);
@@ -6213,12 +6831,16 @@ load_set_model (GtkFileChooserDefault *impl)
   g_assert (impl->browse_files_model != NULL);
 
   profile_msg ("    gtk_tree_view_set_model start", NULL);
-  gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
-			   GTK_TREE_MODEL (impl->browse_files_model));
-  gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
-				   MODEL_COL_NAME);
-  file_list_set_sort_column_ids (impl);
+  current_view_set_file_model (impl, GTK_TREE_MODEL (impl->browse_files_model));
+
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                                      MODEL_COL_NAME);
+      file_list_set_sort_column_ids (impl);
+    }
+
   set_sort_column (impl);
   profile_msg ("    gtk_tree_view_set_model end", NULL);
   impl->list_sort_ascending = TRUE;
@@ -6290,7 +6912,7 @@ browse_files_select_first_row (GtkFileChooserDefault *impl)
   GtkTreeIter dummy_iter;
   GtkTreeModel *tree_model;
 
-  tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
+  tree_model = impl->current_model;
 
   if (!tree_model)
     return;
@@ -6299,7 +6921,7 @@ browse_files_select_first_row (GtkFileChooserDefault *impl)
 
   /* If the list is empty, do nothing. */
   if (gtk_tree_model_get_iter (tree_model, &dummy_iter, path))
-      gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
+	  current_view_set_cursor (impl, path);
 
   gtk_tree_path_free (path);
 }
@@ -6310,7 +6932,7 @@ struct center_selected_row_closure {
 };
 
 /* Callback used from gtk_tree_selection_selected_foreach(); centers the
- * selected row in the tree view.
+ * selected row in the current view.
  */
 static void
 center_selected_row_foreach_cb (GtkTreeModel      *model,
@@ -6324,7 +6946,13 @@ center_selected_row_foreach_cb (GtkTreeModel      *model,
   if (closure->already_centered)
     return;
 
-  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0);
+  if (closure->impl->view_mode == VIEW_MODE_LIST)
+    gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0);
+  else if (closure->impl->view_mode == VIEW_MODE_ICON)
+    gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (closure->impl->browse_files_icon_view), path, TRUE, 0.5, 0.0);
+  else
+    g_assert_not_reached ();
+
   closure->already_centered = TRUE;
 }
 
@@ -6333,20 +6961,17 @@ static void
 browse_files_center_selected_row (GtkFileChooserDefault *impl)
 {
   struct center_selected_row_closure closure;
-  GtkTreeSelection *selection;
 
   closure.impl = impl;
   closure.already_centered = FALSE;
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
+  current_selection_selected_foreach(impl, center_selected_row_foreach_cb, &closure);
 }
 
 static gboolean
 show_and_select_files (GtkFileChooserDefault *impl,
 		       GSList                *files)
 {
-  GtkTreeSelection *selection;
   GtkFileSystemModel *fsmodel;
   gboolean enabled_hidden, removed_filters;
   gboolean selected_a_file;
@@ -6355,8 +6980,7 @@ show_and_select_files (GtkFileChooserDefault *impl,
   g_assert (impl->load_state == LOAD_FINISHED);
   g_assert (impl->browse_files_model != NULL);
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  fsmodel = GTK_FILE_SYSTEM_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)));
+  fsmodel = GTK_FILE_SYSTEM_MODEL (impl->current_model);
 
   g_assert (fsmodel == impl->browse_files_model);
 
@@ -6412,11 +7036,10 @@ show_and_select_files (GtkFileChooserDefault *impl,
         {
           GtkTreePath *path;
 
-          gtk_tree_selection_select_iter (selection, &iter);
+          current_selection_select_iter (impl, &iter);
 
           path = gtk_tree_model_get_path (GTK_TREE_MODEL (fsmodel), &iter);
-          gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view),
-                                    path, NULL, FALSE);
+          current_view_set_cursor (impl, path);
           gtk_tree_path_free (path);
 
           selected_a_file = TRUE;
@@ -6452,7 +7075,7 @@ pending_select_files_process (GtkFileChooserDefault *impl)
        */
       if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN &&
           gtk_widget_get_mapped (GTK_WIDGET (impl)))
-	browse_files_select_first_row (impl);
+         browse_files_select_first_row (impl);
     }
 
   g_assert (impl->pending_select_files == NULL);
@@ -6531,12 +7154,14 @@ stop_loading_and_clear_list_model (GtkFileChooserDefault *impl,
   
   if (impl->browse_files_model)
     {
+      if (impl->current_model == GTK_TREE_MODEL (impl->browse_files_model))
+        impl->current_model = NULL;
       g_object_unref (impl->browse_files_model);
       impl->browse_files_model = NULL;
     }
 
   if (remove_from_treeview)
-    gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+	  current_view_set_file_model (impl, NULL);
 }
 
 static char *
@@ -6690,6 +7315,17 @@ file_system_model_got_thumbnail (GObject *object, GAsyncResult *res, gpointer da
   GDK_THREADS_LEAVE ();
 }
 
+static gboolean
+get_visible_range (GtkTreePath **start, GtkTreePath **end,
+                   GtkFileChooserDefault *impl)
+{
+  if (impl->view_mode == VIEW_MODE_LIST)
+    return gtk_tree_view_get_visible_range (GTK_TREE_VIEW (impl->browse_files_tree_view), start, end);
+  if (impl->view_mode == VIEW_MODE_ICON)
+    return gtk_icon_view_get_visible_range (GTK_ICON_VIEW (impl->browse_files_icon_view), start, end);
+  g_assert_not_reached ();
+}
+
 static gboolean
 file_system_model_set (GtkFileSystemModel *model,
                        GFile              *file,
@@ -6747,38 +7383,59 @@ file_system_model_set (GtkFileSystemModel *model,
       else
         g_value_set_boolean (value, TRUE);
       break;
-    case MODEL_COL_PIXBUF:
+    case MODEL_COL_LIST_PIXBUF:
+    case MODEL_COL_ICON_PIXBUF:
       if (info)
         {
+          GtkTreeModel *tree_model;
+          GtkTreePath *path, *start, *end;
+          GtkTreeIter iter;
+          gboolean file_visible;
+
+          /* not loading icon view's icon in the list view */
+          if (column == MODEL_COL_ICON_PIXBUF && impl->view_mode == VIEW_MODE_LIST)
+            return FALSE;
+
+          tree_model = impl->current_model;
+          if (tree_model != GTK_TREE_MODEL (model))
+            return FALSE;
+
+          /* #1 use standard icon if it is loaded */
           if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_ICON))
             {
-              g_value_take_object (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), impl->icon_size));
+              gint icon_size;
+
+              if (column == MODEL_COL_ICON_PIXBUF)
+                icon_size = impl->icon_view_icon_size;
+              else
+                icon_size = impl->list_view_icon_size;
+
+              g_value_take_object (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), icon_size));
+              return TRUE;
             }
-          else
-            {
-              GtkTreeModel *tree_model;
-              GtkTreePath *path, *start, *end;
-              GtkTreeIter iter;
 
-              if (impl->browse_files_tree_view == NULL ||
-                  g_file_info_has_attribute (info, "filechooser::queried"))
-                return FALSE;
+          if (!get_visible_range (&start, &end, impl))
+            return FALSE;
 
-              tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
-              if (tree_model != GTK_TREE_MODEL (model))
-                return FALSE;
+          if (!_gtk_file_system_model_get_iter_for_file (model,
+                                                         &iter,
+                                                         file))
+            g_assert_not_reached ();
 
-              if (!_gtk_file_system_model_get_iter_for_file (model,
-                                                             &iter,
-                                                             file))
-                g_assert_not_reached ();
-              if (!gtk_tree_view_get_visible_range (GTK_TREE_VIEW (impl->browse_files_tree_view), &start, &end))
-                return FALSE;
-              path = gtk_tree_model_get_path (tree_model, &iter);
-              if (gtk_tree_path_compare (start, path) != 1 &&
-                  gtk_tree_path_compare (path, end) != 1)
+          path = gtk_tree_model_get_path (tree_model, &iter);
+          file_visible = (gtk_tree_path_compare (start, path) != 1 &&
+                          gtk_tree_path_compare (path, end) != 1);
+
+          gtk_tree_path_free (path);
+          gtk_tree_path_free (start);
+          gtk_tree_path_free (end);
+
+          if (file_visible)
+            {
+              /* #2 start loading standard icon (callback will be handled by #1) */
+              if (!g_file_info_has_attribute (info, "filechooser::icon_queried"))
                 {
-                  g_file_info_set_attribute_boolean (info, "filechooser::queried", TRUE);
+                  g_file_info_set_attribute_boolean (info, "filechooser::icon_queried", TRUE);
                   g_file_query_info_async (file,
                                            G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
                                            G_FILE_ATTRIBUTE_THUMBNAILING_FAILED ","
@@ -6789,14 +7446,23 @@ file_system_model_set (GtkFileSystemModel *model,
                                            file_system_model_got_thumbnail,
                                            model);
                 }
-              gtk_tree_path_free (path);
-              gtk_tree_path_free (start);
-              gtk_tree_path_free (end);
-              return FALSE;
             }
+          return FALSE;
         }
       else
-        g_value_set_object (value, NULL);
+        {
+          if (column == MODEL_COL_ICON_PIXBUF)
+            {
+              g_value_take_object (value,
+                  gtk_icon_theme_load_icon (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl))),
+                    "inode-directory",
+                    impl->icon_view_icon_size,
+                    0,
+                    NULL));
+            }
+          else
+            g_value_set_object (value, NULL);
+        }
       break;
     case MODEL_COL_SIZE:
       g_value_set_int64 (value, info ? g_file_info_get_size (info) : 0);
@@ -6922,7 +7588,6 @@ update_chooser_entry_selected_foreach (GtkTreeModel *model,
 static void
 update_chooser_entry (GtkFileChooserDefault *impl)
 {
-  GtkTreeSelection *selection;
   struct update_chooser_entry_selected_foreach_closure closure;
 
   /* no need to update the file chooser's entry if there's no entry */
@@ -6939,9 +7604,8 @@ update_chooser_entry (GtkFileChooserDefault *impl)
 
   g_assert (impl->location_entry != NULL);
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
   closure.num_selected = 0;
-  gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure);
+  current_selection_selected_foreach (impl, update_chooser_entry_selected_foreach, &closure);
 
   if (closure.num_selected == 0)
     {
@@ -7413,7 +8077,6 @@ gtk_file_chooser_default_unselect_file (GtkFileChooser *chooser,
 					GFile          *file)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
-  GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
   GtkTreeIter iter;
 
   if (!impl->browse_files_model)
@@ -7424,8 +8087,7 @@ gtk_file_chooser_default_unselect_file (GtkFileChooser *chooser,
                                                  file))
     return;
 
-  gtk_tree_selection_unselect_iter (gtk_tree_view_get_selection (tree_view),
-                                    &iter);
+  current_selection_unselect_iter (impl, &iter);
 }
 
 static gboolean
@@ -7435,12 +8097,9 @@ maybe_select (GtkTreeModel *model,
 	      gpointer     data)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data);
-  GtkTreeSelection *selection;
   gboolean is_sensitive;
   gboolean is_folder;
   
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  
   gtk_tree_model_get (model, iter,
                       MODEL_COL_IS_FOLDER, &is_folder,
                       MODEL_COL_IS_SENSITIVE, &is_sensitive,
@@ -7449,9 +8108,9 @@ maybe_select (GtkTreeModel *model,
   if (is_sensitive &&
       ((is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ||
        (!is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)))
-    gtk_tree_selection_select_iter (selection, iter);
+    current_selection_select_iter (impl, iter);
   else
-    gtk_tree_selection_unselect_iter (selection, iter);
+    current_selection_unselect_iter (impl, iter);
     
   return FALSE;
 }
@@ -7466,8 +8125,15 @@ gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
     {
       GtkTreeSelection *selection;
       
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-      gtk_tree_selection_select_all (selection);
+      if (impl->view_mode == VIEW_MODE_LIST)
+        {
+          selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+          gtk_tree_selection_select_all (selection);
+        }
+      else if (impl->view_mode == VIEW_MODE_ICON)
+        gtk_icon_view_select_all (GTK_ICON_VIEW (impl->browse_files_icon_view));
+      else
+        g_assert_not_reached ();
       return;
     }
 
@@ -7480,9 +8146,8 @@ static void
 gtk_file_chooser_default_unselect_all (GtkFileChooser *chooser)
 {
   GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
-  GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
 
-  gtk_tree_selection_unselect_all (selection);
+  current_selection_unselect_all (impl);
   pending_select_files_free (impl);
 }
 
@@ -7635,15 +8300,13 @@ gtk_file_chooser_default_get_files (GtkFileChooser *chooser)
     current_focus = NULL;
 
   file_list_seen = FALSE;
-  if (current_focus == impl->browse_files_tree_view)
+  if (current_focus == impl->browse_files_current_view)
     {
-      GtkTreeSelection *selection;
-
     file_list:
 
       file_list_seen = TRUE;
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-      gtk_tree_selection_selected_foreach (selection, get_files_foreach, &info);
+
+	  current_selection_selected_foreach (impl, get_files_foreach, &info);
 
       /* If there is no selection in the file list, we probably have this situation:
        *
@@ -7683,7 +8346,7 @@ gtk_file_chooser_default_get_files (GtkFileChooser *chooser)
       else
         return NULL;
     }
-  else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
+  else if (impl->toplevel_last_focus_widget == impl->browse_files_current_view)
     goto file_list;
   else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
     goto file_entry;
@@ -8147,7 +8810,6 @@ switch_folder_foreach_cb (GtkTreeModel      *model,
 static void
 switch_to_selected_folder (GtkFileChooserDefault *impl)
 {
-  GtkTreeSelection *selection;
   struct switch_folder_closure closure;
 
   /* We do this with foreach() rather than get_selected() as we may be in
@@ -8158,8 +8820,7 @@ switch_to_selected_folder (GtkFileChooserDefault *impl)
   closure.file = NULL;
   closure.num_selected = 0;
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  gtk_tree_selection_selected_foreach (selection, switch_folder_foreach_cb, &closure);
+  current_selection_selected_foreach (impl, switch_folder_foreach_cb, &closure);
 
   g_assert (closure.file && closure.num_selected == 1);
 
@@ -8178,14 +8839,28 @@ get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
   GFileInfo *info;
 
   g_assert (!impl->select_multiple);
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+
+  if (impl->view_mode == VIEW_MODE_LIST)
+     {
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+        {
+          *had_selection = FALSE;
+          return NULL;
+        }
+      *had_selection = TRUE;
+    }
+  else if (impl->view_mode == VIEW_MODE_ICON)
     {
-      *had_selection = FALSE;
-      return NULL;
+      if (!get_selected_tree_iter_from_icon_view (impl, &iter))
+        {
+          *had_selection = FALSE;
+          return NULL;
+        }
+      *had_selection = TRUE;
     }
-
-  *had_selection = TRUE;
+  else
+    g_assert_not_reached ();
 
   info = _gtk_file_system_model_get_info (impl->browse_files_model, &iter);
   return info;
@@ -8561,7 +9236,7 @@ file_exists_get_info_cb (GCancellable *cancellable,
     }
   else
     {
-      g_assert_not_reached();
+      g_assert_not_reached ();
     }
 
   if (needs_parent_check)
@@ -8667,7 +9342,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
 
   current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
 
-  if (current_focus == impl->browse_files_tree_view)
+  if (current_focus == impl->browse_files_current_view)
     {
       /* The following array encodes what we do based on the impl->action and the
        * number of files selected.
@@ -8877,7 +9552,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
 
       g_object_unref (file);
     }
-  else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
+  else if (impl->toplevel_last_focus_widget == impl->browse_files_current_view)
     {
       /* The focus is on a dialog's action area button, *and* the widget that
        * was focused immediately before it is the file list.  
@@ -8926,7 +9601,7 @@ gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
     {
       if (impl->location_mode == LOCATION_MODE_PATH_BAR
 	  || impl->operation_mode == OPERATION_MODE_RECENT)
-	widget = impl->browse_files_tree_view;
+	widget = impl->browse_files_current_view;
       else
 	widget = impl->location_entry;
     }
@@ -8964,12 +9639,10 @@ static GSList *
 search_get_selected_files (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, search_selected_foreach_get_file_cb, &result);
+  current_selection_selected_foreach (impl, search_selected_foreach_get_file_cb, &result);
   result = g_slist_reverse (result);
 
   return result;
@@ -8981,12 +9654,9 @@ search_get_selected_files (GtkFileChooserDefault *impl)
 static gboolean
 search_should_respond (GtkFileChooserDefault *impl)
 {
-  GtkTreeSelection *selection;
-
   g_assert (impl->operation_mode == OPERATION_MODE_SEARCH);
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  return (gtk_tree_selection_count_selected_rows (selection) != 0);
+  return (current_selection_count_selected_rows (impl) != 0);
 }
 
 /* Adds one hit from the search engine to the search_model */
@@ -9043,6 +9713,7 @@ search_engine_finished_cb (GtkSearchEngine *engine,
    */
   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
                            GTK_TREE_MODEL (impl->search_model));
+  current_view_set_file_model (impl, GTK_TREE_MODEL (impl->search_model));
   file_list_set_sort_column_ids (impl);
 #endif
 
@@ -9090,7 +9761,7 @@ search_clear_model (GtkFileChooserDefault *impl,
   impl->search_model = NULL;
   
   if (remove_from_treeview)
-    gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+    current_view_set_file_model (impl, NULL);
 }
 
 /* Stops any ongoing searches; does not touch the search_model */
@@ -9141,8 +9812,7 @@ search_setup_model (GtkFileChooserDefault *impl)
    * 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));
+  current_view_set_file_model (impl, GTK_TREE_MODEL (impl->search_model));
   file_list_set_sort_column_ids (impl);
 }
 
@@ -9306,7 +9976,7 @@ recent_clear_model (GtkFileChooserDefault *impl,
     return;
 
   if (remove_from_treeview)
-    gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+    current_view_set_file_model (impl, NULL);
 
   g_object_unref (impl->recent_model);
   impl->recent_model = NULL;
@@ -9363,8 +10033,7 @@ 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));
+  current_view_set_file_model (impl, GTK_TREE_MODEL (impl->recent_model));
   file_list_set_sort_column_ids (impl);
   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->recent_model), MODEL_COL_MTIME, GTK_SORT_DESCENDING);
 
@@ -9509,12 +10178,10 @@ static GSList *
 recent_get_selected_files (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_file_cb, &result);
+  current_selection_selected_foreach (impl, recent_selected_foreach_get_file_cb, &result);
   result = g_slist_reverse (result);
 
   return result;
@@ -9526,12 +10193,9 @@ recent_get_selected_files (GtkFileChooserDefault *impl)
 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);
+  return (current_selection_count_selected_rows (impl) != 0);
 }
 
 static void
@@ -9591,9 +10255,16 @@ check_preview_change (GtkFileChooserDefault *impl)
   char *new_display_name;
   GtkTreeModel *model;
 
-  gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
-  model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
-  if (cursor_path)
+  if (impl->view_mode == VIEW_MODE_LIST)
+    gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    cursor_path = NULL;
+  else
+    g_assert_not_reached ();
+
+  model = impl->current_model;
+
+  if (cursor_path && model)
     {
       GtkTreeIter iter;
 
@@ -9903,7 +10574,7 @@ shortcuts_key_press_event_cb (GtkWidget             *widget,
 
   if (key_is_left_or_right (event))
     {
-      gtk_widget_grab_focus (impl->browse_files_tree_view);
+      gtk_widget_grab_focus (impl->browse_files_current_view);
       return TRUE;
     }
 
@@ -9974,8 +10645,9 @@ list_select_func  (GtkTreeSelection  *selection,
   return TRUE;
 }
 
+/* GtkTreeSelection or GtkIconView selection changed. */
 static void
-list_selection_changed (GtkTreeSelection      *selection,
+list_selection_changed (void      *selection,
 			GtkFileChooserDefault *impl)
 {
   /* See if we are in the new folder editable row for Save mode */
@@ -10012,15 +10684,34 @@ list_row_activated (GtkTreeView           *tree_view,
 		    GtkTreePath           *path,
 		    GtkTreeViewColumn     *column,
 		    GtkFileChooserDefault *impl)
+{
+  GtkTreeModel *model;
+  model = gtk_tree_view_get_model (tree_view);
+  item_activated (model, path, impl);
+}
+
+/* Callback used when a item in the icon file list is activated. */
+static void
+icon_item_activated (GtkIconView           *icon_view,
+                     GtkTreePath           *path,
+                     GtkFileChooserDefault *impl)
+{
+  GtkTreeModel *model;
+  model = gtk_icon_view_get_model (icon_view);
+  item_activated (model, path, impl);
+}
+
+/* Common implementation for list_row_activated and icon_item_activated */
+static void
+item_activated (GtkTreeModel          *model,
+                GtkTreePath           *path,
+                GtkFileChooserDefault *impl)
 {
   GFile *file;
   GtkTreeIter iter;
-  GtkTreeModel *model;
   gboolean is_folder;
   gboolean is_sensitive;
 
-  model = gtk_tree_view_get_model (tree_view);
-
   if (!gtk_tree_model_get_iter (model, &iter, path))
     return;
 
@@ -10070,6 +10761,10 @@ update_cell_renderer_attributes (GtkFileChooserDefault *impl)
 {
   GtkTreeViewColumn *column;
   GtkCellRenderer *renderer;
+  /* only applicable in the tree view (i.e. list view) */
+  if (!impl->browse_files_tree_view)
+    return;
+
   GList *walk, *list;
 
   /* Keep the following column numbers in sync with create_file_list() */
@@ -10083,7 +10778,7 @@ update_cell_renderer_attributes (GtkFileChooserDefault *impl)
       if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
         {
           gtk_tree_view_column_set_attributes (column, renderer, 
-                                               "pixbuf", MODEL_COL_PIXBUF,
+                                               "pixbuf", MODEL_COL_LIST_PIXBUF,
                                                NULL);
         }
       else
@@ -10148,7 +10843,7 @@ location_popup_handler (GtkFileChooserDefault *impl,
         change_folder_and_display_error (impl, impl->current_folder, FALSE);
 
       if (impl->location_mode == LOCATION_MODE_PATH_BAR)
-        widget_to_focus = impl->browse_files_tree_view;
+        widget_to_focus = impl->browse_files_current_view;
       else
         widget_to_focus = impl->location_entry;
 
@@ -10350,3 +11045,241 @@ shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
   return GTK_TREE_MODEL (model);
 }
 
+static gboolean
+get_selected_tree_iter_from_icon_view (GtkFileChooserDefault *impl,
+                                       GtkTreeIter           *iter_out)
+{
+  GList *icon_selection;
+  GtkTreePath *icon_selection_path;
+
+  icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (impl->browse_files_icon_view));
+  if (!icon_selection)
+    return FALSE;
+
+  icon_selection_path = g_list_nth_data (icon_selection, 0);
+  gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->current_model),
+                           iter_out,
+                           icon_selection_path);
+
+  g_list_foreach (icon_selection, (GFunc) gtk_tree_path_free, NULL);
+  g_list_free (icon_selection);
+  return TRUE;
+}
+
+static void
+icon_view_selection_selected_foreach (GtkFileChooserDefault       *impl,
+                                      GtkTreeSelectionForeachFunc func,
+                                      gpointer                    data)
+{
+  GtkTreeIter iter;
+  GList *icon_selection;
+  GList *elem;
+  GtkTreePath *icon_selection_path;
+
+  icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (impl->browse_files_icon_view));
+  for (elem = icon_selection; elem; elem = elem->next)
+    {
+      icon_selection_path = elem->data;
+      gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->current_model),
+                               &iter,
+                               icon_selection_path);
+      (* func) (GTK_TREE_MODEL (impl->current_model),
+                icon_selection_path,
+                &iter,
+                data);
+    }
+
+  g_list_foreach (icon_selection, (GFunc) gtk_tree_path_free, NULL);
+  g_list_free (icon_selection);
+}
+
+static void
+selection_selected_foreach (GtkFileChooserDefault       *impl,
+                            ViewMode                    view,
+                            GtkTreeSelectionForeachFunc func,
+                            gpointer                    data)
+{
+  if (impl->current_model == NULL)
+    return;
+
+  if (view == VIEW_MODE_LIST)
+    {
+      GtkTreeSelection *selection;
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_selection_selected_foreach (selection, func, data);
+    }
+  else if (view == VIEW_MODE_ICON)
+    icon_view_selection_selected_foreach (impl, func, data);
+  else
+    g_assert_not_reached ();
+}
+
+static void
+current_selection_selected_foreach (GtkFileChooserDefault       *impl,
+                                    GtkTreeSelectionForeachFunc func,
+                                    gpointer                    data)
+{
+  selection_selected_foreach (impl, impl->view_mode, func, data);
+}
+
+static guint
+current_selection_count_selected_rows (GtkFileChooserDefault *impl)
+{
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      GtkTreeSelection *selection;
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      return gtk_tree_selection_count_selected_rows (selection);
+    }
+  if (impl->view_mode == VIEW_MODE_ICON)
+    {
+      GList *icon_selection;
+      icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (impl->browse_files_icon_view));
+      guint count = g_list_length (icon_selection);
+      g_list_foreach (icon_selection, (GFunc) gtk_tree_path_free, NULL);
+      g_list_free (icon_selection);
+      return count;
+    }
+  g_assert_not_reached ();
+  return 0;
+}
+
+static void
+selection_select_iter (GtkFileChooserDefault *impl,
+                       GtkTreeIter           *iter,
+                       ViewMode               target)
+{
+  if (target == VIEW_MODE_LIST)
+    {
+      GtkTreeSelection *selection;
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_selection_select_iter (selection, iter);
+    }
+  else if (target == VIEW_MODE_ICON)
+    {
+      GtkTreePath *path;
+      path = gtk_tree_model_get_path (impl->current_model, iter);
+      gtk_icon_view_select_path (GTK_ICON_VIEW (impl->browse_files_icon_view), path);
+      gtk_tree_path_free (path);
+    }
+  else
+    g_assert_not_reached ();
+}
+
+static void
+current_selection_select_iter (GtkFileChooserDefault *impl,
+                               GtkTreeIter           *iter)
+{
+  selection_select_iter (impl, iter, impl->view_mode);
+}
+
+struct copy_old_selection_to_current_view_closure {
+  GtkFileChooserDefault *impl;
+};
+
+static void
+copy_old_selection_to_current_view_foreach_cp (GtkTreeModel *model,
+                                               GtkTreePath  *path,
+                                               GtkTreeIter  *iter,
+                                               gpointer      data)
+{
+  struct copy_old_selection_to_current_view_closure *closure;
+  closure = data;
+  selection_select_iter (closure->impl, iter, closure->impl->view_mode);
+}
+
+static void
+copy_old_selection_to_current_view (GtkFileChooserDefault *impl,
+                                    ViewMode               old_view_mode)
+{
+  struct copy_old_selection_to_current_view_closure closure;
+  closure.impl = impl;
+
+  selection_selected_foreach(impl,
+                             old_view_mode,
+                             copy_old_selection_to_current_view_foreach_cp,
+                             &closure);
+}
+
+static void
+current_selection_unselect_iter (GtkFileChooserDefault *impl,
+                                 GtkTreeIter           *iter)
+{
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      GtkTreeSelection *selection;
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_selection_unselect_iter (selection, iter);
+    }
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    {
+      GtkTreePath *path;
+      path = gtk_tree_model_get_path (impl->current_model, iter);
+      gtk_icon_view_unselect_path (GTK_ICON_VIEW (impl->browse_files_icon_view), path);
+      gtk_tree_path_free (path);
+    }
+  else
+    g_assert_not_reached ();
+}
+
+static void
+current_selection_unselect_all (GtkFileChooserDefault *impl)
+{
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      GtkTreeSelection *selection;
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_selection_unselect_all (selection);
+    }
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    gtk_icon_view_unselect_all (GTK_ICON_VIEW (impl->browse_files_icon_view));
+  else
+    g_assert_not_reached ();
+}
+
+static void
+current_view_set_file_model (GtkFileChooserDefault *impl, GtkTreeModel *model)
+{
+  GtkWidget *view;
+
+  impl->current_model = model;
+
+  if (impl->view_mode == VIEW_MODE_LIST)
+    view = impl->browse_files_tree_view;
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    view = impl->browse_files_icon_view;
+  else
+    g_assert_not_reached ();
+
+  g_object_set (view, "model", impl->current_model, NULL);
+}
+
+static void
+current_view_set_cursor (GtkFileChooserDefault *impl, GtkTreePath *path)
+{
+  if (impl->view_mode == VIEW_MODE_LIST)
+    gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    gtk_icon_view_set_cursor (GTK_ICON_VIEW (impl->browse_files_icon_view), path, NULL, FALSE);
+  else
+    g_assert_not_reached ();
+}
+
+static void
+current_view_set_select_multiple (GtkFileChooserDefault *impl, gboolean select_multiple)
+{
+  GtkTreeSelection *selection;
+  GtkSelectionMode mode;
+  mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE;
+
+  if (impl->view_mode == VIEW_MODE_LIST)
+    {
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+      gtk_tree_selection_set_mode (selection, mode);
+      gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (impl->browse_files_tree_view), select_multiple);
+    }
+  else if (impl->view_mode == VIEW_MODE_ICON)
+    gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (impl->browse_files_icon_view), mode);
+  else
+    g_assert_not_reached ();
+}
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index dab74c3bdd..ba09a55364 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -33,6 +33,8 @@
 #include "gtktreestore.h"
 #include "gtktreeview.h"
 #include "gtkvbox.h"
+#include "gtkiconview.h"
+#include "gtkhscale.h"
 
 G_BEGIN_DECLS
 
@@ -135,6 +137,11 @@ typedef enum {
   LOCATION_MODE_FILENAME_ENTRY
 } LocationMode;
 
+typedef enum {
+  VIEW_MODE_LIST,
+  VIEW_MODE_ICON
+} ViewMode;
+
 typedef enum {
   OPERATION_MODE_BROWSE,
   OPERATION_MODE_SEARCH,
@@ -170,10 +177,18 @@ struct _GtkFileChooserDefault
   GtkWidget *browse_shortcuts_popup_menu_remove_item;
   GtkWidget *browse_shortcuts_popup_menu_rename_item;
   GtkWidget *browse_files_tree_view;
+  GtkWidget *browse_files_scrolled_window;
+  GtkWidget *browse_files_current_view;
+  GtkWidget *browse_files_icon_view;
   GtkWidget *browse_files_popup_menu;
   GtkWidget *browse_files_popup_menu_add_shortcut_item;
   GtkWidget *browse_files_popup_menu_hidden_files_item;
   GtkWidget *browse_files_popup_menu_size_column_item;
+  GtkWidget *browse_files_popup_menu_sort_by_name_item;
+  GtkWidget *browse_files_popup_menu_sort_by_size_item;
+  GtkWidget *browse_files_popup_menu_sort_by_mtime_item;
+  GtkWidget *browse_files_popup_menu_sort_ascending_item;
+  GtkWidget *browse_files_popup_menu_sort_descending_item;
   GtkWidget *browse_new_folder_button;
   GtkWidget *browse_path_bar_hbox;
   GtkSizeGroup *browse_path_bar_size_group;
@@ -186,6 +201,7 @@ struct _GtkFileChooserDefault
 
   gulong toplevel_unmapped_id;
 
+  GtkTreeModel *current_model;
   GtkFileSystemModel *browse_files_model;
   char *browse_files_last_selected_name;
 
@@ -211,6 +227,13 @@ struct _GtkFileChooserDefault
   GtkWidget *extra_align;
   GtkWidget *extra_widget;
 
+  GtkWidget *view_mode_combo_box;
+  GtkWidget *icon_view_scale_hbox;
+  GtkWidget *icon_view_scale;
+  GtkWidget *icon_view_scale_zoom_in_icon;
+  GtkWidget *icon_view_scale_zoom_out_icon;
+  ViewMode view_mode;
+
   GtkWidget *location_button;
   GtkWidget *location_entry_box;
   GtkWidget *location_label;
@@ -259,6 +282,7 @@ struct _GtkFileChooserDefault
 
   GtkTreeViewColumn *list_name_column;
   GtkCellRenderer *list_name_renderer;
+  GtkCellRenderer *list_icon_renderer;
   GtkTreeViewColumn *list_mtime_column;
   GtkTreeViewColumn *list_size_column;
 
@@ -266,10 +290,14 @@ struct _GtkFileChooserDefault
   char *edited_new_text;
 
   gulong settings_signal_id;
-  int icon_size;
+  int list_view_icon_size;
+  int icon_view_icon_size;
 
   GSource *focus_entry_idle;
 
+  GSource *start_editing_icon_view_idle;
+  GtkTreePath *start_editing_icon_view_path;
+
   gulong toplevel_set_focus_id;
   GtkWidget *toplevel_last_focus_widget;
 
diff --git a/gtk/gtkfilechoosersettings.c b/gtk/gtkfilechoosersettings.c
index 5b8fb87611..ce34291ef0 100644
--- a/gtk/gtkfilechoosersettings.c
+++ b/gtk/gtkfilechoosersettings.c
@@ -39,6 +39,8 @@
 
 #define SETTINGS_GROUP		"Filechooser Settings"
 #define LOCATION_MODE_KEY	"LocationMode"
+#define VIEW_MODE_KEY		  "ViewMode"
+#define ICON_VIEW_SCALE_KEY "IconViewScale"
 #define SHOW_HIDDEN_KEY		"ShowHidden"
 #define SHOW_SIZE_COLUMN_KEY    "ShowSizeColumn"
 #define GEOMETRY_X_KEY		"GeometryX"
@@ -58,8 +60,11 @@
 #define STARTUP_MODE_RECENT_STRING "recent"
 #define STARTUP_MODE_CWD_STRING    "cwd"
 
-#define MODE_PATH_BAR          "path-bar"
-#define MODE_FILENAME_ENTRY    "filename-entry"
+#define MODE_PATH_BAR			"path-bar"
+#define MODE_FILENAME_ENTRY		"filename-entry"
+
+#define MODE_LIST_VIEW			"list-view"
+#define MODE_ICON_VIEW			"icon-view"
 
 #define EQ(a, b) (g_ascii_strcasecmp ((a), (b)) == 0)
 
@@ -114,7 +119,7 @@ ensure_settings_read (GtkFileChooserSettings *settings)
 {
   GError *error;
   GKeyFile *key_file;
-  gchar *location_mode_str, *filename;
+  gchar *location_mode_str, *view_mode_str, *filename;
   gchar *sort_column, *sort_order;
   gchar *startup_mode;
   gboolean value;
@@ -159,6 +164,27 @@ ensure_settings_read (GtkFileChooserSettings *settings)
       g_free (location_mode_str);
     }
 
+  /* View mode */
+
+  view_mode_str = g_key_file_get_string (key_file, SETTINGS_GROUP,
+					     VIEW_MODE_KEY, NULL);
+  if (view_mode_str)
+    {
+      if (EQ (view_mode_str, MODE_LIST_VIEW))
+        settings->view_mode = VIEW_MODE_LIST;
+      else if (EQ (view_mode_str, MODE_ICON_VIEW))
+        settings->view_mode = VIEW_MODE_ICON;
+      else
+        g_warning ("Unknown view mode '%s' encountered in filechooser settings",
+		   view_mode_str);
+
+      g_free (view_mode_str);
+    }
+
+  /* Icon view scale */
+
+  get_int_key (key_file, SETTINGS_GROUP, ICON_VIEW_SCALE_KEY, &settings->icon_view_scale);
+
   /* Show hidden */
 
   value = g_key_file_get_boolean (key_file, SETTINGS_GROUP,
@@ -256,6 +282,8 @@ static void
 _gtk_file_chooser_settings_init (GtkFileChooserSettings *settings)
 {
   settings->location_mode = LOCATION_MODE_PATH_BAR;
+  settings->view_mode = VIEW_MODE_LIST;
+  settings->icon_view_scale = 48;
   settings->sort_order = GTK_SORT_ASCENDING;
   settings->sort_column = FILE_LIST_COL_NAME;
   settings->show_hidden = FALSE;
@@ -287,6 +315,34 @@ _gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings,
   settings->location_mode = location_mode;
 }
 
+ViewMode
+_gtk_file_chooser_settings_get_view_mode (GtkFileChooserSettings *settings)
+{
+  ensure_settings_read (settings);
+  return settings->view_mode;
+}
+
+void
+_gtk_file_chooser_settings_set_view_mode (GtkFileChooserSettings *settings,
+					      ViewMode view_mode)
+{
+  settings->view_mode = view_mode;
+}
+
+gint
+_gtk_file_chooser_settings_get_icon_view_scale (GtkFileChooserSettings *settings)
+{
+  ensure_settings_read (settings);
+  return settings->icon_view_scale;
+}
+
+void
+_gtk_file_chooser_settings_set_icon_view_scale (GtkFileChooserSettings *settings,
+					    gint icon_view_scale)
+{
+  settings->icon_view_scale = icon_view_scale;
+}
+
 gboolean
 _gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings)
 {
@@ -389,7 +445,7 @@ gboolean
 _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings,
 				 GError                **error)
 {
-  const gchar *location_mode_str;
+  const gchar *location_mode_str, *view_mode_str;
   gchar *filename;
   gchar *dirname;
   gchar *contents;
@@ -417,6 +473,16 @@ _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings,
       return FALSE;
     }
 
+  if (settings->view_mode == VIEW_MODE_LIST)
+    view_mode_str = MODE_LIST_VIEW;
+  else if (settings->view_mode == VIEW_MODE_ICON)
+    view_mode_str = MODE_ICON_VIEW;
+  else
+    {
+      g_assert_not_reached ();
+      return FALSE;
+    }
+
   switch (settings->sort_column)
     {
     case FILE_LIST_COL_NAME:
@@ -473,6 +539,10 @@ _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings,
 
   g_key_file_set_string (key_file, SETTINGS_GROUP,
 			 LOCATION_MODE_KEY, location_mode_str);
+  g_key_file_set_string (key_file, SETTINGS_GROUP,
+			 VIEW_MODE_KEY, view_mode_str);
+  g_key_file_set_integer (key_file, SETTINGS_GROUP,
+			 ICON_VIEW_SCALE_KEY, settings->icon_view_scale);
   g_key_file_set_boolean (key_file, SETTINGS_GROUP,
 			  SHOW_HIDDEN_KEY, settings->show_hidden);
   g_key_file_set_boolean (key_file, SETTINGS_GROUP,
diff --git a/gtk/gtkfilechoosersettings.h b/gtk/gtkfilechoosersettings.h
index 2283192c01..b987fca8c3 100644
--- a/gtk/gtkfilechoosersettings.h
+++ b/gtk/gtkfilechoosersettings.h
@@ -45,9 +45,10 @@ struct _GtkFileChooserSettings
   GObject object;
 
   LocationMode location_mode;
+  ViewMode view_mode;
 
   GtkSortType sort_order;
-  gint sort_column;
+  gint sort_column, icon_view_scale;
   StartupMode startup_mode;
 
   int geometry_x;
@@ -73,6 +74,14 @@ LocationMode _gtk_file_chooser_settings_get_location_mode (GtkFileChooserSetting
 void         _gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings,
 							   LocationMode            location_mode);
 
+ViewMode _gtk_file_chooser_settings_get_view_mode (GtkFileChooserSettings *settings);
+void     _gtk_file_chooser_settings_set_view_mode (GtkFileChooserSettings *settings,
+							   ViewMode            view_mode);
+
+gint _gtk_file_chooser_settings_get_icon_view_scale (GtkFileChooserSettings *settings);
+void _gtk_file_chooser_settings_set_icon_view_scale (GtkFileChooserSettings *settings,
+						 gint icon_view_scale);
+
 gboolean _gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings);
 void     _gtk_file_chooser_settings_set_show_hidden (GtkFileChooserSettings *settings,
 						     gboolean                show_hidden);
openSUSE Build Service is sponsored by