diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 5edc931771..b6e9bc06f3 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -1310,7 +1310,7 @@ gtk_file_chooser_get_current_folder gtk_file_chooser_add_filter gtk_file_chooser_remove_filter -gtk_file_chooser_list_filters +gtk_file_chooser_get_filters gtk_file_chooser_set_filter gtk_file_chooser_get_filter diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c index 985a18a1ca..b77652bd1c 100644 --- a/gtk/gtkfilechooser.c +++ b/gtk/gtkfilechooser.c @@ -168,6 +168,38 @@ gtk_file_chooser_default_init (GtkFileChooserInterface *iface) FALSE, GTK_PARAM_READWRITE)); + /** + * GtkFileChooser:filters: + * + * A #GListModel containing the filters that have been + * added with gtk_file_chooser_add_filter(). + * + * The returned object should not be modified. It may + * or may not be updated for later changes. + */ + g_object_interface_install_property (iface, + g_param_spec_object ("filters", + P_("Filters"), + P_("List model of filters"), + G_TYPE_LIST_MODEL, + GTK_PARAM_READABLE)); + + /** + * GtkFileChooser:shortcut-folders: + * + * A #GListModel containing the shortcut folders that have been + * added with gtk_file_chooser_add_shortcut(). + * + * The returned object should not be modified. It may + * or may not be updated for later changes. + */ + g_object_interface_install_property (iface, + g_param_spec_object ("shortcut-folders", + P_("Shortcut Folders"), + P_("List model of shortcut folders"), + G_TYPE_LIST_MODEL, + GTK_PARAM_READABLE)); + /** * GtkFileChooser:create-folders: * @@ -682,23 +714,24 @@ gtk_file_chooser_remove_filter (GtkFileChooser *chooser, } /** - * gtk_file_chooser_list_filters: + * gtk_file_chooser_get_filters: * @chooser: a #GtkFileChooser * - * Lists the current set of user-selectable filters; see + * Gets the current set of user-selectable filters, as a list model; see * gtk_file_chooser_add_filter(), gtk_file_chooser_remove_filter(). * - * Returns: (element-type GtkFileFilter) (transfer container): a - * #GSList containing the current set of user selectable filters. The - * contents of the list are owned by GTK+, but you must free the list - * itself with g_slist_free() when you are done with it. + * You should not modify the returned list model. Future changes to + * @chooser may or may not affect the returned model. + * + * Returns: (transfer full): a #GListModel containing the current set + * of user-selectable filters. **/ -GSList * -gtk_file_chooser_list_filters (GtkFileChooser *chooser) +GListModel * +gtk_file_chooser_get_filters (GtkFileChooser *chooser) { g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL); - return GTK_FILE_CHOOSER_GET_IFACE (chooser)->list_filters (chooser); + return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_filters (chooser); } /** @@ -750,21 +783,23 @@ gtk_file_chooser_get_filter (GtkFileChooser *chooser) } /** - * gtk_file_chooser_list_shortcut_folders: + * gtk_file_chooser_get_shortcut_folders: * @chooser: a #GtkFileChooser * * Queries the list of shortcut folders in the file chooser, as set by * gtk_file_chooser_add_shortcut_folder(). * - * Returns: (nullable) (element-type Gio.File) (transfer full): A list - * of folder filenames, or %NULL if there are no shortcut folders. + * You should not modify the returned list model. Future changes to + * @chooser may or may not affect the returned model. + * + * Returns: (transfer full): A list model of #GFiles */ -GSList * -gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser) +GListModel * +gtk_file_chooser_get_shortcut_folders (GtkFileChooser *chooser) { g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL); - return GTK_FILE_CHOOSER_GET_IFACE (chooser)->list_shortcut_folders (chooser); + return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_shortcut_folders (chooser); } /** diff --git a/gtk/gtkfilechooser.h b/gtk/gtkfilechooser.h index 2aff129c5d..f37aea031e 100644 --- a/gtk/gtkfilechooser.h +++ b/gtk/gtkfilechooser.h @@ -145,18 +145,18 @@ GFile * gtk_file_chooser_get_current_folder (GtkFileChooser *chooser); */ GDK_AVAILABLE_IN_ALL void gtk_file_chooser_add_filter (GtkFileChooser *chooser, - GtkFileFilter *filter); + GtkFileFilter *filter); GDK_AVAILABLE_IN_ALL void gtk_file_chooser_remove_filter (GtkFileChooser *chooser, - GtkFileFilter *filter); + GtkFileFilter *filter); GDK_AVAILABLE_IN_ALL -GSList *gtk_file_chooser_list_filters (GtkFileChooser *chooser); +GListModel *gtk_file_chooser_get_filters (GtkFileChooser *chooser); /* Current filter */ GDK_AVAILABLE_IN_ALL void gtk_file_chooser_set_filter (GtkFileChooser *chooser, - GtkFileFilter *filter); + GtkFileFilter *filter); GDK_AVAILABLE_IN_ALL GtkFileFilter *gtk_file_chooser_get_filter (GtkFileChooser *chooser); @@ -164,14 +164,14 @@ GtkFileFilter *gtk_file_chooser_get_filter (GtkFileChooser *chooser); GDK_AVAILABLE_IN_ALL gboolean gtk_file_chooser_add_shortcut_folder (GtkFileChooser *chooser, - GFile *folder, - GError **error); + GFile *folder, + GError **error); GDK_AVAILABLE_IN_ALL gboolean gtk_file_chooser_remove_shortcut_folder (GtkFileChooser *chooser, - GFile *folder, - GError **error); + GFile *folder, + GError **error); GDK_AVAILABLE_IN_ALL -GSList *gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser); +GListModel *gtk_file_chooser_get_shortcut_folders (GtkFileChooser *chooser); GDK_AVAILABLE_IN_ALL void gtk_file_chooser_add_choice (GtkFileChooser *chooser, diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c index 575079b8da..97bd4eab90 100644 --- a/gtk/gtkfilechooserbutton.c +++ b/gtk/gtkfilechooserbutton.c @@ -1035,6 +1035,8 @@ gtk_file_chooser_button_get_property (GObject *object, case GTK_FILE_CHOOSER_PROP_FILTER: case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE: case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS: + case GTK_FILE_CHOOSER_PROP_FILTERS: + case GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS: g_object_get_property (G_OBJECT (button->chooser), pspec->name, value); break; diff --git a/gtk/gtkfilechoosernativeportal.c b/gtk/gtkfilechoosernativeportal.c index db992b9b5b..d14a28cb34 100644 --- a/gtk/gtkfilechoosernativeportal.c +++ b/gtk/gtkfilechoosernativeportal.c @@ -126,7 +126,7 @@ response_cb (GDBusConnection *connection, if (current_filter) { GtkFileFilter *filter = gtk_file_filter_new_from_gvariant (current_filter); - const gchar *current_filter_name = gtk_file_filter_get_name (filter); + const char *current_filter_name = gtk_file_filter_get_name (filter); /* Try to find the given filter in the list of filters. * Since filters are compared by pointer value, using the passed @@ -137,18 +137,24 @@ response_cb (GDBusConnection *connection, * If there is no match, just set the filter as it was retrieved. */ GtkFileFilter *filter_to_select = filter; - GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self)); - for (GSList *l = filters; l; l = l->next) + GListModel *filters; + guint j, n; + + filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self)); + n = g_list_model_get_n_items (filters); + for (j = 0; j < n; j++) { - GtkFileFilter *f = l->data; + GtkFileFilter *f = g_list_model_get_item (filters, j); if (g_strcmp0 (gtk_file_filter_get_name (f), current_filter_name) == 0) { filter_to_select = f; break; } + g_object_unref (f); } - g_slist_free (filters); + g_object_unref (filters); gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (self), filter_to_select); + g_object_unref (filter_to_select); } g_slist_free_full (self->custom_files, g_object_unref); @@ -264,17 +270,20 @@ open_file_msg_cb (GObject *source_object, static GVariant * get_filters (GtkFileChooser *self) { - GSList *list, *l; + GListModel *filters; + guint n, i; GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa(us))")); - list = gtk_file_chooser_list_filters (self); - for (l = list; l; l = l->next) + filters = gtk_file_chooser_get_filters (self); + n = g_list_model_get_n_items (filters); + for (i = 0; i < n; i++) { - GtkFileFilter *filter = l->data; + GtkFileFilter *filter = g_list_model_get_item (filters, i); g_variant_builder_add (&builder, "@(sa(us))", gtk_file_filter_to_gvariant (filter)); + g_object_unref (filter); } - g_slist_free (list); + g_object_unref (filters); return g_variant_builder_end (&builder); } diff --git a/gtk/gtkfilechoosernativequartz.c b/gtk/gtkfilechoosernativequartz.c index 6ce0e936f7..d7cf4113a4 100644 --- a/gtk/gtkfilechoosernativequartz.c +++ b/gtk/gtkfilechoosernativequartz.c @@ -99,9 +99,10 @@ typedef struct { else [data->panel setAllowedFileTypes:filter]; - GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self)); - data->self->current_filter = g_slist_nth_data (filters, selected_index); - g_slist_free (filters); + GListModel *filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self)); + data->self->current_filter = g_list_model_get_item (filters, selected_index); + g_object_unref (data->self->current_filter); + g_object_unref (filters); g_object_notify (G_OBJECT (data->self), "filter"); } @end @@ -307,13 +308,28 @@ filechooser_quartz_launch (FileChooserQuartzData *data) if (data->self->current_filter) { - GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self)); - gint current_filter_index = g_slist_index (filters, data->self->current_filter); - g_slist_free (filters); + GListModel *filters; + guint i, n; + guint current_filter_index = GTK_INVALID_LIST_POSITION; - if (current_filter_index >= 0) + filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self)); + n = g_list_model_get_n_items (filters); + for (i = 0; i < n; i++) + { + gpointer item = g_list_model_get_item (filters, i); + if (item == data->self->current_filter) + { + g_object_unref (item); + current_filter_index = i; + break; + } + g_object_unref (item); + } + g_object_unref (filters); + + if (current_filter_index != GTK_INVALID_LIST_POSITION) [data->filter_combo_box selectItemAtIndex:current_filter_index]; - else + else [data->filter_combo_box selectItemAtIndex:0]; } else @@ -437,15 +453,15 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self) GtkWindow *transient_for; GtkFileChooserAction action; - GSList *filters, *l; - int n_filters, i; + GListModel *filters; + guint n_filters, i; char *message = NULL; data = g_new0 (FileChooserQuartzData, 1); // examine filters! - filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self)); - n_filters = g_slist_length (filters); + filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self)); + n_filters = g_list_model_get_n_items (filters); if (n_filters > 0) { data->filters = [NSMutableArray arrayWithCapacity:n_filters]; @@ -453,13 +469,17 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self) data->filter_names = [NSMutableArray arrayWithCapacity:n_filters]; [data->filter_names retain]; - for (l = filters, i = 0; l != NULL; l = l->next, i++) + for (i = 0; i < n; i++) { - if (!file_filter_to_quartz (l->data, data->filters, data->filter_names)) + GtkFileFilter *filter = g_list_model_get_item (filters, i); + if (!file_filter_to_quartz (filter, data->filters, data->filter_names)) { filechooser_quartz_data_free (data); + g_object_unref (filter); + g_object_unref (filters); return FALSE; } + g_object_unref (filter); } self->current_filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (self)); } @@ -467,6 +487,8 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self) { self->current_filter = NULL; } + g_object_unref (filters); + self->mode_data = data; data->self = g_object_ref (self); diff --git a/gtk/gtkfilechoosernativewin32.c b/gtk/gtkfilechoosernativewin32.c index 026fcd862b..66157ccd69 100644 --- a/gtk/gtkfilechoosernativewin32.c +++ b/gtk/gtkfilechoosernativewin32.c @@ -66,7 +66,7 @@ typedef struct { char *cancel_label; char *title; - GSList *shortcut_files; + GListModel *shortcut_files; GArray *choices_selections; GFile *current_folder; @@ -244,9 +244,11 @@ ifiledialogevents_OnTypeChange (IFileDialogEvents * self, return S_OK; } fileType--; // fileTypeIndex starts at 1 - GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (events->data->self)); - events->data->self->current_filter = g_slist_nth_data (filters, fileType); - g_slist_free (filters); + GListModel *filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (events->data->self)); + GtkFileFilter *filter = g_list_model_get_item (filters, fileType); + events->data->self->current_filter = filter; + g_object_unref (filter); + g_object_unref (filters); g_object_notify (G_OBJECT (events->data->self), "filter"); return S_OK; } @@ -328,7 +330,7 @@ filechooser_win32_thread_data_free (FilechooserWin32ThreadData *data) g_array_free (data->choices_selections, TRUE); data->choices_selections = NULL; } - g_slist_free_full (data->shortcut_files, g_object_unref); + g_object_unref (data->shortcut_files); g_slist_free_full (data->files, g_object_unref); if (data->self) g_object_unref (data->self); @@ -463,7 +465,7 @@ filechooser_win32_thread (gpointer _data) IFileDialog2 *pfd2 = NULL; DWORD flags; DWORD cookie; - GSList *l; + guint j, n_items; CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); @@ -529,9 +531,11 @@ filechooser_win32_thread (gpointer _data) g_free (label); } - for (l = data->shortcut_files; l != NULL; l = l->next) + n_items = g_list_model_get_n_items (data->shortcut_files); + for (j = 0; j < n_items; j++) { - IShellItem *item = get_shell_item_for_file (l->data); + GFile *file = g_list_model_get_item (data->shortcut_files, j); + IShellItem *item = get_shell_item_for_file (file); if (item) { hr = IFileDialog_AddPlace (pfd, item, FDAP_BOTTOM); @@ -539,6 +543,7 @@ filechooser_win32_thread (gpointer _data) g_warning_hr ("Can't add dialog shortcut", hr); IShellItem_Release (item); } + g_object_unref (file); } if (data->current_file) @@ -591,9 +596,23 @@ filechooser_win32_thread (gpointer _data) if (data->self->current_filter) { - GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self)); - gint current_filter_index = g_slist_index (filters, data->self->current_filter); - g_slist_free (filters); + GListModel *filters; + guint current_filter_index = GTK_INVALID_LIST_POSITION; + + filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self)); + n_items = g_list_model_get_n_items (filters); + for (j = 0; j < n_items; j++) + { + gpointer item = g_list_model_get_item (filters, j); + if (item == data->self->current_filter) + { + current_filter_index = j; + g_object_unref (item); + break; + } + g_object_unref (item); + } + g_object_unref (filters); if (current_filter_index >= 0) hr = IFileDialog_SetFileTypeIndex (pfd, current_filter_index + 1); @@ -617,6 +636,8 @@ filechooser_win32_thread (gpointer _data) hr = IFileDialog_QueryInterface (pfd, &IID_IFileDialogCustomize, (LPVOID *) &pfdc); if (SUCCEEDED (hr)) { + GSList *l; + for (l = data->self->choices; l; l = l->next, dialog_control_id++) { GtkFileChooserNativeChoice *choice = (GtkFileChooserNativeChoice*) l->data; @@ -742,6 +763,8 @@ filechooser_win32_thread (gpointer _data) hr = IFileDialog_QueryInterface (pfd, &IID_IFileDialogCustomize, (LPVOID *) &pfdc); if (SUCCEEDED (hr)) { + GSList *l; + for (l = data->self->choices; l; l = l->next) { GtkFileChooserNativeChoice *choice = (GtkFileChooserNativeChoice*) l->data; @@ -864,21 +887,24 @@ gtk_file_chooser_native_win32_show (GtkFileChooserNative *self) FilechooserWin32ThreadData *data; GtkWindow *transient_for; GtkFileChooserAction action; - GSList *filters, *l; - int n_filters, i; + GListModel *filters; + guint n_filters, i; data = g_new0 (FilechooserWin32ThreadData, 1); - filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self)); - n_filters = g_slist_length (filters); + filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self)); + n_filters = g_list_model_get_n_items (filters); if (n_filters > 0) { data->filters = g_new0 (COMDLG_FILTERSPEC, n_filters + 1); - for (l = filters, i = 0; l != NULL; l = l->next, i++) + for (i = 0; i < n_filters; i++) { - if (!file_filter_to_win32 (l->data, &data->filters[i])) + GtkFileFilter *filter = g_list_model_get_item (filters, i); + if (!file_filter_to_win32 (filter, &data->filters[i])) { + g_object_unref (filter); + g_object_unref (filters); filechooser_win32_thread_data_free (data); return FALSE; } @@ -889,12 +915,13 @@ gtk_file_chooser_native_win32_show (GtkFileChooserNative *self) { self->current_filter = NULL; } + g_object_unref (filters); self->mode_data = data; data->self = g_object_ref (self); data->shortcut_files = - gtk_file_chooser_list_shortcut_folders (GTK_FILE_CHOOSER (self->dialog)); + gtk_file_chooser_get_shortcut_folders (GTK_FILE_CHOOSER (self->dialog)); data->accept_label = translate_mnemonics (self->accept_label); data->cancel_label = translate_mnemonics (self->cancel_label); diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h index 06a49dea03..85e86c8905 100644 --- a/gtk/gtkfilechooserprivate.h +++ b/gtk/gtkfilechooserprivate.h @@ -58,34 +58,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); - 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); + GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser); + void (*add_filter) (GtkFileChooser *chooser, + GtkFileFilter *filter); + void (*remove_filter) (GtkFileChooser *chooser, + GtkFileFilter *filter); + GListModel * (*get_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); - GSList * (*list_shortcut_folders) (GtkFileChooser *chooser); + GFile *file, + GError **error); + GListModel * (*get_shortcut_folders) (GtkFileChooser *chooser); /* Signals */ diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c index afa166056e..d41d9513cb 100644 --- a/gtk/gtkfilechooserutils.c +++ b/gtk/gtkfilechooserutils.c @@ -45,14 +45,14 @@ static void delegate_add_filter (GtkFileChooser *choose GtkFileFilter *filter); static void delegate_remove_filter (GtkFileChooser *chooser, GtkFileFilter *filter); -static GSList * delegate_list_filters (GtkFileChooser *chooser); +static GListModel * delegate_get_filters (GtkFileChooser *chooser); static gboolean delegate_add_shortcut_folder (GtkFileChooser *chooser, GFile *file, GError **error); static gboolean delegate_remove_shortcut_folder (GtkFileChooser *chooser, GFile *file, GError **error); -static GSList * delegate_list_shortcut_folders (GtkFileChooser *chooser); +static GListModel * delegate_get_shortcut_folders (GtkFileChooser *chooser); static void delegate_notify (GObject *object, GParamSpec *pspec, gpointer data); @@ -92,17 +92,23 @@ void _gtk_file_chooser_install_properties (GObjectClass *klass) { g_object_class_override_property (klass, - GTK_FILE_CHOOSER_PROP_ACTION, - "action"); + GTK_FILE_CHOOSER_PROP_ACTION, + "action"); g_object_class_override_property (klass, - GTK_FILE_CHOOSER_PROP_FILTER, - "filter"); + GTK_FILE_CHOOSER_PROP_FILTER, + "filter"); g_object_class_override_property (klass, - GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE, - "select-multiple"); + GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE, + "select-multiple"); g_object_class_override_property (klass, - GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS, - "create-folders"); + GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS, + "create-folders"); + g_object_class_override_property (klass, + GTK_FILE_CHOOSER_PROP_FILTERS, + "filters"); + g_object_class_override_property (klass, + GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS, + "shortcut-folders"); } /** @@ -131,10 +137,10 @@ _gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface) iface->get_file_system = delegate_get_file_system; iface->add_filter = delegate_add_filter; iface->remove_filter = delegate_remove_filter; - iface->list_filters = delegate_list_filters; + iface->get_filters = delegate_get_filters; iface->add_shortcut_folder = delegate_add_shortcut_folder; iface->remove_shortcut_folder = delegate_remove_shortcut_folder; - iface->list_shortcut_folders = delegate_list_shortcut_folders; + iface->get_shortcut_folders = delegate_get_shortcut_folders; iface->add_choice = delegate_add_choice; iface->remove_choice = delegate_remove_choice; iface->set_choice = delegate_set_choice; @@ -241,10 +247,10 @@ delegate_remove_filter (GtkFileChooser *chooser, gtk_file_chooser_remove_filter (get_delegate (chooser), filter); } -static GSList * -delegate_list_filters (GtkFileChooser *chooser) +static GListModel * +delegate_get_filters (GtkFileChooser *chooser) { - return gtk_file_chooser_list_filters (get_delegate (chooser)); + return gtk_file_chooser_get_filters (get_delegate (chooser)); } static gboolean @@ -263,10 +269,10 @@ delegate_remove_shortcut_folder (GtkFileChooser *chooser, return gtk_file_chooser_remove_shortcut_folder (get_delegate (chooser), file, error); } -static GSList * -delegate_list_shortcut_folders (GtkFileChooser *chooser) +static GListModel * +delegate_get_shortcut_folders (GtkFileChooser *chooser) { - return gtk_file_chooser_list_shortcut_folders (get_delegate (chooser)); + return gtk_file_chooser_get_shortcut_folders (get_delegate (chooser)); } static gboolean diff --git a/gtk/gtkfilechooserutils.h b/gtk/gtkfilechooserutils.h index 96f6658d6f..3ca736c996 100644 --- a/gtk/gtkfilechooserutils.h +++ b/gtk/gtkfilechooserutils.h @@ -32,7 +32,9 @@ typedef enum { GTK_FILE_CHOOSER_PROP_FILTER, GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE, GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS, - GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS + GTK_FILE_CHOOSER_PROP_FILTERS, + GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS, + GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS } GtkFileChooserProp; void _gtk_file_chooser_install_properties (GObjectClass *klass); diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c index 48d3185868..3551463c23 100644 --- a/gtk/gtkfilechooserwidget.c +++ b/gtk/gtkfilechooserwidget.c @@ -485,14 +485,14 @@ static void gtk_file_chooser_widget_add_filter (GtkF GtkFileFilter *filter); static void gtk_file_chooser_widget_remove_filter (GtkFileChooser *chooser, GtkFileFilter *filter); -static GSList * gtk_file_chooser_widget_list_filters (GtkFileChooser *chooser); +static GListModel * gtk_file_chooser_widget_get_filters (GtkFileChooser *chooser); static gboolean gtk_file_chooser_widget_add_shortcut_folder (GtkFileChooser *chooser, GFile *file, GError **error); static gboolean gtk_file_chooser_widget_remove_shortcut_folder (GtkFileChooser *chooser, GFile *file, GError **error); -static GSList * gtk_file_chooser_widget_list_shortcut_folders (GtkFileChooser *chooser); +static GListModel * gtk_file_chooser_widget_get_shortcut_folders (GtkFileChooser *chooser); static gboolean gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed); static void gtk_file_chooser_widget_initial_focus (GtkFileChooserEmbed *chooser_embed); @@ -619,10 +619,10 @@ gtk_file_chooser_widget_iface_init (GtkFileChooserIface *iface) iface->get_current_name = gtk_file_chooser_widget_get_current_name; iface->add_filter = gtk_file_chooser_widget_add_filter; iface->remove_filter = gtk_file_chooser_widget_remove_filter; - iface->list_filters = gtk_file_chooser_widget_list_filters; + iface->get_filters = gtk_file_chooser_widget_get_filters; iface->add_shortcut_folder = gtk_file_chooser_widget_add_shortcut_folder; iface->remove_shortcut_folder = gtk_file_chooser_widget_remove_shortcut_folder; - iface->list_shortcut_folders = gtk_file_chooser_widget_list_shortcut_folders; + iface->get_shortcut_folders = gtk_file_chooser_widget_get_shortcut_folders; iface->add_choice = gtk_file_chooser_widget_add_choice; iface->remove_choice = gtk_file_chooser_widget_remove_choice; iface->set_choice = gtk_file_chooser_widget_set_choice; @@ -3072,6 +3072,14 @@ gtk_file_chooser_widget_get_property (GObject *object, g_value_set_boolean (value, impl->create_folders); break; + case GTK_FILE_CHOOSER_PROP_FILTERS: + g_value_set_object (value, impl->filters); + break; + + case GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS: + g_value_take_object (value, gtk_file_chooser_get_shortcut_folders (GTK_FILE_CHOOSER (impl))); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3429,25 +3437,27 @@ set_startup_mode (GtkFileChooserWidget *impl) static gboolean shortcut_exists (GtkFileChooserWidget *impl, GFile *needle) { - GSList *haystack; - GSList *l; + GListModel *haystack; + guint n, i; gboolean exists; exists = FALSE; - haystack = gtk_places_sidebar_list_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar)); - for (l = haystack; l; l = l->next) + haystack = gtk_places_sidebar_get_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar)); + n = g_list_model_get_n_items (haystack); + for (i = 0; i < n; i++) { - GFile *hay; + GFile *hay = g_list_model_get_item (haystack, i); - hay = G_FILE (l->data); if (g_file_equal (hay, needle)) { + g_object_unref (hay); exists = TRUE; break; } + g_object_unref (hay); } - g_slist_free_full (haystack, g_object_unref); + g_object_unref (haystack); return exists; } @@ -5564,6 +5574,8 @@ gtk_file_chooser_widget_add_filter (GtkFileChooser *chooser, set_current_filter (impl, filter); show_filters (impl, TRUE); + + g_object_notify (G_OBJECT (chooser), "filters"); } static void @@ -5597,25 +5609,16 @@ gtk_file_chooser_widget_remove_filter (GtkFileChooser *chooser, if (!impl->filters) show_filters (impl, FALSE); + + g_object_notify (G_OBJECT (chooser), "filters"); } -static GSList * -gtk_file_chooser_widget_list_filters (GtkFileChooser *chooser) +static GListModel * +gtk_file_chooser_widget_get_filters (GtkFileChooser *chooser) { GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); - GSList *filters; - guint i; - filters = NULL; - - for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (impl->filters)); i++) - { - GtkFileFilter *filter = g_list_model_get_item (G_LIST_MODEL (impl->filters), i); - filters = g_slist_append (filters, filter); - g_object_unref (filter); - } - - return filters; + return G_LIST_MODEL (g_object_ref (impl->filters)); } static gboolean @@ -5626,6 +5629,9 @@ gtk_file_chooser_widget_add_shortcut_folder (GtkFileChooser *chooser, GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); gtk_places_sidebar_add_shortcut (GTK_PLACES_SIDEBAR (impl->places_sidebar), file); + + g_object_notify (G_OBJECT (chooser), "shortcut-folders"); + return TRUE; } @@ -5637,15 +5643,18 @@ gtk_file_chooser_widget_remove_shortcut_folder (GtkFileChooser *chooser, GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); gtk_places_sidebar_remove_shortcut (GTK_PLACES_SIDEBAR (impl->places_sidebar), file); + + g_object_notify (G_OBJECT (chooser), "shortcut-folders"); + return TRUE; } -static GSList * -gtk_file_chooser_widget_list_shortcut_folders (GtkFileChooser *chooser) +static GListModel * +gtk_file_chooser_widget_get_shortcut_folders (GtkFileChooser *chooser) { GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser); - return gtk_places_sidebar_list_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar)); + return gtk_places_sidebar_get_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar)); } struct switch_folder_closure { diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c index 3fa3cc5c3e..1131668f58 100644 --- a/gtk/gtkplacessidebar.c +++ b/gtk/gtkplacessidebar.c @@ -162,7 +162,7 @@ struct _GtkPlacesSidebar { GtkWidget *popover; GtkSidebarRow *context_row; - GSList *shortcuts; + GListStore *shortcuts; GDBusProxy *hostnamed_proxy; GCancellable *hostnamed_cancellable; @@ -709,15 +709,25 @@ file_is_shown (GtkPlacesSidebar *sidebar, return found; } +typedef struct +{ + GtkPlacesSidebar *sidebar; + guint position; +} ShortcutData; + static void on_app_shortcuts_query_complete (GObject *source, GAsyncResult *result, gpointer data) { - GtkPlacesSidebar *sidebar = data; + ShortcutData *sdata = data; + GtkPlacesSidebar *sidebar = sdata->sidebar; + guint pos = sdata->position; GFile *file = G_FILE (source); GFileInfo *info; + g_free (sdata); + info = g_file_query_info_finish (file, result, NULL); if (info) @@ -726,20 +736,12 @@ on_app_shortcuts_query_complete (GObject *source, gchar *tooltip; const gchar *name; GIcon *start_icon; - int pos = 0; name = g_file_info_get_display_name (info); start_icon = g_file_info_get_symbolic_icon (info); uri = g_file_get_uri (file); tooltip = g_file_get_parse_name (file); - /* XXX: we could avoid this by using an ancillary closure - * with the index coming from add_application_shortcuts(), - * but in terms of algorithmic overhead, the application - * shortcuts is not going to be really big - */ - pos = g_slist_index (sidebar->shortcuts, file); - add_place (sidebar, PLACES_BUILT_IN, SECTION_COMPUTER, name, start_icon, NULL, uri, @@ -757,11 +759,13 @@ on_app_shortcuts_query_complete (GObject *source, static void add_application_shortcuts (GtkPlacesSidebar *sidebar) { - GSList *l; + guint i, n; - for (l = sidebar->shortcuts; l; l = l->next) + n = g_list_model_get_n_items (G_LIST_MODEL (sidebar->shortcuts)); + for (i = 0; i < n; i++) { - GFile *file = l->data; + GFile *file = g_list_model_get_item (G_LIST_MODEL (sidebar->shortcuts), i); + ShortcutData *data; if (!should_show_file (sidebar, file)) continue; @@ -769,13 +773,16 @@ add_application_shortcuts (GtkPlacesSidebar *sidebar) if (file_is_shown (sidebar, file)) continue; + data = g_new (ShortcutData, 1); + data->sidebar = sidebar; + data->position = i; g_file_query_info_async (file, "standard::display-name,standard::symbolic-icon", G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, sidebar->cancellable, on_app_shortcuts_query_complete, - sidebar); + data); } } @@ -3748,6 +3755,8 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar) sidebar->show_recent = TRUE; sidebar->show_desktop = TRUE; + sidebar->shortcuts = g_list_store_new (G_TYPE_FILE); + create_volume_monitor (sidebar); sidebar->open_flags = GTK_PLACES_OPEN_NORMAL; @@ -4018,9 +4027,7 @@ gtk_places_sidebar_dispose (GObject *object) g_clear_object (&sidebar->current_location); g_clear_pointer (&sidebar->rename_uri, g_free); - - g_slist_free_full (sidebar->shortcuts, g_object_unref); - sidebar->shortcuts = NULL; + g_clear_object (&sidebar->shortcuts); #ifdef HAVE_CLOUDPROVIDERS for (l = cloud_providers_collector_get_providers (sidebar->cloud_manager); @@ -4782,24 +4789,6 @@ gtk_places_sidebar_get_show_trash (GtkPlacesSidebar *sidebar) return sidebar->show_trash; } -static GSList * -find_shortcut_link (GtkPlacesSidebar *sidebar, - GFile *location) -{ - GSList *l; - - for (l = sidebar->shortcuts; l; l = l->next) - { - GFile *shortcut; - - shortcut = G_FILE (l->data); - if (g_file_equal (shortcut, location)) - return l; - } - - return NULL; -} - /* * gtk_places_sidebar_add_shortcut: * @sidebar: a places sidebar @@ -4823,8 +4812,7 @@ gtk_places_sidebar_add_shortcut (GtkPlacesSidebar *sidebar, g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar)); g_return_if_fail (G_IS_FILE (location)); - g_object_ref (location); - sidebar->shortcuts = g_slist_append (sidebar->shortcuts, location); + g_list_store_append (sidebar->shortcuts, location); update_places (sidebar); } @@ -4842,43 +4830,46 @@ void gtk_places_sidebar_remove_shortcut (GtkPlacesSidebar *sidebar, GFile *location) { - GSList *link; - GFile *shortcut; + guint i, n; g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar)); g_return_if_fail (G_IS_FILE (location)); - link = find_shortcut_link (sidebar, location); - if (!link) - return; + n = g_list_model_get_n_items (G_LIST_MODEL (sidebar->shortcuts)); + for (i = 0; i < n; i++) + { + GFile *shortcut = g_list_model_get_item (G_LIST_MODEL (sidebar->shortcuts), i); - shortcut = G_FILE (link->data); - g_object_unref (shortcut); + if (shortcut == location) + { + g_list_store_remove (sidebar->shortcuts, i); + g_object_unref (shortcut); + update_places (sidebar); + return; + } - sidebar->shortcuts = g_slist_delete_link (sidebar->shortcuts, link); - update_places (sidebar); + g_object_unref (shortcut); + } } /* * gtk_places_sidebar_list_shortcuts: * @sidebar: a places sidebar * - * Gets the list of shortcuts. + * Gets the list of shortcuts, as a list model containing #GFile objects. * - * Returns: (element-type GFile) (transfer full): - * A #GSList of #GFile of the locations that have been added as + * You should not modify the returned list model. Future changes to + * @sidebar may or may not affect the returned model. + * + * Returns: (transfer full): a list model of #GFiles that have been added as * application-specific shortcuts with gtk_places_sidebar_add_shortcut(). - * To free this list, you can use - * |[ - * g_slist_free_full (list, (GDestroyNotify) g_object_unref); - * ]| */ -GSList * -gtk_places_sidebar_list_shortcuts (GtkPlacesSidebar *sidebar) +GListModel * +gtk_places_sidebar_get_shortcuts (GtkPlacesSidebar *sidebar) { g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar), NULL); - return g_slist_copy_deep (sidebar->shortcuts, (GCopyFunc) g_object_ref, NULL); + return G_LIST_MODEL (g_object_ref (sidebar->shortcuts)); } /* diff --git a/gtk/gtkplacessidebarprivate.h b/gtk/gtkplacessidebarprivate.h index ec0b35b325..a3b011b612 100644 --- a/gtk/gtkplacessidebarprivate.h +++ b/gtk/gtkplacessidebarprivate.h @@ -92,7 +92,7 @@ void gtk_places_sidebar_add_shortcut (GtkPlacesSideb GFile *location); void gtk_places_sidebar_remove_shortcut (GtkPlacesSidebar *sidebar, GFile *location); -GSList * gtk_places_sidebar_list_shortcuts (GtkPlacesSidebar *sidebar); +GListModel * gtk_places_sidebar_get_shortcuts (GtkPlacesSidebar *sidebar); GFile * gtk_places_sidebar_get_nth_bookmark (GtkPlacesSidebar *sidebar, gint n); diff --git a/tests/testgtk.c b/tests/testgtk.c index 10507a3f3a..50db5c8111 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -5672,15 +5672,19 @@ native_filter_changed (GtkWidget *combo, GtkFileChooserNative *native) { int i; - GSList *filters, *l; + GListModel *filters; GtkFileFilter *filter; i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); - filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (native)); - for (l = filters; l != NULL; l = l->next) - gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (native), l->data); - g_slist_free (filters); + filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (native)); + while (g_list_model_get_n_items (filters) > 0) + { + GtkFileFilter *f = g_list_model_get_item (filters, 0); + gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (native), f); + g_object_unref (f); + } + g_object_unref (filters); switch (i) {