From: Matthias Clasen Date: Thu, 9 Jul 2015 01:31:40 +0000 (-0400) Subject: file chooser: Fix multi-selection X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~24^2~9087 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=0c7237f15ee8271502e99b062cc4780b499d8397;p=gtk4.git file chooser: Fix multi-selection Even if we only ever hit the code with a singleton selection, calling gtk_tree_selection_get_selected is not ok if the tree selection mode allows multi-selection. Replace all calls to gtk_tree_selection_get_selected in the file chooser code with callback loops iterating over the selection. This problem was introduced with the recently added rename and delete menuitems. --- diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c index d6fe28144e..644a97a1d0 100644 --- a/gtk/gtkfilechooserwidget.c +++ b/gtk/gtkfilechooserwidget.c @@ -563,12 +563,14 @@ static void location_switch_to_path_bar (GtkFileChooserWidget *impl); static void stop_loading_and_clear_list_model (GtkFileChooserWidget *impl, gboolean remove_from_treeview); +static GSList *get_selected_files (GtkFileChooserWidget *impl); +static GSList *get_selected_infos (GtkFileChooserWidget *impl); + static void search_setup_widgets (GtkFileChooserWidget *impl); static void search_stop_searching (GtkFileChooserWidget *impl, gboolean remove_query); static void search_clear_model (GtkFileChooserWidget *impl, gboolean remove_from_treeview); -static GSList *search_get_selected_files (GtkFileChooserWidget *impl); static void search_entry_activate_cb (GtkFileChooserWidget *impl); static void search_entry_stop_cb (GtkFileChooserWidget *impl); static void settings_load (GtkFileChooserWidget *impl); @@ -582,7 +584,6 @@ static void recent_stop_loading (GtkFileChooserWidget *impl); static void recent_clear_model (GtkFileChooserWidget *impl, gboolean remove_from_treeview); static gboolean recent_should_respond (GtkFileChooserWidget *impl); -static GSList * recent_get_selected_files (GtkFileChooserWidget *impl); static void set_file_system_backend (GtkFileChooserWidget *impl); static void unset_file_system_backend (GtkFileChooserWidget *impl); @@ -1499,55 +1500,64 @@ G_GNUC_END_IGNORE_DEPRECATIONS return (response == GTK_RESPONSE_ACCEPT); } +static void +delete_selected_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GtkFileChooserWidget *impl = data; + GFile *file; + GFileInfo *info; + GError *error = NULL; + + file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (model), iter); + info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (model), iter); + + if (confirm_delete (impl, info)) + { + if (!g_file_delete (file, NULL, &error)) + error_deleting_file (impl, file, error); + } +} + static void delete_file_cb (GtkMenuItem *item, GtkFileChooserWidget *impl) { GtkFileChooserWidgetPrivate *priv = impl->priv; GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); + gtk_tree_selection_selected_foreach (selection, delete_selected_cb, impl); +} - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - GFile *file; - GFileInfo *info; - GError *error = NULL; +static void +trash_selected_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GtkFileChooserWidget *impl = data; + GFile *file; + GError *error = NULL; - file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (model), &iter); - info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (model), &iter); + file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (model), iter); - if (confirm_delete (impl, info)) - { - if (!g_file_delete (file, NULL, &error)) - error_deleting_file (impl, file, error); - } - } + if (!g_file_trash (file, NULL, &error)) + error_trashing_file (impl, file, error); } + static void trash_file_cb (GtkMenuItem *item, GtkFileChooserWidget *impl) { GtkFileChooserWidgetPrivate *priv = impl->priv; GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); - - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - GFile *file; - GError *error = NULL; - - file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (model), &iter); - - if (!g_file_trash (file, NULL, &error)) - error_trashing_file (impl, file, error); - } + gtk_tree_selection_selected_foreach (selection, trash_selected_cb, impl); } static void @@ -1609,43 +1619,47 @@ rename_file_rename_clicked (GtkButton *button, } static void -rename_file_cb (GtkMenuItem *item, - GtkFileChooserWidget *impl) +rename_selected_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) { + GtkFileChooserWidget *impl = data; GtkFileChooserWidgetPrivate *priv = impl->priv; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreePath *path; GdkRectangle rect; gchar *filename; - /* insensitive until we change the name */ - gtk_widget_set_sensitive (priv->rename_file_rename_button, FALSE); + gtk_tree_model_get (model, iter, + MODEL_COL_FILE, &priv->rename_file_source_file, + -1); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); + gtk_tree_view_get_cell_area (GTK_TREE_VIEW (priv->browse_files_tree_view), + path, priv->list_name_column, &rect); - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - gtk_tree_model_get (model, &iter, - MODEL_COL_FILE, &priv->rename_file_source_file, - -1); + gtk_tree_view_convert_tree_to_widget_coords (GTK_TREE_VIEW (priv->browse_files_tree_view), + rect.x, rect.y, &rect.x, &rect.y); - path = gtk_tree_model_get_path (model, &iter); - gtk_tree_view_get_cell_area (GTK_TREE_VIEW (priv->browse_files_tree_view), - path, priv->list_name_column, &rect); + filename = g_file_get_basename (priv->rename_file_source_file); + gtk_entry_set_text (GTK_ENTRY(priv->rename_file_name_entry), filename); + g_free (filename); - gtk_tree_view_convert_tree_to_widget_coords (GTK_TREE_VIEW (priv->browse_files_tree_view), - rect.x, rect.y, &rect.x, &rect.y); + gtk_popover_set_pointing_to (GTK_POPOVER (priv->rename_file_popover), &rect); + gtk_widget_show (priv->rename_file_popover); + gtk_widget_grab_focus (priv->rename_file_popover); +} - filename = g_file_get_basename (priv->rename_file_source_file); - gtk_entry_set_text (GTK_ENTRY(priv->rename_file_name_entry), filename); - g_free (filename); +static void +rename_file_cb (GtkMenuItem *item, + GtkFileChooserWidget *impl) +{ + GtkFileChooserWidgetPrivate *priv = impl->priv; + GtkTreeSelection *selection; - gtk_popover_set_pointing_to (GTK_POPOVER (priv->rename_file_popover), &rect); - gtk_widget_show (priv->rename_file_popover); - gtk_widget_grab_focus (priv->rename_file_popover); - } + /* insensitive until we change the name */ + gtk_widget_set_sensitive (priv->rename_file_rename_button, FALSE); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); + gtk_tree_selection_selected_foreach (selection, rename_selected_cb, impl); } /* callback used to set data to clipboard */ @@ -1701,8 +1715,7 @@ copy_file_clear_cb (GtkClipboard *clipboard, { GSList *selected_files = data; - g_slist_foreach (selected_files, (GFunc) g_object_unref, NULL); - g_slist_free (selected_files); + g_slist_free_full (selected_files, g_object_unref); } /* Callback used when the "Copy file’s location" menu item is activated */ @@ -1712,7 +1725,7 @@ copy_file_location_cb (GtkMenuItem *item, { GSList *selected_files = NULL; - selected_files = search_get_selected_files (impl); + selected_files = get_selected_files (impl); if (selected_files) { @@ -1746,7 +1759,7 @@ visit_file_cb (GtkMenuItem *item, { GSList *files; - files = search_get_selected_files (impl); + files = get_selected_files (impl); /* Sigh, just use the first one */ if (files) @@ -1767,7 +1780,7 @@ open_folder_cb (GtkMenuItem *item, { GSList *files; - files = search_get_selected_files (impl); + files = get_selected_files (impl); /* Sigh, just use the first one */ if (files) @@ -2101,16 +2114,16 @@ check_file_list_menu_sensitivity (GtkFileChooserWidget *impl) { if (num_selected == 1) { - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; + GSList *infos; GFileInfo *info; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); - gtk_tree_selection_get_selected (selection, &model, &iter); - info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (model), &iter); + infos = get_selected_infos (impl); + info = G_FILE_INFO (infos->data); + gtk_widget_set_sensitive (priv->rename_file_item, g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME)); + + g_slist_free_full (infos, g_object_unref); } else gtk_widget_set_sensitive (priv->rename_file_item, FALSE); @@ -2120,14 +2133,12 @@ check_file_list_menu_sensitivity (GtkFileChooserWidget *impl) { if (num_selected == 1) { - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; + GSList *infos; GFileInfo *info; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); - gtk_tree_selection_get_selected (selection, &model, &iter); - info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (model), &iter); + infos = get_selected_infos (impl); + info = G_FILE_INFO (infos->data); + if (g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)) { gtk_widget_set_sensitive (priv->trash_file_item, TRUE); @@ -2146,6 +2157,8 @@ check_file_list_menu_sensitivity (GtkFileChooserWidget *impl) gtk_widget_set_visible (priv->delete_file_item, FALSE); gtk_widget_set_visible (priv->trash_file_item, TRUE); } + + g_slist_free_full (infos, g_object_unref); } else { @@ -5713,7 +5726,7 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser) info.file_from_entry = NULL; if (priv->operation_mode == OPERATION_MODE_SEARCH) - return search_get_selected_files (impl); + return get_selected_files (impl); if (priv->operation_mode == OPERATION_MODE_RECENT) { @@ -5723,7 +5736,7 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser) goto file_entry; } else - return recent_get_selected_files (impl); + return get_selected_files (impl); } toplevel = get_toplevel (GTK_WIDGET (impl)); @@ -6849,12 +6862,11 @@ gtk_file_chooser_widget_initial_focus (GtkFileChooserEmbed *chooser_embed) gtk_widget_grab_focus (widget); } -/* Callback used from gtk_tree_selection_selected_foreach(); gets the selected GFiles */ static void -search_selected_foreach_get_file_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) +selected_foreach_get_file_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) { GSList **list; GFile *file; @@ -6868,9 +6880,39 @@ search_selected_foreach_get_file_cb (GtkTreeModel *model, *list = g_slist_prepend (*list, file); } -/* Constructs a list of the selected paths in search mode */ static GSList * -search_get_selected_files (GtkFileChooserWidget *impl) +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); + 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; @@ -6879,7 +6921,7 @@ search_get_selected_files (GtkFileChooserWidget *impl) result = NULL; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->browse_files_tree_view)); - gtk_tree_selection_selected_foreach (selection, search_selected_foreach_get_file_cb, &result); + gtk_tree_selection_selected_foreach (selection, selected_foreach_get_info_cb, &result); result = g_slist_reverse (result); return result; @@ -7371,38 +7413,6 @@ recent_start_loading (GtkFileChooserWidget *impl) g_source_set_name_by_id (priv->load_recent_id, "[gtk+] recent_idle_load"); } -static void -recent_selected_foreach_get_file_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer data) -{ - GSList **list; - GFile *file; - - list = data; - - gtk_tree_model_get (model, iter, MODEL_COL_FILE, &file, -1); - *list = g_slist_prepend (*list, file); -} - -/* Constructs a list of the selected paths in recent files mode */ -static GSList * -recent_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, recent_selected_foreach_get_file_cb, &result); - result = g_slist_reverse (result); - - return result; -} - /* Called from ::should_respond(). We return whether there are selected * files in the recent files list. */