From 6486386e040320e64ae7cb0e5ceddd2371578bc4 Mon Sep 17 00:00:00 2001 From: "B. Stack" Date: Sat, 25 Mar 2023 13:45:21 -0400 Subject: 3.24.27 and add filechooser-icon-view patch --- gtk-classic-build-deb.sh | 9 +- gtk3-filechooser-icon-view.patch | 2427 +++++++++++++++++++++++++++++++++ gtk3-filechooser-icon-view.patch.diff | 1055 ++++++++++++++ 3 files changed, 3490 insertions(+), 1 deletion(-) create mode 100644 gtk3-filechooser-icon-view.patch create mode 100644 gtk3-filechooser-icon-view.patch.diff diff --git a/gtk-classic-build-deb.sh b/gtk-classic-build-deb.sh index 8ecad9a..b79c904 100755 --- a/gtk-classic-build-deb.sh +++ b/gtk-classic-build-deb.sh @@ -88,9 +88,10 @@ cd "${WORKDIR}/gtk+-${raw_version}" tar -Jxf "${WORKDIR}/gtk+3.0_${deb_version}.debian.tar.xz" mv debian/changelog debian/changelog.orig { - echo "gtk+3.0 (${raw_version}-100+stackrpms) obs; urgency=medium" + echo "gtk+3.0 (${raw_version}-101+stackrpms) obs; urgency=medium" echo "" echo " * Rebuild gtk3 with gtk3-classic patches" + echo " * Add filechooser-icon-view from dudemanguy" echo "" echo " -- B. Stack $( date "+%a, %d %b %+4Y %T %z" )" echo "" @@ -100,6 +101,12 @@ rm debian.changelog cp -p "${WORKDIR}/gtk3classic/"*.patch debian/patches/ cp -p "${WORKDIR}/gtk3classic/"*.css debian/patches/ cat "${WORKDIR}/gtk3classic/series" >> debian/patches/series + +#### Fetch gtk3-filechooser-icon-view.patch +# from wget https://gist.github.com/Dudemanguy/c172394e30e1e7d0f477ad15c719bc71/raw/8f2e9fb36d736b600030a2db24a26304654f5e17/gtk3-filechooser-icon-view.patch --output-document="${WORKDIR}/gtk3classic/gtk3-filechooser-icon-view.patch" +cp -p "${WORKDIR}/gtk3-filechooser-icon-view.patch" debian/patches/ +echo "gtk3-filechooser-icon-view.patch" >> debian/patches/series + sed -i -r debian/rules \ -e 's/env -u LD_PRELOAD xvfb-run -a dh_auto_test/#env -u LD_PRELOAD xvfb-run -a dh_auto_test/' \ -e '/NOMATCHFINDABLE/s/abcdefg/# added for 3.24.34 because LD_PRELOAD statement does nothing now/;' \ diff --git a/gtk3-filechooser-icon-view.patch b/gtk3-filechooser-icon-view.patch new file mode 100644 index 0000000..52edecb --- /dev/null +++ b/gtk3-filechooser-icon-view.patch @@ -0,0 +1,2427 @@ +Last-modified: 2023-03-24 +Authors: dudemanguy, bgstack15 +Applicable-to: [gtk3-classic](https://github.com/lah7/gtk3-classic) +Message: Adapted by bgstack15 from [dudemanguy/gtk3-filechooser-icon-view.patch](https://gist.github.com/Dudemanguy/c172394e30e1e7d0f477ad15c719bc71) for after the lah7/gtk3-classic patches +Version: 3.24.37 +--- a/gtk/gtkfilechooserprivate.h ++++ b/gtk/gtkfilechooserprivate.h +@@ -32,10 +32,14 @@ + #include "gtktreestore.h" + #include "gtktreeview.h" + #include "gtkbox.h" ++#include "gtkiconview.h" ++#include "gtkscale.h" + + G_BEGIN_DECLS + + #define SETTINGS_KEY_LOCATION_MODE "location-mode" ++#define SETTINGS_KEY_VIEW_MODE "view-mode" ++#define SETTINGS_KEY_ICON_VIEW_SCALE "icon-view-scale" + #define SETTINGS_KEY_SHOW_HIDDEN "show-hidden" + #define SETTINGS_KEY_SHOW_SIZE_COLUMN "show-size-column" + #define SETTINGS_KEY_SHOW_TYPE_COLUMN "show-type-column" +@@ -60,34 +64,34 @@ struct _GtkFileChooserIface + + /* Methods + */ +- gboolean (*set_current_folder) (GtkFileChooser *chooser, +- GFile *file, +- GError **error); +- GFile * (*get_current_folder) (GtkFileChooser *chooser); +- void (*set_current_name) (GtkFileChooser *chooser, +- const gchar *name); ++ gboolean (*set_current_folder) (GtkFileChooser *chooser, ++ GFile *file, ++ GError **error); ++ GFile * (*get_current_folder) (GtkFileChooser *chooser); ++ void (*set_current_name) (GtkFileChooser *chooser, ++ const gchar *name); + gchar * (*get_current_name) (GtkFileChooser *chooser); +- gboolean (*select_file) (GtkFileChooser *chooser, +- GFile *file, +- GError **error); +- void (*unselect_file) (GtkFileChooser *chooser, +- GFile *file); +- void (*select_all) (GtkFileChooser *chooser); +- void (*unselect_all) (GtkFileChooser *chooser); +- GSList * (*get_files) (GtkFileChooser *chooser); +- GFile * (*get_preview_file) (GtkFileChooser *chooser); +- GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser); +- void (*add_filter) (GtkFileChooser *chooser, +- GtkFileFilter *filter); +- void (*remove_filter) (GtkFileChooser *chooser, +- GtkFileFilter *filter); +- GSList * (*list_filters) (GtkFileChooser *chooser); ++ gboolean (*select_file) (GtkFileChooser *chooser, ++ GFile *file, ++ GError **error); ++ void (*unselect_file) (GtkFileChooser *chooser, ++ GFile *file); ++ void (*select_all) (GtkFileChooser *chooser); ++ void (*unselect_all) (GtkFileChooser *chooser); ++ GSList * (*get_files) (GtkFileChooser *chooser); ++ GFile * (*get_preview_file) (GtkFileChooser *chooser); ++ GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser); ++ void (*add_filter) (GtkFileChooser *chooser, ++ GtkFileFilter *filter); ++ void (*remove_filter) (GtkFileChooser *chooser, ++ GtkFileFilter *filter); ++ GSList * (*list_filters) (GtkFileChooser *chooser); + gboolean (*add_shortcut_folder) (GtkFileChooser *chooser, +- GFile *file, +- GError **error); ++ GFile *file, ++ GError **error); + gboolean (*remove_shortcut_folder) (GtkFileChooser *chooser, +- GFile *file, +- GError **error); ++ GFile *file, ++ GError **error); + GSList * (*list_shortcut_folders) (GtkFileChooser *chooser); + + /* Signals +@@ -115,11 +119,11 @@ struct _GtkFileChooserIface + + GtkFileSystem *_gtk_file_chooser_get_file_system (GtkFileChooser *chooser); + gboolean _gtk_file_chooser_add_shortcut_folder (GtkFileChooser *chooser, +- GFile *folder, +- GError **error); ++ GFile *folder, ++ GError **error); + gboolean _gtk_file_chooser_remove_shortcut_folder (GtkFileChooser *chooser, +- GFile *folder, +- GError **error); ++ GFile *folder, ++ GError **error); + GSList * _gtk_file_chooser_list_shortcut_folder_files (GtkFileChooser *chooser); + + +--- a/gtk/gtkfilechooserwidget.c ++++ b/gtk/gtkfilechooserwidget.c +@@ -45,10 +45,12 @@ + #include "gtkfilesystemmodel.h" + #include "gtkgrid.h" + #include "gtkicontheme.h" ++#include "gtkiconview.h" + #include "gtklabel.h" + #include "gtkmarshalers.h" + #include "gtkmessagedialog.h" + #include "gtkmountoperation.h" ++#include "gtknotebook.h" + #include "gtkpaned.h" + #include "gtkpathbar.h" + #include "gtkplacessidebar.h" +@@ -84,6 +86,7 @@ + #include "gtkcssprovider.h" + + #include ++#include + + #ifdef HAVE_UNISTD_H + #include +@@ -202,6 +205,11 @@ typedef enum { + } StartupMode; + + typedef enum { ++ VIEW_MODE_LIST, ++ VIEW_MODE_ICON, ++} ViewMode; ++ ++typedef enum { + CLOCK_FORMAT_24, + CLOCK_FORMAT_12 + } ClockFormat; +@@ -231,8 +239,12 @@ struct _GtkFileChooserWidgetPrivate { + GtkWidget *browse_header_revealer; + GtkWidget *browse_header_stack; + GtkWidget *browse_files_stack; +- GtkWidget *browse_files_swin; ++ GtkNotebook *view_notebook; ++ GtkWidget *browse_files_list_swin; ++ GtkWidget *browse_files_icon_swin; ++ GtkWidget *browse_files_current_view; + GtkWidget *browse_files_tree_view; ++ GtkWidget *browse_files_icon_view; + GtkWidget *remote_warning_bar; + + GtkWidget *browse_files_popover; +@@ -248,6 +260,12 @@ struct _GtkFileChooserWidgetPrivate { + GtkWidget *delete_file_item; + GtkWidget *sort_directories_item; + GtkWidget *show_time_item; ++ GtkWidget *arrange_item; ++ GtkWidget *sort_by_name_item; ++ GtkWidget *sort_by_size_item; ++ GtkWidget *sort_by_time_item; ++ GtkWidget *ascending_item; ++ GtkWidget *descending_item; + + GtkWidget *browse_new_folder_button; + GtkSizeGroup *browse_path_bar_size_group; +@@ -264,6 +282,7 @@ struct _GtkFileChooserWidgetPrivate { + + GtkGesture *long_press_gesture; + ++ GtkTreeModel *current_model; + GtkFileSystemModel *browse_files_model; + char *browse_files_last_selected_name; + +@@ -351,10 +370,17 @@ struct _GtkFileChooserWidgetPrivate { + guint location_changed_id; + + gulong settings_signal_id; +- int icon_size; ++ gint list_view_icon_size; ++ gint icon_view_icon_size; + + GSource *focus_entry_idle; + ++ GtkWidget *view_mode_combo_box; ++ GtkWidget *icon_view_scale; ++ ViewMode view_mode; ++ ++ GtkCellRenderer *list_icon_renderer; ++ + gulong toplevel_set_focus_id; + GtkWidget *toplevel_last_focus_widget; + +@@ -422,7 +448,8 @@ enum { + MODEL_COL_NAME_COLLATED, + MODEL_COL_IS_FOLDER, + MODEL_COL_IS_SENSITIVE, +- MODEL_COL_SURFACE, ++ MODEL_COL_LIST_SURFACE, ++ MODEL_COL_ICON_PIXBUF, + MODEL_COL_SIZE_TEXT, + MODEL_COL_DATE_TEXT, + MODEL_COL_TIME_TEXT, +@@ -442,7 +469,8 @@ enum { + G_TYPE_STRING, /* MODEL_COL_NAME_COLLATED */ \ + G_TYPE_BOOLEAN, /* MODEL_COL_IS_FOLDER */ \ + G_TYPE_BOOLEAN, /* MODEL_COL_IS_SENSITIVE */ \ +- CAIRO_GOBJECT_TYPE_SURFACE, /* MODEL_COL_SURFACE */ \ ++ CAIRO_GOBJECT_TYPE_SURFACE, /* MODEL_COL_LIST_SURFACE */ \ ++ GDK_TYPE_PIXBUF, /* MODEL_COL_ICON_PIXBUF */ \ + G_TYPE_STRING, /* MODEL_COL_SIZE_TEXT */ \ + G_TYPE_STRING, /* MODEL_COL_DATE_TEXT */ \ + G_TYPE_STRING, /* MODEL_COL_TIME_TEXT */ \ +@@ -452,7 +480,10 @@ enum { + #define DEFAULT_RECENT_FILES_LIMIT 50 + + /* 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 +@@ -573,7 +604,7 @@ static gboolean list_select_func (GtkT + gboolean path_currently_selected, + gpointer data); + +-static void list_selection_changed (GtkTreeSelection *tree_selection, ++static void list_selection_changed (void *selection, + GtkFileChooserWidget *impl); + static void list_row_activated (GtkTreeView *tree_view, + GtkTreePath *path, +@@ -581,6 +612,13 @@ static void list_row_activated ( + GtkFileChooserWidget *impl); + static void list_cursor_changed (GtkTreeView *treeview, + GtkFileChooserWidget *impl); ++static void icon_item_activated (GtkIconView *icon_view, ++ GtkTreePath *path, ++ GtkFileChooserWidget *impl); ++static void item_activated (GtkTreeModel *model, ++ GtkTreePath *path, ++ GtkFileChooserWidget *impl); ++ + + static void path_bar_clicked (GtkPathBar *path_bar, + GFile *file, +@@ -593,6 +631,13 @@ static void update_cell_renderer_attribu + static void load_remove_timer (GtkFileChooserWidget *impl, LoadState new_load_state); + static void browse_files_center_selected_row (GtkFileChooserWidget *impl); + ++static void icon_view_scale_value_changed_cb (GtkRange *range, ++ GtkFileChooserWidget *impl); ++ ++static void view_mode_set (GtkFileChooserWidget *impl, ViewMode view_mode); ++static void view_mode_combo_box_changed_cb (GtkComboBox *combo, ++ GtkFileChooserWidget *impl); ++ + static void location_switch_to_path_bar (GtkFileChooserWidget *impl); + + static void stop_loading_and_clear_list_model (GtkFileChooserWidget *impl, +@@ -622,6 +667,26 @@ static gboolean recent_should_respond + static void set_file_system_backend (GtkFileChooserWidget *impl); + static void unset_file_system_backend (GtkFileChooserWidget *impl); + ++static gboolean get_selected_tree_iter_from_icon_view (GtkFileChooserWidget *impl, ++ GtkTreeIter *iter_out); ++static void current_selection_selected_foreach (GtkFileChooserWidget *impl, ++ GtkTreeSelectionForeachFunc func, ++ gpointer data); ++static guint current_selection_count_selected_rows (GtkFileChooserWidget *impl); ++static void current_selection_select_iter (GtkFileChooserWidget *impl, ++ GtkTreeIter *iter); ++static void copy_old_selection_to_current_view (GtkFileChooserWidget *impl, ++ ViewMode old_view_mode); ++static void current_selection_unselect_iter (GtkFileChooserWidget *impl, ++ GtkTreeIter *iter); ++static void current_selection_unselect_all (GtkFileChooserWidget *impl); ++static void current_view_set_file_model (GtkFileChooserWidget *impl, ++ GtkTreeModel *model); ++static void current_view_set_cursor (GtkFileChooserWidget *impl, ++ GtkTreePath *path); ++static void current_view_set_select_multiple (GtkFileChooserWidget *impl, ++ gboolean select_multiple); ++ + static void clear_model_cache (GtkFileChooserWidget *impl, + gint column); + static void set_model_filter (GtkFileChooserWidget *impl, +@@ -959,7 +1024,7 @@ update_preview_widget_visibility (GtkFil + } + } + +- if (priv->preview_widget_active && priv->preview_widget) ++ if (priv->preview_widget_active && priv->preview_widget && priv->view_mode == VIEW_MODE_LIST) + gtk_widget_show (priv->preview_box); + else + gtk_widget_hide (priv->preview_box); +@@ -1227,19 +1292,16 @@ selection_check (GtkFileChooserWidget *i + gboolean *all_files, + gboolean *all_folders) + { +- GtkFileChooserWidgetPrivate *priv = impl->priv; + 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 (priv->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)); + +@@ -1367,7 +1429,7 @@ browse_files_key_press_event_cb (GtkWidg + return TRUE; + } + +- if (key_is_left_or_right (event)) ++ if (priv->view_mode == VIEW_MODE_LIST && key_is_left_or_right (event)) + { + if (gtk_widget_child_focus (priv->places_sidebar, GTK_DIR_LEFT)) + return TRUE; +@@ -1470,12 +1532,8 @@ add_to_shortcuts_cb (GSimpleAction *acti + gpointer data) + { + GtkFileChooserWidget *impl = data; +- GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection; +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); + +- gtk_tree_selection_selected_foreach (selection, ++ current_selection_selected_foreach (impl, + add_bookmark_foreach_cb, + impl); + } +@@ -1848,6 +1906,86 @@ open_folder_cb (GSimpleAction *action, + } + G_GNUC_END_IGNORE_DEPRECATIONS + ++/* callback used when "Sort by Name" menu item is activated */ ++static void ++sort_by_name_cb (GSimpleAction *action, ++ GVariant *parameter, ++ gpointer data) ++{ ++ GtkFileChooserWidget *impl = data; ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkTreeSortable *sortable; ++ ++ sortable = GTK_TREE_SORTABLE (priv->browse_files_model); ++ gtk_tree_sortable_set_sort_column_id (sortable, ++ priv->sort_column=MODEL_COL_NAME, ++ priv->sort_order); ++} ++ ++/* callback used when "Sort by Size" menu item is activated */ ++static void ++sort_by_size_cb (GSimpleAction *action, ++ GVariant *parameter, ++ gpointer data) ++{ ++ GtkFileChooserWidget *impl = data; ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkTreeSortable *sortable; ++ ++ sortable = GTK_TREE_SORTABLE (priv->browse_files_model); ++ gtk_tree_sortable_set_sort_column_id (sortable, ++ priv->sort_column=MODEL_COL_SIZE, ++ priv->sort_order); ++} ++ ++/* callback used when "Sort by Time" menu item is activated */ ++static void ++sort_by_time_cb (GSimpleAction *action, ++ GVariant *parameter, ++ gpointer data) ++{ ++ GtkFileChooserWidget *impl = data; ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkTreeSortable *sortable; ++ ++ sortable = GTK_TREE_SORTABLE (priv->browse_files_model); ++ gtk_tree_sortable_set_sort_column_id (sortable, ++ priv->sort_column=MODEL_COL_TIME, ++ priv->sort_order); ++} ++ ++/* callback used when "Ascending" menu item is activated */ ++static void ++ascending_cb (GSimpleAction *action, ++ GVariant *parameter, ++ gpointer data) ++{ ++ GtkFileChooserWidget *impl = data; ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkTreeSortable *sortable; ++ ++ sortable = GTK_TREE_SORTABLE (priv->browse_files_model); ++ gtk_tree_sortable_set_sort_column_id (sortable, ++ priv->sort_column, ++ priv->sort_order=GTK_SORT_ASCENDING); ++} ++ ++/* callback used when "Descending" menu item is activated */ ++static void ++descending_cb (GSimpleAction *action, ++ GVariant *parameter, ++ gpointer data) ++{ ++ GtkFileChooserWidget *impl = data; ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkTreeSortable *sortable; ++ ++ sortable = GTK_TREE_SORTABLE (priv->browse_files_model); ++ gtk_tree_sortable_set_sort_column_id (sortable, ++ priv->sort_column, ++ priv->sort_order=GTK_SORT_DESCENDING); ++} ++ + /* callback used when the "Show Hidden Files" menu item is toggled */ + static void + change_show_hidden_state (GSimpleAction *action, +@@ -2175,6 +2313,7 @@ check_file_list_popover_sensitivity (Gtk + gboolean all_files; + gboolean all_folders; + gboolean active; ++ gboolean always_active; + GActionGroup *actions; + GAction *action, *action2; + +@@ -2183,6 +2322,7 @@ check_file_list_popover_sensitivity (Gtk + selection_check (impl, &num_selected, &all_files, &all_folders); + + active = (num_selected != 0); ++ always_active = (num_selected >= 0); + + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "copy-location"); + g_simple_action_set_enabled (G_SIMPLE_ACTION (action), active); +@@ -2196,6 +2336,21 @@ check_file_list_popover_sensitivity (Gtk + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "open"); + g_simple_action_set_enabled (G_SIMPLE_ACTION (action), (num_selected == 1) && all_folders); + ++ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "sort-by-name"); ++ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), always_active); ++ ++ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "sort-by-size"); ++ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), always_active); ++ ++ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "sort-by-time"); ++ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), always_active); ++ ++ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "ascending"); ++ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), always_active); ++ ++ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "descending"); ++ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), always_active); ++ + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "rename"); + if (num_selected == 1) + { +@@ -2261,6 +2416,11 @@ static GActionEntry entries[] = { + { "rename", rename_file_cb, NULL, NULL, NULL }, + { "delete", delete_file_cb, NULL, NULL, NULL }, + { "trash", trash_file_cb, NULL, NULL, NULL }, ++ { "sort-by-name", sort_by_name_cb, NULL, NULL, NULL }, ++ { "sort-by-size", sort_by_size_cb, NULL, NULL, NULL }, ++ { "sort-by-time", sort_by_time_cb, NULL, NULL, NULL }, ++ { "ascending", ascending_cb, NULL, NULL, NULL }, ++ { "descending", descending_cb, NULL, NULL, NULL }, + { "toggle-show-hidden", NULL, NULL, "false", change_show_hidden_state }, + { "toggle-show-size", NULL, NULL, "false", change_show_size_state }, + { "toggle-show-type", NULL, NULL, "false", change_show_type_state }, +@@ -2290,17 +2450,6 @@ append_separator (GtkWidget *box) + gtk_widget_set_visible (GTK_WIDGET (separator), TRUE); + gtk_menu_shell_append (GTK_MENU_SHELL (box), separator); + return separator; +- separator = g_object_new (GTK_TYPE_SEPARATOR, +- "orientation", GTK_ORIENTATION_HORIZONTAL, +- "visible", TRUE, +- "margin-start", 12, +- "margin-end", 12, +- "margin-top", 6, +- "margin-bottom", 6, +- NULL); +- gtk_container_add (GTK_CONTAINER (box), separator); +- +- return separator; + } + + /* Constructs the popup menu for the file list if needed */ +@@ -2319,14 +2468,6 @@ add_button (GtkWidget *box, + gtk_widget_set_visible (GTK_WIDGET (item), TRUE); + gtk_menu_shell_append (GTK_MENU_SHELL (box), item); + return item; +- item = g_object_new (GTK_TYPE_MODEL_BUTTON, +- "visible", TRUE, +- "action-name", action, +- "text", label, +- NULL); +- gtk_container_add (GTK_CONTAINER (box), item); +- +- return item; + } + + static void +@@ -2338,11 +2479,6 @@ file_list_build_popover (GtkFileChooserW + if (priv->browse_files_popover) + return; + +- priv->browse_files_popover = gtk_popover_new (priv->browse_files_tree_view); +- box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); +- g_object_set (box, "margin", 10, NULL); +- gtk_widget_show (box); +- gtk_container_add (GTK_CONTAINER (priv->browse_files_popover), box); + priv->browse_files_popover = gtk_menu_new (); + gtk_menu_attach_to_widget (GTK_MENU (priv->browse_files_popover), GTK_WIDGET (priv->browse_files_tree_view), NULL); + box = priv->browse_files_popover; +@@ -2357,11 +2493,29 @@ file_list_build_popover (GtkFileChooserW + + append_separator (box); + +- priv->hidden_files_item = add_button (box, _("Show _Hidden Files"), "item.toggle-show-hidden"); +- priv->size_column_item = add_button (box, _("Show _Size Column"), "item.toggle-show-size"); +- priv->type_column_item = add_button (box, _("Show T_ype Column"), "item.toggle-show-type"); +- priv->show_time_item = add_button (box, _("Show _Time"), "item.toggle-show-time"); +- priv->sort_directories_item = add_button (box, _("Sort _Folders before Files"), "item.toggle-sort-dirs-first"); ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ priv->hidden_files_item = add_button (box, _("Show _Hidden Files"), "item.toggle-show-hidden"); ++ priv->size_column_item = add_button (box, _("Show _Size Column"), "item.toggle-show-size"); ++ priv->type_column_item = add_button (box, _("Show T_ype Column"), "item.toggle-show-type"); ++ priv->show_time_item = add_button (box, _("Show _Time"), "item.toggle-show-time"); ++ priv->sort_directories_item = add_button (box, _("Sort _Folders before Files"), "item.toggle-sort-dirs-first"); ++ } ++ if (priv->view_mode == VIEW_MODE_ICON) ++ { ++ GtkWidget *menu; ++ priv->arrange_item = add_button (box, _("Arrange Items"), NULL); ++ menu = gtk_menu_new (); ++ gtk_menu_item_set_submenu (GTK_MENU_ITEM (priv->arrange_item), menu); ++ priv->sort_by_name_item = add_button (menu, _("Sort _by Name"), "item.sort-by-name"); ++ priv->sort_by_size_item = add_button (menu, _("Sort _by Size"), "item.sort-by-size"); ++ priv->sort_by_time_item = add_button (menu, _("Sort _by Time"), "item.sort-by-time"); ++ append_separator (menu); ++ priv->ascending_item = add_button (menu, _("Ascending"), "item.ascending"); ++ priv->descending_item = add_button (menu, _("Descending"), "item.descending"); ++ priv->hidden_files_item = add_button (box, _("Show _Hidden Files"), "item.toggle-show-hidden"); ++ priv->sort_directories_item = add_button (box, _("Sort _Folders before Files"), "item.toggle-sort-dirs-first"); ++ } + g_object_set (priv->visit_file_item, "image", gtk_image_new_from_icon_name ("gtk-jump-to", GTK_ICON_SIZE_MENU), NULL); + g_object_set (priv->open_folder_item, "image", gtk_image_new_from_icon_name ("gtk-open", GTK_ICON_SIZE_MENU), NULL); + g_object_set (priv->copy_file_location_item, "image", gtk_image_new_from_icon_name ("gtk-copy", GTK_ICON_SIZE_MENU), NULL); +@@ -2419,41 +2573,10 @@ file_list_show_popover (GtkFileChooserWi + gdouble y) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +- GdkRectangle rect; +- GtkTreeSelection *selection; +- GtkTreeModel *model; +- GList *list; +- GtkTreePath *path; +- + + file_list_update_popover (impl); + gtk_menu_popup_at_pointer (GTK_MENU (priv->browse_files_popover), NULL); + return; +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- list = gtk_tree_selection_get_selected_rows (selection, &model); +- if (list) +- { +- path = list->data; +- gtk_tree_view_get_cell_area (GTK_TREE_VIEW (priv->browse_files_tree_view), path, NULL, &rect); +- gtk_tree_view_convert_bin_window_to_widget_coords (GTK_TREE_VIEW (priv->browse_files_tree_view), +- rect.x, rect.y, &rect.x, &rect.y); +- +- rect.x = CLAMP (x - 20, 0, gtk_widget_get_allocated_width (priv->browse_files_tree_view) - 40); +- rect.width = 40; +- +- g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free); +- } +- else +- { +- rect.x = x; +- rect.y = y; +- rect.width = 1; +- rect.height = 1; +- } +- +- gtk_popover_set_pointing_to (GTK_POPOVER (priv->browse_files_popover), &rect); +- gtk_popover_popup (GTK_POPOVER (priv->browse_files_popover)); + } + + /* Callback used for the GtkWidget::popup-menu signal of the file list */ +@@ -2490,7 +2613,7 @@ list_button_press_event_cb (GtkWidget + return FALSE; + + in_press = TRUE; +- gtk_widget_event (priv->browse_files_tree_view, (GdkEvent *) event); ++ gtk_widget_event (widget, (GdkEvent *) event); + in_press = FALSE; + + file_list_show_popover (impl, event->x, event->y); +@@ -2521,13 +2644,16 @@ file_list_set_sort_column_ids (GtkFileCh + { + GtkFileChooserWidgetPrivate *priv = impl->priv; + +- gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), 0); ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), 0); + +- gtk_tree_view_column_set_sort_column_id (priv->list_name_column, MODEL_COL_NAME); +- gtk_tree_view_column_set_sort_column_id (priv->list_time_column, MODEL_COL_TIME); +- gtk_tree_view_column_set_sort_column_id (priv->list_size_column, MODEL_COL_SIZE); +- gtk_tree_view_column_set_sort_column_id (priv->list_type_column, MODEL_COL_TYPE); +- gtk_tree_view_column_set_sort_column_id (priv->list_location_column, MODEL_COL_LOCATION_TEXT); ++ gtk_tree_view_column_set_sort_column_id (priv->list_name_column, MODEL_COL_NAME); ++ gtk_tree_view_column_set_sort_column_id (priv->list_time_column, MODEL_COL_TIME); ++ gtk_tree_view_column_set_sort_column_id (priv->list_size_column, MODEL_COL_SIZE); ++ gtk_tree_view_column_set_sort_column_id (priv->list_type_column, MODEL_COL_TYPE); ++ gtk_tree_view_column_set_sort_column_id (priv->list_location_column, MODEL_COL_LOCATION_TEXT); ++ } + } + + static gboolean +@@ -2550,11 +2676,22 @@ file_list_query_tooltip_cb (GtkWidget * + return FALSE; + + +- if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (priv->browse_files_tree_view), +- &x, &y, +- keyboard_tip, +- &model, &path, &iter)) +- return FALSE; ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (priv->browse_files_tree_view), ++ &x, &y, ++ keyboard_tip, ++ &model, &path, &iter)) ++ return FALSE; ++ } ++ else if(priv->view_mode == VIEW_MODE_ICON) ++ { ++ if (!gtk_icon_view_get_tooltip_context (GTK_ICON_VIEW (priv->browse_files_icon_view), ++ &x, &y, ++ keyboard_tip, ++ &model, &path, &iter)) ++ return FALSE; ++ } + + gtk_tree_model_get (model, &iter, + MODEL_COL_FILE, &file, +@@ -2568,10 +2705,18 @@ file_list_query_tooltip_cb (GtkWidget * + + filename = g_file_get_path (file); + gtk_tooltip_set_text (tooltip, filename); +- gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (priv->browse_files_tree_view), +- tooltip, +- path); +- ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (priv->browse_files_tree_view), ++ tooltip, ++ path); ++ } ++ else if(priv->view_mode == VIEW_MODE_ICON) ++ { ++ gtk_icon_view_set_tooltip_item (GTK_ICON_VIEW (priv->browse_files_icon_view), ++ tooltip, ++ path); ++ } + g_free (filename); + g_object_unref (file); + gtk_tree_path_free (path); +@@ -2587,8 +2732,8 @@ set_icon_cell_renderer_fixed_size (GtkFi + + gtk_cell_renderer_get_padding (priv->list_pixbuf_renderer, &xpad, &ypad); + gtk_cell_renderer_set_fixed_size (priv->list_pixbuf_renderer, +- xpad * 2 + priv->icon_size, +- ypad * 2 + priv->icon_size); ++ xpad * 2 + priv->list_view_icon_size, ++ ypad * 2 + priv->list_view_icon_size); + } + + static gboolean +@@ -2872,7 +3017,7 @@ location_mode_set (GtkFileChooserWidget + location_switch_to_path_bar (impl); + + if (switch_to_file_list) +- gtk_widget_grab_focus (priv->browse_files_tree_view); ++ gtk_widget_grab_focus (priv->browse_files_current_view); + + break; + +@@ -2943,6 +3088,119 @@ location_toggle_popup_handler (GtkFileCh + } + } + ++/* Creates icon view (alternative for the list view) */ ++static GtkWidget * ++create_browse_files_icon_view (GtkFileChooserWidget *impl) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ ++ gtk_icon_view_set_text_column (GTK_ICON_VIEW (priv->browse_files_icon_view), ++ MODEL_COL_NAME); ++ gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (priv->browse_files_icon_view), ++ MODEL_COL_ICON_PIXBUF); ++ gtk_icon_view_set_item_width (GTK_ICON_VIEW (priv->browse_files_icon_view), ++ ICON_VIEW_ITEM_WIDTH); ++ ++ return priv->browse_files_icon_view; ++} ++ ++static void ++view_mode_set (GtkFileChooserWidget *impl, ViewMode view_mode) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkWidget *old_view = NULL; ++ ViewMode old_view_mode = priv->view_mode; ++ priv->browse_files_popover = NULL; ++ ++ if (old_view_mode == view_mode) ++ return; ++ ++ g_debug("GtkFileChooserWidget::view_mode_set %d", view_mode); ++ ++ priv->view_mode = view_mode; ++ gtk_combo_box_set_active (GTK_COMBO_BOX (priv->view_mode_combo_box), ++ view_mode); ++ ++ /* Creating the target view */ ++ if (view_mode == VIEW_MODE_ICON) ++ { ++ priv->browse_files_current_view = priv->browse_files_icon_view; ++ old_view = priv->browse_files_tree_view; ++ gtk_widget_show (priv->icon_view_scale); ++ } ++ else if (view_mode == VIEW_MODE_LIST) ++ { ++ priv->browse_files_current_view = priv->browse_files_tree_view; ++ old_view = priv->browse_files_icon_view; ++ gtk_widget_hide (priv->icon_view_scale); ++ } ++ else ++ g_assert_not_reached (); ++ ++ /* Set model and selection */ ++ current_view_set_file_model (impl, priv->current_model); ++ current_view_set_select_multiple (impl, priv->select_multiple); ++ copy_old_selection_to_current_view (impl, old_view_mode); ++ ++ /* Hide the old view */ ++ g_object_set (old_view, "model", NULL, NULL); ++ gtk_widget_hide (old_view); ++ ++ /* Show the new view */ ++ gtk_widget_show (priv->browse_files_current_view); ++ gtk_notebook_set_current_page(priv->view_notebook, view_mode); ++} ++ ++/* Callback used when view mode combo box active item is changed */ ++static void ++view_mode_combo_box_changed_cb (GtkComboBox *combo, ++ GtkFileChooserWidget *impl) ++{ ++ ViewMode target = gtk_combo_box_get_active (combo); ++ ++ view_mode_set (impl, target); ++} ++ ++/* Callback used when view mode is changed */ ++gboolean ++view_notebook_switch_page_cb (GtkNotebook *notebook, ++ GtkWidget *page, ++ guint page_num, ++ gpointer user_data) ++{ ++ GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (user_data); ++ view_mode_set (impl, page_num); ++ return TRUE; ++} ++ ++static void ++icon_view_scale_value_changed_cb (GtkRange *range, ++ GtkFileChooserWidget *impl) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ gdouble value = gtk_range_get_value (range); ++ value = round (value / 16) * 16; ++ ++ if (priv->icon_view_icon_size == (gint)value) ++ return; ++ ++ priv->icon_view_icon_size = (gint)value; ++ ++ if (priv->view_mode != VIEW_MODE_ICON) ++ return; ++ ++ set_icon_cell_renderer_fixed_size (impl); ++ ++ if (priv->browse_files_model) ++ _gtk_file_system_model_clear_cache (priv->browse_files_model, MODEL_COL_ICON_PIXBUF); ++ if (priv->search_model) ++ _gtk_file_system_model_clear_cache (priv->search_model, MODEL_COL_ICON_PIXBUF); ++ if (priv->recent_model) ++ _gtk_file_system_model_clear_cache (priv->recent_model, MODEL_COL_ICON_PIXBUF); ++ ++ gtk_widget_queue_resize (priv->browse_files_current_view); ++} ++ + static void + gtk_file_chooser_widget_constructed (GObject *object) + { +@@ -3051,18 +3309,11 @@ set_select_multiple (GtkFileChooserWidge + gboolean property_notify) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection; +- GtkSelectionMode mode; + + if (select_multiple == priv->select_multiple) + return; + +- mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE; +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- gtk_tree_selection_set_mode (selection, mode); +- +- gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (priv->browse_files_tree_view), select_multiple); ++ current_view_set_select_multiple (impl, select_multiple); + + priv->select_multiple = select_multiple; + g_object_notify (G_OBJECT (impl), "select-multiple"); +@@ -3189,6 +3440,7 @@ operation_mode_set_enter_location (GtkFi + gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "location"); + gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE); + location_bar_update (impl); ++ gtk_tree_view_column_set_visible (priv->list_location_column, FALSE); + gtk_widget_set_sensitive (priv->filter_combo, TRUE); + location_mode_set (impl, LOCATION_MODE_FILENAME_ENTRY); + } +@@ -3218,7 +3470,7 @@ operation_mode_set_search (GtkFileChoose + visible_widget = gtk_stack_get_visible_child (GTK_STACK (priv->browse_files_stack)); + + if (visible_widget != priv->places_view && +- visible_widget != priv->browse_files_swin) ++ visible_widget != priv->browse_files_list_swin) + { + gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list"); + } +@@ -3343,6 +3595,12 @@ update_appearance (GtkFileChooserWidget + location_mode_set (impl, priv->location_mode); + } + ++ if (priv->action == GTK_FILE_CHOOSER_ACTION_OPEN || ++ priv->action == GTK_FILE_CHOOSER_ACTION_SAVE) ++ gtk_widget_show (priv->view_mode_combo_box); ++ else ++ gtk_widget_hide (priv->view_mode_combo_box); ++ + if (priv->location_entry) + _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (priv->location_entry), priv->action); + +@@ -3351,7 +3609,7 @@ update_appearance (GtkFileChooserWidget + /* 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 (priv->browse_files_tree_view); ++ gtk_widget_queue_draw (priv->browse_files_current_view); + + emit_default_size_changed (impl); + } +@@ -3781,14 +4039,27 @@ change_icon_theme (GtkFileChooserWidget + profile_start ("start", NULL); + + if (gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height)) +- priv->icon_size = MAX (width, height); ++ priv->list_view_icon_size = MAX (width, height); + else +- priv->icon_size = FALLBACK_ICON_SIZE; ++ priv->list_view_icon_size = FALLBACK_LIST_VIEW_ICON_SIZE; + +- /* the first cell in the first column is the icon column, and we have a fixed size there */ +- set_icon_cell_renderer_fixed_size (impl); ++ if (gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &width, &height)) ++ { ++ priv->icon_view_icon_size = MAX (width, height); ++ } ++ else ++ priv->list_view_icon_size = FALLBACK_LIST_VIEW_ICON_SIZE; + +- clear_model_cache (impl, MODEL_COL_SURFACE); ++ /* the first cell in the first column is the icon column, and we have a fixed size there */ ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ set_icon_cell_renderer_fixed_size (impl); ++ } ++ if (priv->browse_files_model) ++ { ++ clear_model_cache (impl, MODEL_COL_LIST_SURFACE); ++ clear_model_cache (impl, MODEL_COL_ICON_PIXBUF); ++ } + gtk_widget_queue_resize (priv->browse_files_tree_view); + + profile_end ("end", NULL); +@@ -3889,7 +4160,7 @@ set_sort_column (GtkFileChooserWidget *i + GtkFileChooserWidgetPrivate *priv = impl->priv; + GtkTreeSortable *sortable; + +- sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->browse_files_tree_view))); ++ sortable = GTK_TREE_SORTABLE (priv->current_model); + + /* can happen when we're still populating the model */ + if (sortable == NULL) +@@ -3904,6 +4175,7 @@ static void + settings_load (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; ++ ViewMode view_mode; + gboolean show_hidden; + gboolean show_size_column; + gboolean show_type_column; +@@ -3911,6 +4183,7 @@ settings_load (GtkFileChooserWidget *imp + DateFormat date_format; + TypeFormat type_format; + gint sort_column; ++ gint icon_view_scale; + GtkSortType sort_order; + StartupMode startup_mode; + gint sidebar_width; +@@ -3918,6 +4191,8 @@ settings_load (GtkFileChooserWidget *imp + + settings = _gtk_file_chooser_get_settings_for_widget (GTK_WIDGET (impl)); + ++ view_mode = g_settings_get_enum (settings, SETTINGS_KEY_VIEW_MODE); ++ icon_view_scale = g_settings_get_int (settings, SETTINGS_KEY_ICON_VIEW_SCALE); + show_hidden = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN); + show_size_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN); + show_type_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_TYPE_COLUMN); +@@ -3929,12 +4204,20 @@ settings_load (GtkFileChooserWidget *imp + date_format = g_settings_get_enum (settings, SETTINGS_KEY_DATE_FORMAT); + type_format = g_settings_get_enum (settings, SETTINGS_KEY_TYPE_FORMAT); + ++ gtk_range_set_value (GTK_RANGE (priv->icon_view_scale), icon_view_scale); ++ priv->icon_view_icon_size = icon_view_scale; ++ ++ view_mode_set (impl, view_mode); ++ + if (!priv->show_hidden_set) + set_show_hidden (impl, show_hidden); + priv->show_size_column = show_size_column; +- gtk_tree_view_column_set_visible (priv->list_size_column, show_size_column); +- priv->show_type_column = show_type_column; +- gtk_tree_view_column_set_visible (priv->list_type_column, show_type_column); ++ ++ if (priv->list_size_column) { ++ gtk_tree_view_column_set_visible (priv->list_size_column, show_size_column); ++ priv->show_type_column = show_type_column; ++ gtk_tree_view_column_set_visible (priv->list_type_column, show_type_column); ++ } + + priv->sort_column = sort_column; + priv->sort_order = sort_order; +@@ -3963,6 +4246,8 @@ settings_save (GtkFileChooserWidget *imp + /* All the other state */ + + g_settings_set_enum (settings, SETTINGS_KEY_LOCATION_MODE, priv->location_mode); ++ g_settings_set_enum (settings, SETTINGS_KEY_VIEW_MODE, priv->view_mode); ++ g_settings_set_int (settings, SETTINGS_KEY_ICON_VIEW_SCALE, priv->icon_view_icon_size); + g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN, + gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl))); + g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN, priv->show_size_column); +@@ -4474,10 +4759,14 @@ load_set_model (GtkFileChooserWidget *im + g_assert (priv->browse_files_model != NULL); + + profile_msg (" gtk_tree_view_set_model start", NULL); +- gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), +- GTK_TREE_MODEL (priv->browse_files_model)); +- update_columns (impl, FALSE, _("Modified")); +- file_list_set_sort_column_ids (impl); ++ current_view_set_file_model (impl, GTK_TREE_MODEL (priv->browse_files_model)); ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), ++ GTK_TREE_MODEL (priv->browse_files_model)); ++ update_columns (impl, FALSE, _("Modified")); ++ file_list_set_sort_column_ids (impl); ++ } + set_sort_column (impl); + profile_msg (" gtk_tree_view_set_model end", NULL); + priv->list_sort_ascending = TRUE; +@@ -4557,7 +4846,7 @@ browse_files_select_first_row (GtkFileCh + GtkTreeIter dummy_iter; + GtkTreeModel *tree_model; + +- tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ tree_model = priv->current_model; + + if (!tree_model) + return; +@@ -4576,8 +4865,7 @@ browse_files_select_first_row (GtkFileCh + */ + priv->auto_selecting_first_row = TRUE; + +- gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->browse_files_tree_view), path, NULL, FALSE); +- ++ current_view_set_cursor (impl, path); + priv->auto_selecting_first_row = FALSE; + } + gtk_tree_path_free (path); +@@ -4603,7 +4891,13 @@ center_selected_row_foreach_cb (GtkTreeM + if (closure->already_centered) + return; + +- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->priv->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0); ++ if (closure->impl->priv->view_mode == VIEW_MODE_LIST) ++ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->priv->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0); ++ else if (closure->impl->priv->view_mode == VIEW_MODE_ICON) ++ gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (closure->impl->priv->browse_files_icon_view), path, TRUE, 0.5, 0.0); ++ else ++ g_assert_not_reached (); ++ + closure->already_centered = TRUE; + } + +@@ -4611,15 +4905,11 @@ center_selected_row_foreach_cb (GtkTreeM + static void + browse_files_center_selected_row (GtkFileChooserWidget *impl) + { +- GtkFileChooserWidgetPrivate *priv = impl->priv; + struct center_selected_row_closure closure; +- GtkTreeSelection *selection; +- + closure.impl = impl; + closure.already_centered = FALSE; + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->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 +@@ -4627,7 +4917,6 @@ show_and_select_files (GtkFileChooserWid + GSList *files) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection; + GtkFileSystemModel *fsmodel; + gboolean enabled_hidden, removed_filters; + gboolean selected_a_file; +@@ -4636,8 +4925,7 @@ show_and_select_files (GtkFileChooserWid + g_assert (priv->load_state == LOAD_FINISHED); + g_assert (priv->browse_files_model != NULL); + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- fsmodel = GTK_FILE_SYSTEM_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->browse_files_tree_view))); ++ fsmodel = GTK_FILE_SYSTEM_MODEL (priv->current_model); + + g_assert (fsmodel == priv->browse_files_model); + +@@ -4692,11 +4980,10 @@ show_and_select_files (GtkFileChooserWid + { + 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 (priv->browse_files_tree_view), +- path, NULL, FALSE); ++ current_view_set_cursor (impl, path); + gtk_tree_path_free (path); + + selected_a_file = TRUE; +@@ -4847,12 +5134,15 @@ stop_loading_and_clear_list_model (GtkFi + { + GtkFileChooserWidgetPrivate *priv = impl->priv; + ++ if (priv->current_model == GTK_TREE_MODEL (priv->browse_files_model)) ++ priv->current_model = NULL; ++ + load_remove_timer (impl, LOAD_EMPTY); + + g_set_object (&priv->browse_files_model, NULL); + + if (remove) +- gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), NULL); ++ current_view_set_file_model (impl, NULL); + } + + /* Replace 'target' with 'replacement' in the input string. */ +@@ -5123,6 +5413,18 @@ end: + } + + static gboolean ++get_visible_range (GtkTreePath **start, GtkTreePath **end, ++ GtkFileChooserWidget *impl) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ if (priv->view_mode == VIEW_MODE_LIST) ++ return gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->browse_files_tree_view), start, end); ++ if (priv->view_mode == VIEW_MODE_ICON) ++ return gtk_icon_view_get_visible_range (GTK_ICON_VIEW (priv->browse_files_icon_view), start, end); ++ g_assert_not_reached (); ++} ++ ++static gboolean + file_system_model_set (GtkFileSystemModel *model, + GFile *file, + GFileInfo *info, +@@ -5181,12 +5483,15 @@ file_system_model_set (GtkFileSystemMode + else + g_value_set_boolean (value, TRUE); + break; +- case MODEL_COL_SURFACE: ++ case MODEL_COL_LIST_SURFACE: ++ /* don't load list view icons in other view modes */ ++ if(priv->view_mode != VIEW_MODE_LIST) ++ return FALSE; + if (info) + { + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_ICON)) + { +- g_value_take_boxed (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), priv->icon_size)); ++ g_value_take_boxed (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), priv->list_view_icon_size)); + } + else + { +@@ -5240,6 +5545,76 @@ file_system_model_set (GtkFileSystemMode + else + g_value_set_boxed (value, NULL); + break; ++ case MODEL_COL_ICON_PIXBUF: ++ if (info) ++ { ++ GtkTreeModel *tree_model; ++ GtkTreePath *path, *start, *end; ++ GtkTreeIter iter; ++ int icon_size; ++ gboolean file_visible; ++ ++ tree_model = priv->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)) ++ { ++ icon_size = priv->icon_view_icon_size; ++ ++ cairo_surface_t *icon_surface = _gtk_file_info_render_icon (info, GTK_WIDGET (impl), icon_size); ++ GdkPixbuf *icon_pixbuf = gdk_pixbuf_get_from_surface(icon_surface, ++ 0, 0, ++ cairo_image_surface_get_width(icon_surface), ++ cairo_image_surface_get_height(icon_surface)); ++ cairo_surface_destroy(icon_surface); ++ ++ g_value_take_object (value, icon_pixbuf); ++ return TRUE; ++ } ++ ++ if (!get_visible_range (&start, &end, impl)) ++ return FALSE; ++ ++ if (!_gtk_file_system_model_get_iter_for_file (model, ++ &iter, ++ file)) ++ g_assert_not_reached (); ++ ++ 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::icon_queried", TRUE); ++ g_file_query_info_async (file, ++ G_FILE_ATTRIBUTE_THUMBNAIL_PATH "," ++ G_FILE_ATTRIBUTE_THUMBNAILING_FAILED "," ++ G_FILE_ATTRIBUTE_STANDARD_ICON, ++ G_FILE_QUERY_INFO_NONE, ++ G_PRIORITY_DEFAULT, ++ _gtk_file_system_model_get_cancellable (model), ++ file_system_model_got_thumbnail, ++ model); ++ } ++ ++ } ++ return FALSE; ++ } ++ 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); + break; +@@ -5432,7 +5807,6 @@ static void + update_chooser_entry (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection; + struct update_chooser_entry_selected_foreach_closure closure; + + /* no need to update the file chooser's entry if there's no entry */ +@@ -5449,9 +5823,8 @@ update_chooser_entry (GtkFileChooserWidg + + g_assert (priv->location_entry != NULL); + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->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) + { +@@ -5948,19 +6321,15 @@ gtk_file_chooser_widget_unselect_file (G + { + GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); + GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeView *tree_view; +- GtkTreeModel *model; + GtkTreeIter iter; + +- tree_view = GTK_TREE_VIEW (priv->browse_files_tree_view); +- model = gtk_tree_view_get_model (tree_view); +- if (!model) ++ if (!priv->current_model) + return; + +- if (!_gtk_file_system_model_get_iter_for_file (GTK_FILE_SYSTEM_MODEL (model), &iter, file)) ++ if (!_gtk_file_system_model_get_iter_for_file (GTK_FILE_SYSTEM_MODEL (priv->current_model), &iter, file)) + return; + +- gtk_tree_selection_unselect_iter (gtk_tree_view_get_selection (tree_view), &iter); ++ current_selection_unselect_iter (impl, &iter); + } + + static gboolean +@@ -5971,12 +6340,9 @@ maybe_select (GtkTreeModel *model, + { + GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (data); + GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection; + gboolean is_sensitive; + gboolean is_folder; + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- + gtk_tree_model_get (model, iter, + MODEL_COL_IS_FOLDER, &is_folder, + MODEL_COL_IS_SENSITIVE, &is_sensitive, +@@ -5985,9 +6351,9 @@ maybe_select (GtkTreeModel *model, + if (is_sensitive && + ((is_folder && priv->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) || + (!is_folder && priv->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; + } +@@ -6003,8 +6369,15 @@ gtk_file_chooser_widget_select_all (GtkF + { + GtkTreeSelection *selection; + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- gtk_tree_selection_select_all (selection); ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ gtk_tree_selection_select_all (selection); ++ } ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ gtk_icon_view_select_all (GTK_ICON_VIEW (priv->browse_files_icon_view)); ++ else ++ g_assert_not_reached(); + return; + } + +@@ -6017,10 +6390,7 @@ static void + gtk_file_chooser_widget_unselect_all (GtkFileChooser *chooser) + { + GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); +- GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- +- gtk_tree_selection_unselect_all (selection); ++ current_selection_unselect_all (impl); + pending_select_files_free (impl); + } + +@@ -6176,15 +6546,13 @@ gtk_file_chooser_widget_get_files (GtkFi + current_focus = NULL; + + file_list_seen = FALSE; +- if (current_focus == priv->browse_files_tree_view) ++ if (current_focus == priv->browse_files_current_view) + { +- GtkTreeSelection *selection; +- + file_list: + + file_list_seen = TRUE; +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->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: + * +@@ -6218,7 +6586,7 @@ gtk_file_chooser_widget_get_files (GtkFi + else + return NULL; + } +- else if (priv->toplevel_last_focus_widget == priv->browse_files_tree_view) ++ else if (priv->toplevel_last_focus_widget == priv->browse_files_current_view) + goto file_list; + else if (priv->location_entry && priv->toplevel_last_focus_widget == priv->location_entry) + goto file_entry; +@@ -6496,8 +6864,6 @@ switch_folder_foreach_cb (GtkTreeModel * + static void + switch_to_selected_folder (GtkFileChooserWidget *impl) + { +- GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection; + struct switch_folder_closure closure; + + /* We do this with foreach() rather than get_selected() as we may be in +@@ -6508,8 +6874,7 @@ switch_to_selected_folder (GtkFileChoose + closure.file = NULL; + closure.num_selected = 0; + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->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); + +@@ -6527,19 +6892,33 @@ get_selected_file_info_from_file_list (G + GtkTreeSelection *selection; + GtkTreeIter iter; + GFileInfo *info; +- GtkTreeModel *model; + + g_assert (!priv->select_multiple); +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- if (!gtk_tree_selection_get_selected (selection, &model, &iter)) ++ ++ if (priv->view_mode == VIEW_MODE_LIST) + { +- *had_selection = FALSE; +- return NULL; +- } ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) ++ { ++ *had_selection = FALSE; ++ return NULL; ++ } + +- *had_selection = TRUE; ++ *had_selection = TRUE; ++ } ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ { ++ if (!get_selected_tree_iter_from_icon_view (impl, &iter)) ++ { ++ *had_selection = FALSE; ++ return NULL; ++ } ++ *had_selection = TRUE; ++ } ++ else ++ g_assert_not_reached(); + +- info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (model), &iter); ++ info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (priv->current_model), &iter); + return info; + } + +@@ -7036,7 +7415,7 @@ gtk_file_chooser_widget_should_respond ( + + current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel)); + +- if (current_focus == priv->browse_files_tree_view) ++ if (current_focus == priv->browse_files_current_view) + { + /* The following array encodes what we do based on the priv->action and the + * number of files selected. +@@ -7283,9 +7662,9 @@ gtk_file_chooser_widget_initial_focus (G + { + if (priv->location_mode == LOCATION_MODE_PATH_BAR + || priv->operation_mode == OPERATION_MODE_RECENT) +- widget = priv->browse_files_tree_view; ++ widget = priv->browse_files_current_view; + else +- widget = priv->location_entry; ++ widget = priv->location_entry; + } + else if (priv->action == GTK_FILE_CHOOSER_ACTION_SAVE || + priv->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) +@@ -7298,6 +7677,7 @@ gtk_file_chooser_widget_initial_focus (G + + g_assert (widget != NULL); + gtk_widget_grab_focus (widget); ++ create_browse_files_icon_view (impl); + } + + static void +@@ -7321,45 +7701,23 @@ selected_foreach_get_file_cb (GtkTreeMod + static GSList * + get_selected_files (GtkFileChooserWidget *impl) + { +- GtkFileChooserWidgetPrivate *priv = impl->priv; + GSList *result; +- GtkTreeSelection *selection; +- + result = NULL; + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- gtk_tree_selection_selected_foreach (selection, selected_foreach_get_file_cb, &result); ++ current_selection_selected_foreach (impl, selected_foreach_get_file_cb, &result); + result = g_slist_reverse (result); + + return result; + } + +-static void +-selected_foreach_get_info_cb (GtkTreeModel *model, +- GtkTreePath *path, +- GtkTreeIter *iter, +- gpointer data) +-{ +- GSList **list; +- GFileInfo *info; +- +- list = data; +- +- info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (model), iter); +- *list = g_slist_prepend (*list, g_object_ref (info)); +-} +- + static GSList * + get_selected_infos (GtkFileChooserWidget *impl) + { +- GtkFileChooserWidgetPrivate *priv = impl->priv; + GSList *result; +- GtkTreeSelection *selection; + + result = NULL; + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- gtk_tree_selection_selected_foreach (selection, selected_foreach_get_info_cb, &result); ++ current_selection_selected_foreach (impl, selected_foreach_get_file_cb, &result); + result = g_slist_reverse (result); + + return result; +@@ -7429,6 +7787,7 @@ search_engine_finished_cb (GtkSearchEngi + gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "empty"); + gtk_entry_grab_focus_without_selecting (GTK_ENTRY (priv->search_entry)); + } ++ current_view_set_file_model (impl, GTK_TREE_MODEL (priv->search_model)); + } + + static void +@@ -7454,7 +7813,7 @@ search_clear_model (GtkFileChooserWidget + + if (remove && + gtk_tree_view_get_model (GTK_TREE_VIEW (priv->browse_files_tree_view)) == GTK_TREE_MODEL (priv->search_model)) +- gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), NULL); ++ current_view_set_file_model (impl, NULL); + + g_clear_object (&priv->search_model); + } +@@ -7664,7 +8023,7 @@ recent_clear_model (GtkFileChooserWidget + return; + + if (remove) +- gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), NULL); ++ current_view_set_file_model (impl, NULL); + + g_set_object (&priv->recent_model, NULL); + } +@@ -7717,8 +8076,7 @@ recent_idle_cleanup (gpointer data) + GtkFileChooserWidget *impl = load_data->impl; + GtkFileChooserWidgetPrivate *priv = impl->priv; + +- gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), +- GTK_TREE_MODEL (priv->recent_model)); ++ current_view_set_file_model (impl, GTK_TREE_MODEL (priv->recent_model)); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), 0); + + gtk_tree_view_column_set_sort_column_id (priv->list_name_column, -1); +@@ -7866,12 +8224,8 @@ static gboolean + recent_should_respond (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +- GtkTreeSelection *selection; +- + g_assert (priv->operation_mode == OPERATION_MODE_RECENT); +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- return (gtk_tree_selection_count_selected_rows (selection) != 0); ++ return (current_selection_count_selected_rows (impl) != 0); + } + + static void +@@ -7931,29 +8285,40 @@ check_preview_change (GtkFileChooserWidg + GtkTreeModel *model; + GtkTreeSelection *selection; + +- model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); +- if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_SINGLE || +- gtk_tree_selection_get_mode (selection) == GTK_SELECTION_BROWSE) ++ model = priv->current_model; ++ ++ if (priv->view_mode == VIEW_MODE_LIST) + { +- GtkTreeIter iter; ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_SINGLE || ++ gtk_tree_selection_get_mode (selection) == GTK_SELECTION_BROWSE) ++ { ++ GtkTreeIter iter; ++ ++ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) ++ path = gtk_tree_model_get_path (model, &iter); ++ else ++ path = NULL; ++ } + +- if (gtk_tree_selection_get_selected (selection, NULL, &iter)) +- path = gtk_tree_model_get_path (model, &iter); + else +- path = NULL; +- } +- else +- { +- gtk_tree_view_get_cursor (GTK_TREE_VIEW (priv->browse_files_tree_view), &path, NULL); +- if (path && !gtk_tree_selection_path_is_selected (selection, path)) + { +- gtk_tree_path_free (path); +- path = NULL; ++ gtk_tree_view_get_cursor (GTK_TREE_VIEW (priv->browse_files_tree_view), &path, NULL); ++ if (path && !gtk_tree_selection_path_is_selected (selection, path)) ++ { ++ gtk_tree_path_free (path); ++ path = NULL; ++ } + } + } ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ { ++ gtk_icon_view_get_cursor (GTK_ICON_VIEW (priv->browse_files_icon_view), &path, NULL); ++ } ++ else ++ g_assert_not_reached (); + +- if (path) ++ if (path && model) + { + GtkTreeIter iter; + +@@ -8037,15 +8402,13 @@ list_select_func (GtkTreeSelection *sele + return TRUE; + } + ++/* GtkTreeSelection or GtkIconView selection changed. */ + static void +-list_selection_changed (GtkTreeSelection *selection, +- GtkFileChooserWidget *impl) ++list_selection_changed (void *selection, ++ GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; + +- if (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->browse_files_tree_view)) == NULL) +- return; +- + if (priv->location_entry) + update_chooser_entry (impl); + +@@ -8070,15 +8433,34 @@ list_row_activated (GtkTreeView + GtkTreeViewColumn *column, + GtkFileChooserWidget *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, ++ GtkFileChooserWidget *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, ++ GtkFileChooserWidget *impl) ++{ + GtkFileChooserWidgetPrivate *priv = impl->priv; + 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; + +@@ -8098,7 +8480,7 @@ list_row_activated (GtkTreeView + priv->action == GTK_FILE_CHOOSER_ACTION_SAVE) + g_signal_emit_by_name (impl, "file-activated"); + +- out: ++ out: + + if (file) + g_object_unref (file); +@@ -8129,10 +8511,13 @@ static void + update_cell_renderer_attributes (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; ++ /* only applicable in the tree view (i.e. list view) */ ++ if (!priv->browse_files_tree_view) ++ return; + + gtk_tree_view_column_set_attributes (priv->list_name_column, + priv->list_pixbuf_renderer, +- "surface", MODEL_COL_SURFACE, ++ "surface", MODEL_COL_LIST_SURFACE, + "sensitive", MODEL_COL_IS_SENSITIVE, + NULL); + gtk_tree_view_column_set_attributes (priv->list_name_column, +@@ -8711,15 +9096,19 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_stack); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_sidebar); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_view); ++ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, view_notebook); ++ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_list_swin); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_tree_view); +- gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_swin); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_revealer); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_stack); ++ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_icon_swin); ++ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_icon_view); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_new_folder_button); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_path_bar_size_group); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_path_bar); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, filter_combo_hbox); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, filter_combo); ++ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, icon_view_scale); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, preview_box); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, extra_align); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, extra_and_filters); +@@ -8738,6 +9127,7 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_type_renderer); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_location_column); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_location_renderer); ++ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_icon_renderer); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_name_entry); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_create_button); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_error_label); +@@ -8747,6 +9137,7 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, rename_file_error_label); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, rename_file_popover); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, remote_warning_bar); ++ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, view_mode_combo_box); + + /* And a *lot* of callbacks to bind ... */ + gtk_widget_class_bind_template_callback (widget_class, browse_files_key_press_event_cb); +@@ -8761,6 +9152,10 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_callback (widget_class, file_list_drag_end_cb); + gtk_widget_class_bind_template_callback (widget_class, list_selection_changed); + gtk_widget_class_bind_template_callback (widget_class, list_cursor_changed); ++ gtk_widget_class_bind_template_callback (widget_class, icon_item_activated); ++ gtk_widget_class_bind_template_callback (widget_class, icon_view_scale_value_changed_cb); ++ gtk_widget_class_bind_template_callback (widget_class, view_mode_combo_box_changed_cb); ++ gtk_widget_class_bind_template_callback (widget_class, view_notebook_switch_page_cb); + gtk_widget_class_bind_template_callback (widget_class, filter_combo_changed); + gtk_widget_class_bind_template_callback (widget_class, path_bar_clicked); + gtk_widget_class_bind_template_callback (widget_class, places_sidebar_open_location_cb); +@@ -8810,6 +9205,18 @@ post_process_ui (GtkFileChooserWidget *i + GDK_ACTION_COPY | GDK_ACTION_MOVE); + gtk_drag_dest_add_uri_targets (impl->priv->browse_files_tree_view); + ++ /* Setup file list iconview */ ++ gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (impl->priv->browse_files_icon_view), ++ GDK_BUTTON1_MASK, ++ NULL, 0, ++ GDK_ACTION_COPY | GDK_ACTION_MOVE); ++ gtk_drag_source_add_uri_targets (impl->priv->browse_files_icon_view); ++ gtk_drag_dest_set (impl->priv->browse_files_icon_view, ++ GTK_DEST_DEFAULT_ALL, ++ NULL, 0, ++ GDK_ACTION_COPY | GDK_ACTION_MOVE); ++ gtk_drag_dest_add_uri_targets (impl->priv->browse_files_icon_view); ++ + /* File browser treemodel columns are shared between GtkFileChooser implementations, + * so we don't set cell renderer attributes in GtkBuilder, but rather keep that + * in code. +@@ -8841,6 +9248,7 @@ post_process_ui (GtkFileChooserWidget *i + * that priv->icon_size be already setup. + */ + set_icon_cell_renderer_fixed_size (impl); ++ impl->priv->browse_files_current_view = impl->priv->browse_files_tree_view; + + atk_obj = gtk_widget_get_accessible (impl->priv->browse_new_folder_button); + if (GTK_IS_ACCESSIBLE (atk_obj)) +@@ -8902,7 +9310,8 @@ gtk_file_chooser_widget_init (GtkFileCho + priv->show_size_column = TRUE; + priv->show_type_column = TRUE; + priv->type_format = TYPE_FORMAT_MIME; +- priv->icon_size = FALLBACK_ICON_SIZE; ++ priv->list_view_icon_size = FALLBACK_LIST_VIEW_ICON_SIZE; ++ priv->icon_view_icon_size = FALLBACK_ICON_VIEW_ICON_SIZE; + priv->load_state = LOAD_EMPTY; + priv->reload_state = RELOAD_EMPTY; + priv->pending_select_files = NULL; +@@ -8914,6 +9323,7 @@ gtk_file_chooser_widget_init (GtkFileCho + priv->create_folders = TRUE; + priv->auto_selecting_first_row = FALSE; + priv->renamed_file = NULL; ++ priv->view_mode = VIEW_MODE_LIST; + + /* Ensure GTK+ private types used by the template + * definition before calling gtk_widget_init_template() +@@ -8961,6 +9371,258 @@ gtk_file_chooser_widget_new (GtkFileChoo + NULL); + } + ++static gboolean ++get_selected_tree_iter_from_icon_view (GtkFileChooserWidget *impl, ++ GtkTreeIter *iter_out) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GList *icon_selection; ++ GtkTreePath *icon_selection_path; ++ ++ icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->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 (priv->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 (GtkFileChooserWidget *impl, ++ GtkTreeSelectionForeachFunc func, ++ gpointer data) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkTreeIter iter; ++ GList *icon_selection; ++ GList *elem; ++ GtkTreePath *icon_selection_path; ++ ++ icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->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 (priv->current_model), ++ &iter, ++ icon_selection_path); ++ (* func) (GTK_TREE_MODEL (priv->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 (GtkFileChooserWidget *impl, ++ ViewMode view, ++ GtkTreeSelectionForeachFunc func, ++ gpointer data) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ if (priv->current_model == NULL) ++ return; ++ ++ if (view == VIEW_MODE_LIST) ++ { ++ GtkTreeSelection *selection; ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->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 (GtkFileChooserWidget *impl, ++ GtkTreeSelectionForeachFunc func, ++ gpointer data) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ selection_selected_foreach (impl, priv->view_mode, func, data); ++} ++ ++static guint ++current_selection_count_selected_rows (GtkFileChooserWidget *impl) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ GtkTreeSelection *selection; ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ return gtk_tree_selection_count_selected_rows (selection); ++ } ++ if (priv->view_mode == VIEW_MODE_ICON) ++ { ++ GList *icon_selection; ++ icon_selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->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 (GtkFileChooserWidget *impl, ++ GtkTreeIter *iter, ++ ViewMode target) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ if (target == VIEW_MODE_LIST) ++ { ++ GtkTreeSelection *selection; ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->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 (priv->current_model, iter); ++ gtk_icon_view_select_path (GTK_ICON_VIEW (priv->browse_files_icon_view), path); ++ gtk_tree_path_free (path); ++ } ++ else ++ g_assert_not_reached (); ++} ++ ++static void ++current_selection_select_iter (GtkFileChooserWidget *impl, ++ GtkTreeIter *iter) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ selection_select_iter (impl, iter, priv->view_mode); ++} ++ ++struct copy_old_selection_to_current_view_closure { ++ GtkFileChooserWidget *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->priv->view_mode); ++} ++ ++static void ++copy_old_selection_to_current_view (GtkFileChooserWidget *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 (GtkFileChooserWidget *impl, ++ GtkTreeIter *iter) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ GtkTreeSelection *selection; ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ gtk_tree_selection_unselect_iter (selection, iter); ++ } ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ { ++ GtkTreePath *path; ++ path = gtk_tree_model_get_path (priv->current_model, iter); ++ gtk_icon_view_unselect_path (GTK_ICON_VIEW (priv->browse_files_icon_view), path); ++ gtk_tree_path_free (path); ++ } ++ else ++ g_assert_not_reached (); ++} ++ ++static void ++current_selection_unselect_all (GtkFileChooserWidget *impl) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ GtkTreeSelection *selection; ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ gtk_tree_selection_unselect_all (selection); ++ } ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ gtk_icon_view_unselect_all (GTK_ICON_VIEW (priv->browse_files_icon_view)); ++ else ++ g_assert_not_reached (); ++} ++ ++static void ++current_view_set_file_model (GtkFileChooserWidget *impl, GtkTreeModel *model) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkWidget *view; ++ ++ priv->current_model = model; ++ ++ if (priv->view_mode == VIEW_MODE_LIST) ++ view = priv->browse_files_tree_view; ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ view = priv->browse_files_icon_view; ++ else ++ g_assert_not_reached (); ++ ++ g_object_set (view, "model", priv->current_model, NULL); ++} ++ ++static void ++current_view_set_cursor (GtkFileChooserWidget *impl, GtkTreePath *path) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ if (priv->view_mode == VIEW_MODE_LIST) ++ gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->browse_files_tree_view), path, NULL, FALSE); ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ gtk_icon_view_set_cursor (GTK_ICON_VIEW (priv->browse_files_icon_view), path, NULL, FALSE); ++ else ++ g_assert_not_reached (); ++} ++ ++static void ++current_view_set_select_multiple (GtkFileChooserWidget *impl, gboolean select_multiple) ++{ ++ GtkFileChooserWidgetPrivate *priv = impl->priv; ++ GtkTreeSelection *selection; ++ GtkSelectionMode mode; ++ ++ mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE; ++ ++ if (priv->view_mode == VIEW_MODE_LIST) ++ { ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); ++ gtk_tree_selection_set_mode (selection, mode); ++ gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (priv->browse_files_tree_view), select_multiple); ++ } ++ else if (priv->view_mode == VIEW_MODE_ICON) ++ gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (priv->browse_files_icon_view), mode); ++ else ++ g_assert_not_reached (); ++} ++ + static void + gtk_file_chooser_widget_add_choice (GtkFileChooser *chooser, + const char *id, +@@ -9080,4 +9742,3 @@ gtk_file_chooser_widget_get_choice (GtkF + + return NULL; + } +- +--- a/gtk/org.gtk.Settings.FileChooser.gschema.xml ++++ b/gtk/org.gtk.Settings.FileChooser.gschema.xml +@@ -55,6 +55,11 @@ + + + ++ ++ ++ ++ ++ + + + "" +@@ -63,16 +68,30 @@ + 'path-bar' + Location mode + +- Controls whether the file chooser shows just a path bar, or a visible entry ++ Controls whether the file chooser shows just a path bar, or a visible entry + for the filename as well, for the benefit of typing-oriented users. The + possible values for these modes are "path-bar" and "filename-entry". + + ++ ++ 'list-view' ++ Change view mode ++ ++ Controls the view mode used. ++ ++ ++ ++ 48 ++ Change icon size ++ ++ Controls the size of the icons in icon view mode. ++ ++ + + false + Show hidden files + +- Controls whether the file chooser shows hidden files or not. ++ Controls whether the file chooser shows hidden files or not. + + + +@@ -91,37 +110,37 @@ + true + Show file sizes + +- Controls whether the file chooser shows a column with file sizes. ++ Controls whether the file chooser shows a column with file sizes. + + + + true + Show file types + +- Controls whether the file chooser shows a column with file types. ++ Controls whether the file chooser shows a column with file types. + + + + 'name' + Sort column + +- Can be one of "name", "modified", or "size". It controls +- which of the columns in the file chooser is used for sorting +- the list of files. ++ Can be one of "name", "modified", or "size". It controls ++ which of the columns in the file chooser is used for sorting ++ the list of files. + + + + 'ascending' + Sort order + +- Can be one of the strings "ascending" or "descending". ++ Can be one of the strings "ascending" or "descending". + + + + (-1, -1) + Window position + +- The (x, y) coordinates of the upper-left corner of the GtkFileChooserDialog's ++ The (x, y) coordinates of the upper-left corner of the GtkFileChooserDialog's + window. + + +--- a/gtk/ui/gtkfilechooserwidget.ui ++++ b/gtk/ui/gtkfilechooserwidget.ui +@@ -9,6 +9,56 @@ + 1 + vertical + ++ ++ 1 ++ ++ ++ ++ List View ++ Icon View ++ ++ 0 ++ 1 ++ Select filechooser view ++ start ++ start ++ ++ ++ ++ ++ 0 ++ start ++ ++ ++ ++ ++ 256 ++ 32 ++ 32 ++ 16 ++ ++ ++ ++ ++ 0 ++ horizontal ++ icon_view_icon_size ++ 1 ++ end ++ fill ++ 10 ++ 100 ++ False ++ ++ ++ ++ 1 ++ end ++ ++ ++ ++ ++ + + 1 + +@@ -187,110 +237,172 @@ + 1 + vertical + +- ++ + 1 +- never ++ False ++ + +- ++ + 1 +- 1 +- 0 +- +- +- Files +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- ++ never + +- +- Name +- 1 +- 1 ++ ++ True ++ True ++ True ++ False ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +- +- 6 ++ ++ True ++ Name ++ True ++ ++ ++ 6 ++ ++ ++ ++ ++ 10 ++ end ++ ++ + + + +- +- 10 +- end ++ ++ Location ++ 1 ++ 0 ++ 1 ++ ++ ++ 0 ++ 10 ++ start ++ 6 ++ ++ + + +- +- +- +- +- Location +- 1 +- 0 +- 1 + +- +- 0 +- 10 +- start +- 6 ++ ++ Size ++ fixed ++ ++ ++ 0 ++ 6 ++ ++ + + +- +- +- +- +- Size +- fixed + +- +- 0 +- 6 ++ ++ Type ++ 1 ++ ++ ++ 0 ++ 6 ++ ++ + + +- +- +- +- +- Type +- 1 + +- +- 0 +- 6 ++ ++ Modified ++ fixed ++ ++ ++ 6 ++ ++ ++ ++ ++ 6 ++ ++ + + + + ++ ++ ++ ++ ++ True ++ False ++ List View ++ ++ ++ False ++ ++ ++ ++ ++ True ++ True ++ in ++ GTK_POLICY_AUTOMATIC + +- +- Modified +- fixed ++ ++ True ++ True ++ True ++ 2 ++ ++ ++ ++ ++ ++ ++ ++ + +- +- 6 ++ + + + +- +- 6 +- ++ + + + + ++ ++ 1 ++ ++ ++ ++ ++ True ++ False ++ Icon View ++ ++ ++ 1 ++ False ++ ++ ++ ++ ++ ++ ++ + + + +@@ -409,7 +521,7 @@ + + + 1 +- 1 ++ 2 + + + diff --git a/gtk3-filechooser-icon-view.patch.diff b/gtk3-filechooser-icon-view.patch.diff new file mode 100644 index 0000000..8f6bbfb --- /dev/null +++ b/gtk3-filechooser-icon-view.patch.diff @@ -0,0 +1,1055 @@ +Last-modified: 2023-03-24 +Author: bgstack15 +Message: Adapt https://gist.github.com/Dudemanguy/c172394e30e1e7d0f477ad15c719bc71/raw/8f2e9fb36d736b600030a2db24a26304654f5e17/gtk3-filechooser-icon-view.patch to gtk3classic, attempt 1. This diff is the difference between the file stored in this git repo from the dudemanguy gist repo. +--- ../gtk3classic/gtk3-filechooser-icon-view.patch 2023-03-24 09:13:38.020372785 -0400 ++++ debian/patches/gtk3-filechooser-icon-view.patch 2023-03-24 09:23:58.530067566 -0400 +@@ -1,5 +1,3 @@ +-diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h +-index a0a622c111..2af859433d 100644 + --- a/gtk/gtkfilechooserprivate.h + +++ b/gtk/gtkfilechooserprivate.h + @@ -32,10 +32,14 @@ +@@ -93,11 +91,9 @@ + GSList * _gtk_file_chooser_list_shortcut_folder_files (GtkFileChooser *chooser); + + +-diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c +-index d75a3f7857..623c71e84a 100644 + --- a/gtk/gtkfilechooserwidget.c + +++ b/gtk/gtkfilechooserwidget.c +-@@ -44,10 +44,12 @@ ++@@ -45,10 +45,12 @@ + #include "gtkfilesystemmodel.h" + #include "gtkgrid.h" + #include "gtkicontheme.h" +@@ -110,27 +106,27 @@ + #include "gtkpaned.h" + #include "gtkpathbar.h" + #include "gtkplacessidebar.h" +-@@ -81,6 +83,7 @@ +- #include "gtkgesturelongpress.h" ++@@ -84,6 +86,7 @@ ++ #include "gtkcssprovider.h" + + #include + +#include + + #ifdef HAVE_UNISTD_H + #include +-@@ -198,6 +201,11 @@ typedef enum { +- STARTUP_MODE_CWD ++@@ -202,6 +205,11 @@ typedef enum { + } StartupMode; + +-+typedef enum { ++ typedef enum { + + VIEW_MODE_LIST, + + VIEW_MODE_ICON, + +} ViewMode; + + +- typedef enum { +++typedef enum { + CLOCK_FORMAT_24, + CLOCK_FORMAT_12 +-@@ -228,8 +236,12 @@ struct _GtkFileChooserWidgetPrivate { ++ } ClockFormat; ++@@ -231,8 +239,12 @@ struct _GtkFileChooserWidgetPrivate { + GtkWidget *browse_header_revealer; + GtkWidget *browse_header_stack; + GtkWidget *browse_files_stack; +@@ -144,7 +140,7 @@ + GtkWidget *remote_warning_bar; + + GtkWidget *browse_files_popover; +-@@ -245,6 +257,12 @@ struct _GtkFileChooserWidgetPrivate { ++@@ -248,6 +260,12 @@ struct _GtkFileChooserWidgetPrivate { + GtkWidget *delete_file_item; + GtkWidget *sort_directories_item; + GtkWidget *show_time_item; +@@ -157,7 +153,7 @@ + + GtkWidget *browse_new_folder_button; + GtkSizeGroup *browse_path_bar_size_group; +-@@ -261,6 +279,7 @@ struct _GtkFileChooserWidgetPrivate { ++@@ -264,6 +282,7 @@ struct _GtkFileChooserWidgetPrivate { + + GtkGesture *long_press_gesture; + +@@ -165,7 +161,7 @@ + GtkFileSystemModel *browse_files_model; + char *browse_files_last_selected_name; + +-@@ -348,10 +367,17 @@ struct _GtkFileChooserWidgetPrivate { ++@@ -351,10 +370,17 @@ struct _GtkFileChooserWidgetPrivate { + guint location_changed_id; + + gulong settings_signal_id; +@@ -184,7 +180,7 @@ + gulong toplevel_set_focus_id; + GtkWidget *toplevel_last_focus_widget; + +-@@ -419,7 +445,8 @@ enum { ++@@ -422,7 +448,8 @@ enum { + MODEL_COL_NAME_COLLATED, + MODEL_COL_IS_FOLDER, + MODEL_COL_IS_SENSITIVE, +@@ -194,7 +190,7 @@ + MODEL_COL_SIZE_TEXT, + MODEL_COL_DATE_TEXT, + MODEL_COL_TIME_TEXT, +-@@ -439,7 +466,8 @@ enum { ++@@ -442,7 +469,8 @@ enum { + G_TYPE_STRING, /* MODEL_COL_NAME_COLLATED */ \ + G_TYPE_BOOLEAN, /* MODEL_COL_IS_FOLDER */ \ + G_TYPE_BOOLEAN, /* MODEL_COL_IS_SENSITIVE */ \ +@@ -204,7 +200,7 @@ + G_TYPE_STRING, /* MODEL_COL_SIZE_TEXT */ \ + G_TYPE_STRING, /* MODEL_COL_DATE_TEXT */ \ + G_TYPE_STRING, /* MODEL_COL_TIME_TEXT */ \ +-@@ -449,7 +477,10 @@ enum { ++@@ -452,7 +480,10 @@ enum { + #define DEFAULT_RECENT_FILES_LIMIT 50 + + /* Icon size for if we can't get it from the theme */ +@@ -216,7 +212,7 @@ + + #define PREVIEW_HBOX_SPACING 12 + #define NUM_LINES 45 +-@@ -570,7 +601,7 @@ static gboolean list_select_func (GtkTreeSelection *selection, ++@@ -573,7 +604,7 @@ static gboolean list_select_func (GtkT + gboolean path_currently_selected, + gpointer data); + +@@ -225,7 +221,7 @@ + GtkFileChooserWidget *impl); + static void list_row_activated (GtkTreeView *tree_view, + GtkTreePath *path, +-@@ -578,6 +609,13 @@ static void list_row_activated (GtkTreeView *tree_view, ++@@ -581,6 +612,13 @@ static void list_row_activated ( + GtkFileChooserWidget *impl); + static void list_cursor_changed (GtkTreeView *treeview, + GtkFileChooserWidget *impl); +@@ -239,7 +235,7 @@ + + static void path_bar_clicked (GtkPathBar *path_bar, + GFile *file, +-@@ -590,6 +628,13 @@ static void update_cell_renderer_attributes (GtkFileChooserWidget *impl); ++@@ -593,6 +631,13 @@ static void update_cell_renderer_attribu + static void load_remove_timer (GtkFileChooserWidget *impl, LoadState new_load_state); + static void browse_files_center_selected_row (GtkFileChooserWidget *impl); + +@@ -253,7 +249,7 @@ + static void location_switch_to_path_bar (GtkFileChooserWidget *impl); + + static void stop_loading_and_clear_list_model (GtkFileChooserWidget *impl, +-@@ -619,6 +664,26 @@ static gboolean recent_should_respond (GtkFileChooserWidget *impl); ++@@ -622,6 +667,26 @@ static gboolean recent_should_respond + static void set_file_system_backend (GtkFileChooserWidget *impl); + static void unset_file_system_backend (GtkFileChooserWidget *impl); + +@@ -280,7 +276,7 @@ + static void clear_model_cache (GtkFileChooserWidget *impl, + gint column); + static void set_model_filter (GtkFileChooserWidget *impl, +-@@ -956,7 +1021,7 @@ update_preview_widget_visibility (GtkFileChooserWidget *impl) ++@@ -959,7 +1024,7 @@ update_preview_widget_visibility (GtkFil + } + } + +@@ -289,7 +285,7 @@ + gtk_widget_show (priv->preview_box); + else + gtk_widget_hide (priv->preview_box); +-@@ -1224,19 +1289,16 @@ selection_check (GtkFileChooserWidget *impl, ++@@ -1227,19 +1292,16 @@ selection_check (GtkFileChooserWidget *i + gboolean *all_files, + gboolean *all_folders) + { +@@ -312,7 +308,7 @@ + + g_assert (closure.num_selected == 0 || !(closure.all_files && closure.all_folders)); + +-@@ -1361,7 +1423,7 @@ browse_files_key_press_event_cb (GtkWidget *widget, ++@@ -1367,7 +1429,7 @@ browse_files_key_press_event_cb (GtkWidg + return TRUE; + } + +@@ -321,7 +317,7 @@ + { + if (gtk_widget_child_focus (priv->places_sidebar, GTK_DIR_LEFT)) + return TRUE; +-@@ -1464,12 +1526,8 @@ add_to_shortcuts_cb (GSimpleAction *action, ++@@ -1470,12 +1532,8 @@ add_to_shortcuts_cb (GSimpleAction *acti + gpointer data) + { + GtkFileChooserWidget *impl = data; +@@ -335,7 +331,7 @@ + add_bookmark_foreach_cb, + impl); + } +-@@ -1842,6 +1900,86 @@ open_folder_cb (GSimpleAction *action, ++@@ -1848,6 +1906,86 @@ open_folder_cb (GSimpleAction *action, + } + G_GNUC_END_IGNORE_DEPRECATIONS + +@@ -422,7 +418,7 @@ + /* callback used when the "Show Hidden Files" menu item is toggled */ + static void + change_show_hidden_state (GSimpleAction *action, +-@@ -2169,6 +2307,7 @@ check_file_list_popover_sensitivity (GtkFileChooserWidget *impl) ++@@ -2175,6 +2313,7 @@ check_file_list_popover_sensitivity (Gtk + gboolean all_files; + gboolean all_folders; + gboolean active; +@@ -430,7 +426,7 @@ + GActionGroup *actions; + GAction *action, *action2; + +-@@ -2177,6 +2316,7 @@ check_file_list_popover_sensitivity (GtkFileChooserWidget *impl) ++@@ -2183,6 +2322,7 @@ check_file_list_popover_sensitivity (Gtk + selection_check (impl, &num_selected, &all_files, &all_folders); + + active = (num_selected != 0); +@@ -438,7 +434,7 @@ + + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "copy-location"); + g_simple_action_set_enabled (G_SIMPLE_ACTION (action), active); +-@@ -2190,6 +2330,21 @@ check_file_list_popover_sensitivity (GtkFileChooserWidget *impl) ++@@ -2196,6 +2336,21 @@ check_file_list_popover_sensitivity (Gtk + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "open"); + g_simple_action_set_enabled (G_SIMPLE_ACTION (action), (num_selected == 1) && all_folders); + +@@ -460,7 +456,7 @@ + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "rename"); + if (num_selected == 1) + { +-@@ -2255,6 +2410,11 @@ static GActionEntry entries[] = { ++@@ -2261,6 +2416,11 @@ static GActionEntry entries[] = { + { "rename", rename_file_cb, NULL, NULL, NULL }, + { "delete", delete_file_cb, NULL, NULL, NULL }, + { "trash", trash_file_cb, NULL, NULL, NULL }, +@@ -472,10 +468,10 @@ + { "toggle-show-hidden", NULL, NULL, "false", change_show_hidden_state }, + { "toggle-show-size", NULL, NULL, "false", change_show_size_state }, + { "toggle-show-type", NULL, NULL, "false", change_show_type_state }, +-@@ -2280,15 +2440,9 @@ append_separator (GtkWidget *box) +- { +- GtkWidget *separator; +- ++@@ -2290,17 +2450,6 @@ append_separator (GtkWidget *box) ++ gtk_widget_set_visible (GTK_WIDGET (separator), TRUE); ++ gtk_menu_shell_append (GTK_MENU_SHELL (box), separator); ++ return separator; + - separator = g_object_new (GTK_TYPE_SEPARATOR, + - "orientation", GTK_ORIENTATION_HORIZONTAL, + - "visible", TRUE, +@@ -485,33 +481,27 @@ + - "margin-bottom", 6, + - NULL); + - gtk_container_add (GTK_CONTAINER (box), separator); +-+ separator = gtk_separator_menu_item_new (); +-+ gtk_widget_set_visible (GTK_WIDGET (separator), TRUE); +-+ gtk_menu_shell_append (GTK_MENU_SHELL (box), separator); +- +- return separator; ++- ++- return separator; + } +-@@ -2301,12 +2455,13 @@ add_button (GtkWidget *box, +- { +- GtkWidget *item; + ++ /* Constructs the popup menu for the file list if needed */ ++@@ -2319,14 +2468,6 @@ add_button (GtkWidget *box, ++ gtk_widget_set_visible (GTK_WIDGET (item), TRUE); ++ gtk_menu_shell_append (GTK_MENU_SHELL (box), item); ++ return item; + - item = g_object_new (GTK_TYPE_MODEL_BUTTON, + - "visible", TRUE, + - "action-name", action, + - "text", label, + - NULL); + - gtk_container_add (GTK_CONTAINER (box), item); +-+ if (g_str_match_string ("toggle", action, TRUE)) +-+ item = gtk_check_menu_item_new_with_mnemonic (label); +-+ else +-+ item = gtk_menu_item_new_with_mnemonic (label); +-+ g_object_set (G_OBJECT (item), "action-name", action, NULL); +-+ gtk_widget_set_visible (GTK_WIDGET (item), TRUE); +-+ gtk_menu_shell_append (GTK_MENU_SHELL (box), item); +- +- return item; ++- ++- return item; + } +-@@ -2320,11 +2475,9 @@ file_list_build_popover (GtkFileChooserWidget *impl) ++ ++ static void ++@@ -2338,11 +2479,6 @@ file_list_build_popover (GtkFileChooserW + if (priv->browse_files_popover) + return; + +@@ -520,13 +510,10 @@ + - g_object_set (box, "margin", 10, NULL); + - gtk_widget_show (box); + - gtk_container_add (GTK_CONTAINER (priv->browse_files_popover), box); +-+ priv->browse_files_popover = gtk_menu_new (); +-+ gtk_menu_attach_to_widget (GTK_MENU (priv->browse_files_popover), GTK_WIDGET (priv->browse_files_tree_view), NULL); +-+ box = priv->browse_files_popover; +- +- priv->visit_file_item = add_button (box, _("_Visit File"), "item.visit"); +- priv->open_folder_item = add_button (box, _("_Open With File Manager"), "item.open"); +-@@ -2336,11 +2489,29 @@ file_list_build_popover (GtkFileChooserWidget *impl) ++ priv->browse_files_popover = gtk_menu_new (); ++ gtk_menu_attach_to_widget (GTK_MENU (priv->browse_files_popover), GTK_WIDGET (priv->browse_files_tree_view), NULL); ++ box = priv->browse_files_popover; ++@@ -2357,11 +2493,29 @@ file_list_build_popover (GtkFileChooserW + + append_separator (box); + +@@ -558,10 +545,10 @@ + + priv->hidden_files_item = add_button (box, _("Show _Hidden Files"), "item.toggle-show-hidden"); + + priv->sort_directories_item = add_button (box, _("Sort _Folders before Files"), "item.toggle-sort-dirs-first"); + + } +- } +- +- /* Updates the popover for the file list, creating it if necessary */ +-@@ -2392,39 +2563,11 @@ file_list_show_popover (GtkFileChooserWidget *impl, ++ g_object_set (priv->visit_file_item, "image", gtk_image_new_from_icon_name ("gtk-jump-to", GTK_ICON_SIZE_MENU), NULL); ++ g_object_set (priv->open_folder_item, "image", gtk_image_new_from_icon_name ("gtk-open", GTK_ICON_SIZE_MENU), NULL); ++ g_object_set (priv->copy_file_location_item, "image", gtk_image_new_from_icon_name ("gtk-copy", GTK_ICON_SIZE_MENU), NULL); ++@@ -2419,41 +2573,10 @@ file_list_show_popover (GtkFileChooserWi + gdouble y) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -573,7 +560,9 @@ + - + + file_list_update_popover (impl); +- ++ gtk_menu_popup_at_pointer (GTK_MENU (priv->browse_files_popover), NULL); ++ return; ++- + - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); + - list = gtk_tree_selection_get_selected_rows (selection, &model); + - if (list) +@@ -598,12 +587,10 @@ + - + - gtk_popover_set_pointing_to (GTK_POPOVER (priv->browse_files_popover), &rect); + - gtk_popover_popup (GTK_POPOVER (priv->browse_files_popover)); +-+ gtk_menu_popup_at_pointer (GTK_MENU (priv->browse_files_popover), NULL); +-+ return; + } + + /* Callback used for the GtkWidget::popup-menu signal of the file list */ +-@@ -2461,7 +2604,7 @@ list_button_press_event_cb (GtkWidget *widget, ++@@ -2490,7 +2613,7 @@ list_button_press_event_cb (GtkWidget + return FALSE; + + in_press = TRUE; +@@ -612,14 +599,14 @@ + in_press = FALSE; + + file_list_show_popover (impl, event->x, event->y); +-@@ -2492,13 +2635,16 @@ file_list_set_sort_column_ids (GtkFileChooserWidget *impl) ++@@ -2521,13 +2644,16 @@ file_list_set_sort_column_ids (GtkFileCh + { + GtkFileChooserWidgetPrivate *priv = impl->priv; + +-- gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), -1); ++- gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), 0); + + if (priv->view_mode == VIEW_MODE_LIST) + + { +-+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), -1); +++ gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), 0); + + - gtk_tree_view_column_set_sort_column_id (priv->list_name_column, MODEL_COL_NAME); + - gtk_tree_view_column_set_sort_column_id (priv->list_time_column, MODEL_COL_TIME); +@@ -635,7 +622,7 @@ + } + + static gboolean +-@@ -2521,11 +2667,22 @@ file_list_query_tooltip_cb (GtkWidget *widget, ++@@ -2550,11 +2676,22 @@ file_list_query_tooltip_cb (GtkWidget * + return FALSE; + + +@@ -663,7 +650,7 @@ + + gtk_tree_model_get (model, &iter, + MODEL_COL_FILE, &file, +-@@ -2539,10 +2696,18 @@ file_list_query_tooltip_cb (GtkWidget *widget, ++@@ -2568,10 +2705,18 @@ file_list_query_tooltip_cb (GtkWidget * + + filename = g_file_get_path (file); + gtk_tooltip_set_text (tooltip, filename); +@@ -686,7 +673,7 @@ + g_free (filename); + g_object_unref (file); + gtk_tree_path_free (path); +-@@ -2558,8 +2723,8 @@ set_icon_cell_renderer_fixed_size (GtkFileChooserWidget *impl) ++@@ -2587,8 +2732,8 @@ set_icon_cell_renderer_fixed_size (GtkFi + + gtk_cell_renderer_get_padding (priv->list_pixbuf_renderer, &xpad, &ypad); + gtk_cell_renderer_set_fixed_size (priv->list_pixbuf_renderer, +@@ -697,7 +684,7 @@ + } + + static gboolean +-@@ -2843,7 +3008,7 @@ location_mode_set (GtkFileChooserWidget *impl, ++@@ -2872,7 +3017,7 @@ location_mode_set (GtkFileChooserWidget + location_switch_to_path_bar (impl); + + if (switch_to_file_list) +@@ -706,7 +693,7 @@ + + break; + +-@@ -2914,6 +3079,119 @@ location_toggle_popup_handler (GtkFileChooserWidget *impl) ++@@ -2943,6 +3088,119 @@ location_toggle_popup_handler (GtkFileCh + } + } + +@@ -826,7 +813,7 @@ + static void + gtk_file_chooser_widget_constructed (GObject *object) + { +-@@ -3022,18 +3300,11 @@ set_select_multiple (GtkFileChooserWidget *impl, ++@@ -3051,18 +3309,11 @@ set_select_multiple (GtkFileChooserWidge + gboolean property_notify) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -846,7 +833,7 @@ + + priv->select_multiple = select_multiple; + g_object_notify (G_OBJECT (impl), "select-multiple"); +-@@ -3160,6 +3431,7 @@ operation_mode_set_enter_location (GtkFileChooserWidget *impl) ++@@ -3189,6 +3440,7 @@ operation_mode_set_enter_location (GtkFi + gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_header_stack), "location"); + gtk_revealer_set_reveal_child (GTK_REVEALER (priv->browse_header_revealer), TRUE); + location_bar_update (impl); +@@ -854,7 +841,7 @@ + gtk_widget_set_sensitive (priv->filter_combo, TRUE); + location_mode_set (impl, LOCATION_MODE_FILENAME_ENTRY); + } +-@@ -3189,7 +3461,7 @@ operation_mode_set_search (GtkFileChooserWidget *impl) ++@@ -3218,7 +3470,7 @@ operation_mode_set_search (GtkFileChoose + visible_widget = gtk_stack_get_visible_child (GTK_STACK (priv->browse_files_stack)); + + if (visible_widget != priv->places_view && +@@ -863,7 +850,7 @@ + { + gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "list"); + } +-@@ -3314,6 +3586,12 @@ update_appearance (GtkFileChooserWidget *impl) ++@@ -3343,6 +3595,12 @@ update_appearance (GtkFileChooserWidget + location_mode_set (impl, priv->location_mode); + } + +@@ -876,7 +863,7 @@ + if (priv->location_entry) + _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (priv->location_entry), priv->action); + +-@@ -3322,7 +3600,7 @@ update_appearance (GtkFileChooserWidget *impl) ++@@ -3351,7 +3609,7 @@ update_appearance (GtkFileChooserWidget + /* 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. + */ +@@ -885,7 +872,7 @@ + + emit_default_size_changed (impl); + } +-@@ -3752,14 +4030,27 @@ change_icon_theme (GtkFileChooserWidget *impl) ++@@ -3781,14 +4039,27 @@ change_icon_theme (GtkFileChooserWidget + profile_start ("start", NULL); + + if (gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height)) +@@ -918,7 +905,7 @@ + gtk_widget_queue_resize (priv->browse_files_tree_view); + + profile_end ("end", NULL); +-@@ -3860,7 +4151,7 @@ set_sort_column (GtkFileChooserWidget *impl) ++@@ -3889,7 +4160,7 @@ set_sort_column (GtkFileChooserWidget *i + GtkFileChooserWidgetPrivate *priv = impl->priv; + GtkTreeSortable *sortable; + +@@ -927,7 +914,7 @@ + + /* can happen when we're still populating the model */ + if (sortable == NULL) +-@@ -3875,6 +4166,7 @@ static void ++@@ -3904,6 +4175,7 @@ static void + settings_load (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -935,7 +922,7 @@ + gboolean show_hidden; + gboolean show_size_column; + gboolean show_type_column; +-@@ -3882,6 +4174,7 @@ settings_load (GtkFileChooserWidget *impl) ++@@ -3911,6 +4183,7 @@ settings_load (GtkFileChooserWidget *imp + DateFormat date_format; + TypeFormat type_format; + gint sort_column; +@@ -943,7 +930,7 @@ + GtkSortType sort_order; + StartupMode startup_mode; + gint sidebar_width; +-@@ -3889,6 +4182,8 @@ settings_load (GtkFileChooserWidget *impl) ++@@ -3918,6 +4191,8 @@ settings_load (GtkFileChooserWidget *imp + + settings = _gtk_file_chooser_get_settings_for_widget (GTK_WIDGET (impl)); + +@@ -952,7 +939,7 @@ + show_hidden = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN); + show_size_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN); + show_type_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_TYPE_COLUMN); +-@@ -3900,12 +4195,20 @@ settings_load (GtkFileChooserWidget *impl) ++@@ -3929,12 +4204,20 @@ settings_load (GtkFileChooserWidget *imp + date_format = g_settings_get_enum (settings, SETTINGS_KEY_DATE_FORMAT); + type_format = g_settings_get_enum (settings, SETTINGS_KEY_TYPE_FORMAT); + +@@ -976,7 +963,7 @@ + + priv->sort_column = sort_column; + priv->sort_order = sort_order; +-@@ -3934,6 +4237,8 @@ settings_save (GtkFileChooserWidget *impl) ++@@ -3963,6 +4246,8 @@ settings_save (GtkFileChooserWidget *imp + /* All the other state */ + + g_settings_set_enum (settings, SETTINGS_KEY_LOCATION_MODE, priv->location_mode); +@@ -985,7 +972,7 @@ + g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN, + gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl))); + g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN, priv->show_size_column); +-@@ -4445,10 +4750,14 @@ load_set_model (GtkFileChooserWidget *impl) ++@@ -4474,10 +4759,14 @@ load_set_model (GtkFileChooserWidget *im + g_assert (priv->browse_files_model != NULL); + + profile_msg (" gtk_tree_view_set_model start", NULL); +@@ -1004,7 +991,7 @@ + set_sort_column (impl); + profile_msg (" gtk_tree_view_set_model end", NULL); + priv->list_sort_ascending = TRUE; +-@@ -4528,7 +4837,7 @@ browse_files_select_first_row (GtkFileChooserWidget *impl) ++@@ -4557,7 +4846,7 @@ browse_files_select_first_row (GtkFileCh + GtkTreeIter dummy_iter; + GtkTreeModel *tree_model; + +@@ -1013,7 +1000,7 @@ + + if (!tree_model) + return; +-@@ -4547,8 +4856,7 @@ browse_files_select_first_row (GtkFileChooserWidget *impl) ++@@ -4576,8 +4865,7 @@ browse_files_select_first_row (GtkFileCh + */ + priv->auto_selecting_first_row = TRUE; + +@@ -1023,7 +1010,7 @@ + priv->auto_selecting_first_row = FALSE; + } + gtk_tree_path_free (path); +-@@ -4574,7 +4882,13 @@ center_selected_row_foreach_cb (GtkTreeModel *model, ++@@ -4603,7 +4891,13 @@ center_selected_row_foreach_cb (GtkTreeM + if (closure->already_centered) + return; + +@@ -1038,7 +1025,7 @@ + closure->already_centered = TRUE; + } + +-@@ -4582,15 +4896,11 @@ center_selected_row_foreach_cb (GtkTreeModel *model, ++@@ -4611,15 +4905,11 @@ center_selected_row_foreach_cb (GtkTreeM + static void + browse_files_center_selected_row (GtkFileChooserWidget *impl) + { +@@ -1055,7 +1042,7 @@ + } + + static gboolean +-@@ -4598,7 +4908,6 @@ show_and_select_files (GtkFileChooserWidget *impl, ++@@ -4627,7 +4917,6 @@ show_and_select_files (GtkFileChooserWid + GSList *files) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -1063,7 +1050,7 @@ + GtkFileSystemModel *fsmodel; + gboolean enabled_hidden, removed_filters; + gboolean selected_a_file; +-@@ -4607,8 +4916,7 @@ show_and_select_files (GtkFileChooserWidget *impl, ++@@ -4636,8 +4925,7 @@ show_and_select_files (GtkFileChooserWid + g_assert (priv->load_state == LOAD_FINISHED); + g_assert (priv->browse_files_model != NULL); + +@@ -1073,7 +1060,7 @@ + + g_assert (fsmodel == priv->browse_files_model); + +-@@ -4663,11 +4971,10 @@ show_and_select_files (GtkFileChooserWidget *impl, ++@@ -4692,11 +4980,10 @@ show_and_select_files (GtkFileChooserWid + { + GtkTreePath *path; + +@@ -1087,7 +1074,7 @@ + gtk_tree_path_free (path); + + selected_a_file = TRUE; +-@@ -4818,12 +5125,15 @@ stop_loading_and_clear_list_model (GtkFileChooserWidget *impl, ++@@ -4847,12 +5134,15 @@ stop_loading_and_clear_list_model (GtkFi + { + GtkFileChooserWidgetPrivate *priv = impl->priv; + +@@ -1104,11 +1091,10 @@ + } + + /* Replace 'target' with 'replacement' in the input string. */ +-@@ -5093,6 +5403,18 @@ end: +- return g_strdup (""); ++@@ -5123,6 +5413,18 @@ end: + } + +-+static gboolean ++ static gboolean + +get_visible_range (GtkTreePath **start, GtkTreePath **end, + + GtkFileChooserWidget *impl) + +{ +@@ -1120,10 +1106,11 @@ + + g_assert_not_reached (); + +} + + +- static gboolean +++static gboolean + file_system_model_set (GtkFileSystemModel *model, + GFile *file, +-@@ -5152,12 +5474,15 @@ file_system_model_set (GtkFileSystemModel *model, ++ GFileInfo *info, ++@@ -5181,12 +5483,15 @@ file_system_model_set (GtkFileSystemMode + else + g_value_set_boolean (value, TRUE); + break; +@@ -1141,7 +1128,7 @@ + } + else + { +-@@ -5211,6 +5536,76 @@ file_system_model_set (GtkFileSystemModel *model, ++@@ -5240,6 +5545,76 @@ file_system_model_set (GtkFileSystemMode + else + g_value_set_boxed (value, NULL); + break; +@@ -1218,7 +1205,7 @@ + case MODEL_COL_SIZE: + g_value_set_int64 (value, info ? g_file_info_get_size (info) : 0); + break; +-@@ -5403,7 +5798,6 @@ static void ++@@ -5432,7 +5807,6 @@ static void + update_chooser_entry (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -1226,7 +1213,7 @@ + struct update_chooser_entry_selected_foreach_closure closure; + + /* no need to update the file chooser's entry if there's no entry */ +-@@ -5420,9 +5814,8 @@ update_chooser_entry (GtkFileChooserWidget *impl) ++@@ -5449,9 +5823,8 @@ update_chooser_entry (GtkFileChooserWidg + + g_assert (priv->location_entry != NULL); + +@@ -1237,7 +1224,7 @@ + + if (closure.num_selected == 0) + { +-@@ -5919,19 +6312,15 @@ gtk_file_chooser_widget_unselect_file (GtkFileChooser *chooser, ++@@ -5948,19 +6321,15 @@ gtk_file_chooser_widget_unselect_file (G + { + GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -1260,7 +1247,7 @@ + } + + static gboolean +-@@ -5942,12 +6331,9 @@ maybe_select (GtkTreeModel *model, ++@@ -5971,12 +6340,9 @@ maybe_select (GtkTreeModel *model, + { + GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (data); + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -1273,7 +1260,7 @@ + gtk_tree_model_get (model, iter, + MODEL_COL_IS_FOLDER, &is_folder, + MODEL_COL_IS_SENSITIVE, &is_sensitive, +-@@ -5956,9 +6342,9 @@ maybe_select (GtkTreeModel *model, ++@@ -5985,9 +6351,9 @@ maybe_select (GtkTreeModel *model, + if (is_sensitive && + ((is_folder && priv->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) || + (!is_folder && priv->action == GTK_FILE_CHOOSER_ACTION_OPEN))) +@@ -1285,7 +1272,7 @@ + + return FALSE; + } +-@@ -5974,8 +6360,15 @@ gtk_file_chooser_widget_select_all (GtkFileChooser *chooser) ++@@ -6003,8 +6369,15 @@ gtk_file_chooser_widget_select_all (GtkF + { + GtkTreeSelection *selection; + +@@ -1303,7 +1290,7 @@ + return; + } + +-@@ -5988,10 +6381,7 @@ static void ++@@ -6017,10 +6390,7 @@ static void + gtk_file_chooser_widget_unselect_all (GtkFileChooser *chooser) + { + GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); +@@ -1315,7 +1302,7 @@ + pending_select_files_free (impl); + } + +-@@ -6147,15 +6537,13 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser) ++@@ -6176,15 +6546,13 @@ gtk_file_chooser_widget_get_files (GtkFi + current_focus = NULL; + + file_list_seen = FALSE; +@@ -1334,7 +1321,7 @@ + + /* If there is no selection in the file list, we probably have this situation: + * +-@@ -6189,7 +6577,7 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser) ++@@ -6218,7 +6586,7 @@ gtk_file_chooser_widget_get_files (GtkFi + else + return NULL; + } +@@ -1343,7 +1330,7 @@ + goto file_list; + else if (priv->location_entry && priv->toplevel_last_focus_widget == priv->location_entry) + goto file_entry; +-@@ -6467,8 +6855,6 @@ switch_folder_foreach_cb (GtkTreeModel *model, ++@@ -6496,8 +6864,6 @@ switch_folder_foreach_cb (GtkTreeModel * + static void + switch_to_selected_folder (GtkFileChooserWidget *impl) + { +@@ -1352,7 +1339,7 @@ + struct switch_folder_closure closure; + + /* We do this with foreach() rather than get_selected() as we may be in +-@@ -6479,8 +6865,7 @@ switch_to_selected_folder (GtkFileChooserWidget *impl) ++@@ -6508,8 +6874,7 @@ switch_to_selected_folder (GtkFileChoose + closure.file = NULL; + closure.num_selected = 0; + +@@ -1362,7 +1349,7 @@ + + g_assert (closure.file && closure.num_selected == 1); + +-@@ -6498,19 +6883,33 @@ get_selected_file_info_from_file_list (GtkFileChooserWidget *impl, ++@@ -6527,19 +6892,33 @@ get_selected_file_info_from_file_list (G + GtkTreeSelection *selection; + GtkTreeIter iter; + GFileInfo *info; +@@ -1404,7 +1391,7 @@ + return info; + } + +-@@ -7007,7 +7406,7 @@ gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed) ++@@ -7036,7 +7415,7 @@ gtk_file_chooser_widget_should_respond ( + + current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel)); + +@@ -1413,7 +1400,7 @@ + { + /* The following array encodes what we do based on the priv->action and the + * number of files selected. +-@@ -7254,9 +7653,9 @@ gtk_file_chooser_widget_initial_focus (GtkFileChooserEmbed *chooser_embed) ++@@ -7283,9 +7662,9 @@ gtk_file_chooser_widget_initial_focus (G + { + if (priv->location_mode == LOCATION_MODE_PATH_BAR + || priv->operation_mode == OPERATION_MODE_RECENT) +@@ -1425,7 +1412,7 @@ + } + else if (priv->action == GTK_FILE_CHOOSER_ACTION_SAVE || + priv->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) +-@@ -7269,6 +7668,7 @@ gtk_file_chooser_widget_initial_focus (GtkFileChooserEmbed *chooser_embed) ++@@ -7298,6 +7677,7 @@ gtk_file_chooser_widget_initial_focus (G + + g_assert (widget != NULL); + gtk_widget_grab_focus (widget); +@@ -1433,7 +1420,7 @@ + } + + static void +-@@ -7292,45 +7692,23 @@ selected_foreach_get_file_cb (GtkTreeModel *model, ++@@ -7321,45 +7701,23 @@ selected_foreach_get_file_cb (GtkTreeMod + static GSList * + get_selected_files (GtkFileChooserWidget *impl) + { +@@ -1481,7 +1468,7 @@ + result = g_slist_reverse (result); + + return result; +-@@ -7402,6 +7780,7 @@ search_engine_finished_cb (GtkSearchEngine *engine, ++@@ -7429,6 +7787,7 @@ search_engine_finished_cb (GtkSearchEngi + gtk_stack_set_visible_child_name (GTK_STACK (priv->browse_files_stack), "empty"); + gtk_entry_grab_focus_without_selecting (GTK_ENTRY (priv->search_entry)); + } +@@ -1489,7 +1476,7 @@ + } + + static void +-@@ -7427,7 +7806,7 @@ search_clear_model (GtkFileChooserWidget *impl, ++@@ -7454,7 +7813,7 @@ search_clear_model (GtkFileChooserWidget + + if (remove && + gtk_tree_view_get_model (GTK_TREE_VIEW (priv->browse_files_tree_view)) == GTK_TREE_MODEL (priv->search_model)) +@@ -1498,7 +1485,7 @@ + + g_clear_object (&priv->search_model); + } +-@@ -7637,7 +8016,7 @@ recent_clear_model (GtkFileChooserWidget *impl, ++@@ -7664,7 +8023,7 @@ recent_clear_model (GtkFileChooserWidget + return; + + if (remove) +@@ -1507,17 +1494,17 @@ + + g_set_object (&priv->recent_model, NULL); + } +-@@ -7690,8 +8069,7 @@ recent_idle_cleanup (gpointer data) ++@@ -7717,8 +8076,7 @@ recent_idle_cleanup (gpointer data) + GtkFileChooserWidget *impl = load_data->impl; + GtkFileChooserWidgetPrivate *priv = impl->priv; + + - gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), + - GTK_TREE_MODEL (priv->recent_model)); + + current_view_set_file_model (impl, GTK_TREE_MODEL (priv->recent_model)); +- gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), -1); ++ gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->browse_files_tree_view), 0); + + gtk_tree_view_column_set_sort_column_id (priv->list_name_column, -1); +-@@ -7839,12 +8217,8 @@ static gboolean ++@@ -7866,12 +8224,8 @@ static gboolean + recent_should_respond (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -1531,7 +1518,7 @@ + } + + static void +-@@ -7904,29 +8278,40 @@ check_preview_change (GtkFileChooserWidget *impl) ++@@ -7931,29 +8285,40 @@ check_preview_change (GtkFileChooserWidg + GtkTreeModel *model; + GtkTreeSelection *selection; + +@@ -1588,7 +1575,7 @@ + { + GtkTreeIter iter; + +-@@ -8010,15 +8395,13 @@ list_select_func (GtkTreeSelection *selection, ++@@ -8037,15 +8402,13 @@ list_select_func (GtkTreeSelection *sele + return TRUE; + } + +@@ -1607,11 +1594,10 @@ + if (priv->location_entry) + update_chooser_entry (impl); + +-@@ -8042,16 +8425,35 @@ list_row_activated (GtkTreeView *tree_view, +- GtkTreePath *path, ++@@ -8070,15 +8433,34 @@ list_row_activated (GtkTreeView + GtkTreeViewColumn *column, + GtkFileChooserWidget *impl) +-+{ ++ { + + GtkTreeModel *model; + + model = gtk_tree_view_get_model (tree_view); + + item_activated (model, path, impl); +@@ -1633,7 +1619,7 @@ + +item_activated (GtkTreeModel *model, + + GtkTreePath *path, + + GtkFileChooserWidget *impl) +- { +++{ + GtkFileChooserWidgetPrivate *priv = impl->priv; + GFile *file; + GtkTreeIter iter; +@@ -1646,7 +1632,7 @@ + if (!gtk_tree_model_get_iter (model, &iter, path)) + return; + +-@@ -8071,7 +8473,7 @@ list_row_activated (GtkTreeView *tree_view, ++@@ -8098,7 +8480,7 @@ list_row_activated (GtkTreeView + priv->action == GTK_FILE_CHOOSER_ACTION_SAVE) + g_signal_emit_by_name (impl, "file-activated"); + +@@ -1655,7 +1641,7 @@ + + if (file) + g_object_unref (file); +-@@ -8102,10 +8504,13 @@ static void ++@@ -8129,10 +8511,13 @@ static void + update_cell_renderer_attributes (GtkFileChooserWidget *impl) + { + GtkFileChooserWidgetPrivate *priv = impl->priv; +@@ -1670,7 +1656,7 @@ + "sensitive", MODEL_COL_IS_SENSITIVE, + NULL); + gtk_tree_view_column_set_attributes (priv->list_name_column, +-@@ -8688,15 +9093,19 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class) ++@@ -8711,15 +9096,19 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_stack); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_sidebar); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_view); +@@ -1691,7 +1677,7 @@ + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, preview_box); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, extra_align); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, extra_and_filters); +-@@ -8715,6 +9124,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class) ++@@ -8738,6 +9127,7 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_type_renderer); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_location_column); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_location_renderer); +@@ -1699,7 +1685,7 @@ + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_name_entry); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_create_button); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_error_label); +-@@ -8724,6 +9134,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class) ++@@ -8747,6 +9137,7 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, rename_file_error_label); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, rename_file_popover); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, remote_warning_bar); +@@ -1707,7 +1693,7 @@ + + /* And a *lot* of callbacks to bind ... */ + gtk_widget_class_bind_template_callback (widget_class, browse_files_key_press_event_cb); +-@@ -8738,6 +9149,10 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class) ++@@ -8761,6 +9152,10 @@ gtk_file_chooser_widget_class_init (GtkF + gtk_widget_class_bind_template_callback (widget_class, file_list_drag_end_cb); + gtk_widget_class_bind_template_callback (widget_class, list_selection_changed); + gtk_widget_class_bind_template_callback (widget_class, list_cursor_changed); +@@ -1718,7 +1704,7 @@ + gtk_widget_class_bind_template_callback (widget_class, filter_combo_changed); + gtk_widget_class_bind_template_callback (widget_class, path_bar_clicked); + gtk_widget_class_bind_template_callback (widget_class, places_sidebar_open_location_cb); +-@@ -8785,6 +9200,18 @@ post_process_ui (GtkFileChooserWidget *impl) ++@@ -8810,6 +9205,18 @@ post_process_ui (GtkFileChooserWidget *i + GDK_ACTION_COPY | GDK_ACTION_MOVE); + gtk_drag_dest_add_uri_targets (impl->priv->browse_files_tree_view); + +@@ -1737,7 +1723,7 @@ + /* File browser treemodel columns are shared between GtkFileChooser implementations, + * so we don't set cell renderer attributes in GtkBuilder, but rather keep that + * in code. +-@@ -8816,6 +9243,7 @@ post_process_ui (GtkFileChooserWidget *impl) ++@@ -8841,6 +9248,7 @@ post_process_ui (GtkFileChooserWidget *i + * that priv->icon_size be already setup. + */ + set_icon_cell_renderer_fixed_size (impl); +@@ -1745,7 +1731,7 @@ + + atk_obj = gtk_widget_get_accessible (impl->priv->browse_new_folder_button); + if (GTK_IS_ACCESSIBLE (atk_obj)) +-@@ -8867,7 +9295,8 @@ gtk_file_chooser_widget_init (GtkFileChooserWidget *impl) ++@@ -8902,7 +9310,8 @@ gtk_file_chooser_widget_init (GtkFileCho + priv->show_size_column = TRUE; + priv->show_type_column = TRUE; + priv->type_format = TYPE_FORMAT_MIME; +@@ -1755,7 +1741,7 @@ + priv->load_state = LOAD_EMPTY; + priv->reload_state = RELOAD_EMPTY; + priv->pending_select_files = NULL; +-@@ -8879,6 +9308,7 @@ gtk_file_chooser_widget_init (GtkFileChooserWidget *impl) ++@@ -8914,6 +9323,7 @@ gtk_file_chooser_widget_init (GtkFileCho + priv->create_folders = TRUE; + priv->auto_selecting_first_row = FALSE; + priv->renamed_file = NULL; +@@ -1763,7 +1749,7 @@ + + /* Ensure GTK+ private types used by the template + * definition before calling gtk_widget_init_template() +-@@ -8926,6 +9356,258 @@ gtk_file_chooser_widget_new (GtkFileChooserAction action) ++@@ -8961,6 +9371,258 @@ gtk_file_chooser_widget_new (GtkFileChoo + NULL); + } + +@@ -2022,13 +2008,11 @@ + static void + gtk_file_chooser_widget_add_choice (GtkFileChooser *chooser, + const char *id, +-@@ -9045,4 +9727,3 @@ gtk_file_chooser_widget_get_choice (GtkFileChooser *chooser, ++@@ -9080,4 +9742,3 @@ gtk_file_chooser_widget_get_choice (GtkF + + return NULL; + } + - +-diff --git a/gtk/org.gtk.Settings.FileChooser.gschema.xml b/gtk/org.gtk.Settings.FileChooser.gschema.xml +-index dda603ab61..d0f275a01e 100644 + --- a/gtk/org.gtk.Settings.FileChooser.gschema.xml + +++ b/gtk/org.gtk.Settings.FileChooser.gschema.xml + @@ -55,6 +55,11 @@ +@@ -2121,44 +2105,12 @@ + window. + + +-@@ -129,23 +148,23 @@ +- (-1, -1) +- Window size +- +-- The size (width, height) of the GtkFileChooserDialog's window, in pixels. +-+ The size (width, height) of the GtkFileChooserDialog's window, in pixels. +- +- +- +- 'recent' +- Startup mode +- +-- Either "recent" or "cwd"; controls whether the file chooser +-- starts up showing the list of recently-used files, or the +-- contents of the current working directory. +-+ Either "recent" or "cwd"; controls whether the file chooser +-+ starts up showing the list of recently-used files, or the +-+ contents of the current working directory. +- +- +- +- 148 +- Sidebar width +- +-- Width in pixels of the file chooser's places sidebar. +-+ Width in pixels of the file chooser's places sidebar. +- +- +- +-diff --git a/gtk/ui/gtkfilechooserwidget.ui b/gtk/ui/gtkfilechooserwidget.ui +-index 01d4075f6c..269a95fd4b 100644 + --- a/gtk/ui/gtkfilechooserwidget.ui + +++ b/gtk/ui/gtkfilechooserwidget.ui +-@@ -8,6 +8,56 @@ +- ++@@ -9,6 +9,56 @@ + 1 + vertical +-+ ++ + + + + 1 + + +@@ -2208,10 +2160,11 @@ + + + + + + +- +++ + + 1 +-@@ -156,110 +206,172 @@ ++ ++@@ -187,110 +237,172 @@ + 1 + vertical + +@@ -2458,7 +2411,7 @@ + + + +-@@ -378,7 +490,7 @@ ++@@ -409,7 +521,7 @@ + + + 1 -- cgit