summarylogtreecommitdiffstats
path: root/gtk2-filechooser-icon-view.patch
diff options
context:
space:
mode:
authordudemanguy2018-02-16 09:15:48 -0600
committerdudemanguy2018-02-16 09:15:48 -0600
commit9d40d3a80f04b824fd25a9faed13617a1dda0fae (patch)
tree0f69709b58f4f822604475983d465572278e60e9 /gtk2-filechooser-icon-view.patch
parent8ea59bfc9478a75227cfbc99927066c5be0832cf (diff)
downloadaur-9d40d3a80f04b824fd25a9faed13617a1dda0fae.tar.gz
migrate source to gitlab and patch to package
Diffstat (limited to 'gtk2-filechooser-icon-view.patch')
-rw-r--r--gtk2-filechooser-icon-view.patch2491
1 files changed, 2491 insertions, 0 deletions
diff --git a/gtk2-filechooser-icon-view.patch b/gtk2-filechooser-icon-view.patch
new file mode 100644
index 000000000000..576769e5b107
--- /dev/null
+++ b/gtk2-filechooser-icon-view.patch
@@ -0,0 +1,2491 @@
+diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
+index fb982a3b89..5084492b93 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);
+
+- gtk_tree_path_free (path);
++ 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);
++
++ 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;
+ }
+
+@@ -3768,7 +3865,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;
+@@ -3850,6 +3947,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,
+@@ -3921,9 +4157,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)
+@@ -4027,7 +4263,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"));
+@@ -4050,12 +4286,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);
+ }
+@@ -4080,13 +4376,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
+@@ -4134,7 +4478,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);
+@@ -4168,28 +4512,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
+@@ -4241,32 +4582,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 ();
+@@ -4277,7 +4620,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,
+@@ -4329,7 +4671,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 ();
+@@ -4372,6 +4714,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;
+@@ -4594,7 +5031,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;
+
+@@ -4654,6 +5091,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,
+@@ -4678,6 +5217,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)
+@@ -4797,6 +5383,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);
+@@ -4818,6 +5408,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",
+@@ -5060,18 +5654,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");
+@@ -5179,27 +5765,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;
+
+@@ -5389,6 +5975,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);
+
+@@ -5398,7 +5990,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);
+ }
+@@ -5780,20 +6372,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);
+ }
+@@ -5893,7 +6501,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;
+@@ -5908,15 +6516,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);
+@@ -5926,11 +6537,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;
+@@ -5969,6 +6585,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);
+@@ -6206,12 +6824,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;
+@@ -6283,7 +6905,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;
+@@ -6292,7 +6914,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);
+ }
+@@ -6303,7 +6925,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,
+@@ -6317,7 +6939,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;
+ }
+
+@@ -6326,20 +6954,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;
+@@ -6348,8 +6973,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);
+
+@@ -6405,11 +7029,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;
+@@ -6445,7 +7068,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);
+@@ -6524,12 +7147,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 *
+@@ -6683,6 +7308,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,
+@@ -6740,38 +7376,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 ","
+@@ -6782,14 +7439,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);
+@@ -6915,7 +7581,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 */
+@@ -6932,9 +7597,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)
+ {
+@@ -7406,7 +8070,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)
+@@ -7417,8 +8080,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
+@@ -7428,12 +8090,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,
+@@ -7442,9 +8101,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;
+ }
+@@ -7459,8 +8118,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;
+ }
+
+@@ -7473,9 +8139,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);
+ }
+
+@@ -7628,15 +8293,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:
+ *
+@@ -7676,7 +8339,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;
+@@ -8140,7 +8803,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
+@@ -8151,8 +8813,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);
+
+@@ -8171,14 +8832,29 @@ 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;
+@@ -8554,7 +9230,7 @@ file_exists_get_info_cb (GCancellable *cancellable,
+ }
+ else
+ {
+- g_assert_not_reached();
++ g_assert_not_reached ();
+ }
+
+ if (needs_parent_check)
+@@ -8660,7 +9336,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.
+@@ -8870,7 +9546,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.
+@@ -8919,7 +9595,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;
+ }
+@@ -8957,12 +9633,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;
+@@ -8974,12 +9648,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 */
+@@ -9036,6 +9707,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
+
+@@ -9083,7 +9755,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 */
+@@ -9134,8 +9806,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);
+ }
+
+@@ -9299,7 +9970,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;
+@@ -9356,8 +10027,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);
+
+@@ -9502,12 +10172,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;
+@@ -9519,12 +10187,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
+@@ -9584,9 +10249,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;
+
+@@ -9896,7 +10568,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;
+ }
+
+@@ -9967,8 +10639,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 */
+@@ -10005,15 +10678,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;
+
+@@ -10063,6 +10755,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() */
+@@ -10076,7 +10772,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
+@@ -10141,7 +10837,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;
+
+@@ -10343,3 +11039,242 @@ 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);