From f7ab6f665d405c0eaa20da4491e4550d867bd9cf Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 26 Jul 2020 09:34:08 -0400 Subject: [PATCH] dropdown: Revise constructors A dropdown without a model is useless, so accept a model and expression in the constructor. Allow them to be NULL, but consume them if given. This makes chained constructors convenient without breaking language bindings. Drop gtk_drop_down_set_from_strings() and instead add gtk_drop_down_new_from_strings(). Update all users. --- demos/gtk-demo/dropdown.c | 2 +- demos/gtk-demo/listview_colors.c | 13 ++---- docs/reference/gtk/gtk4-sections.txt | 2 +- gtk/gtkcustompaperunixdialog.c | 3 +- gtk/gtkdropdown.c | 70 +++++++++++++++------------- gtk/gtkdropdown.h | 6 +-- gtk/gtkfilechooserwidget.c | 7 +-- gtk/gtkprinteroptionwidget.c | 8 ++-- gtk/inspector/controllers.c | 3 +- gtk/inspector/prop-editor.c | 14 ++---- gtk/inspector/size-groups.c | 4 +- gtk/inspector/visual.c | 47 +++++++++---------- tests/testdropdown.c | 6 +-- 13 files changed, 85 insertions(+), 100 deletions(-) diff --git a/demos/gtk-demo/dropdown.c b/demos/gtk-demo/dropdown.c index bf82b9bd95..dcd43203f5 100644 --- a/demos/gtk-demo/dropdown.c +++ b/demos/gtk-demo/dropdown.c @@ -254,7 +254,7 @@ do_dropdown (GtkWidget *do_widget) gtk_widget_set_margin_bottom (box, 10); gtk_window_set_child (GTK_WINDOW (window), box); - button = gtk_drop_down_new (); + button = gtk_drop_down_new (NULL, NULL); model = G_LIST_MODEL (pango_cairo_font_map_get_default ()); gtk_drop_down_set_model (GTK_DROP_DOWN (button), model); diff --git a/demos/gtk-demo/listview_colors.c b/demos/gtk-demo/listview_colors.c index edbdb75c4d..c252aab7dd 100644 --- a/demos/gtk-demo/listview_colors.c +++ b/demos/gtk-demo/listview_colors.c @@ -1003,8 +1003,7 @@ do_listview_colors (GtkWidget *do_widget) g_signal_connect (selection, "items-changed", G_CALLBACK (items_changed_cb), label); gtk_header_bar_pack_start (GTK_HEADER_BAR (header), label); - dropdown = gtk_drop_down_new (); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (dropdown), (const char *[]) { "8", "64", "512", "4096", "32768", "262144", "2097152", "16777216", NULL }); + dropdown = gtk_drop_down_new_from_strings ((const char * const[]) { "8", "64", "512", "4096", "32768", "262144", "2097152", "16777216", NULL }); g_signal_connect (dropdown, "notify::selected", G_CALLBACK (limit_changed_cb), gtk_sort_list_model_get_model (sort_model)); @@ -1082,7 +1081,7 @@ do_listview_colors (GtkWidget *do_widget) g_list_store_append (sorters, multi_sorter); g_object_unref (multi_sorter); - dropdown = gtk_drop_down_new (); + dropdown = gtk_drop_down_new (G_LIST_MODEL (sorters), NULL); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); gtk_box_append (GTK_BOX (box), gtk_label_new ("Sort by:")); gtk_box_append (GTK_BOX (box), dropdown); @@ -1096,9 +1095,6 @@ do_listview_colors (GtkWidget *do_widget) gtk_drop_down_set_expression (GTK_DROP_DOWN (dropdown), expression); gtk_expression_unref (expression); - gtk_drop_down_set_model (GTK_DROP_DOWN (dropdown), G_LIST_MODEL (sorters)); - g_object_unref (sorters); - g_object_bind_property (dropdown, "selected-item", sort_model, "sorter", G_BINDING_SYNC_CREATE); factories = g_list_store_new (GTK_TYPE_LIST_ITEM_FACTORY); @@ -1113,7 +1109,7 @@ do_listview_colors (GtkWidget *do_widget) set_title (factory, "Everything"); g_list_store_append (factories, factory); - dropdown = gtk_drop_down_new (); + dropdown = gtk_drop_down_new (G_LIST_MODEL (factories), NULL); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); gtk_box_append (GTK_BOX (box), gtk_label_new ("Show:")); gtk_box_append (GTK_BOX (box), dropdown); @@ -1127,9 +1123,6 @@ do_listview_colors (GtkWidget *do_widget) gtk_drop_down_set_expression (GTK_DROP_DOWN (dropdown), expression); gtk_expression_unref (expression); - gtk_drop_down_set_model (GTK_DROP_DOWN (dropdown), G_LIST_MODEL (factories)); - g_object_unref (factories); - g_object_bind_property (dropdown, "selected-item", gridview, "factory", G_BINDING_SYNC_CREATE); } diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 2881f94dbe..bc03daaac4 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -7594,7 +7594,7 @@ gtk_string_filter_get_type GtkDropDown GtkDropDown gtk_drop_down_new -gtk_drop_down_set_from_strings +gtk_drop_down_new_from_strings gtk_drop_down_set_model gtk_drop_down_get_model gtk_drop_down_set_selected diff --git a/gtk/gtkcustompaperunixdialog.c b/gtk/gtkcustompaperunixdialog.c index 6940fdf12a..8395b6cf4f 100644 --- a/gtk/gtkcustompaperunixdialog.c +++ b/gtk/gtkcustompaperunixdialog.c @@ -1022,8 +1022,7 @@ populate_dialog (GtkCustomPaperUnixDialog *dialog) gtk_grid_attach (GTK_GRID (grid), hbox, 0, 4, 2, 1); gtk_widget_show (hbox); - combo = gtk_drop_down_new (); - gtk_drop_down_set_model (GTK_DROP_DOWN (combo), dialog->printer_list); + combo = gtk_drop_down_new (g_object_ref (dialog->printer_list), NULL); factory = gtk_signal_list_item_factory_new (); g_signal_connect (factory, "setup", G_CALLBACK (setup_printer_item), dialog); diff --git a/gtk/gtkdropdown.c b/gtk/gtkdropdown.c index 7b169ba780..05cb08f175 100644 --- a/gtk/gtkdropdown.c +++ b/gtk/gtkdropdown.c @@ -62,9 +62,9 @@ * and expects to obtain these from the model by evaluating an expression * that has to be provided via gtk_drop_down_set_expression(). * - * The convenience method gtk_drop_down_set_from_strings() can be used - * to set up a model that is populated from an array of strings and - * an expression for obtaining those strings. + * GtkDropDown knows how to obtain strings from the items in a + * #GtkStringList; for other models, you have to provide an expression + * to find the strings. * * GtkDropDown can optionally allow search in the popup, which is * useful if the list of options is long. To enable the search entry, @@ -602,19 +602,47 @@ gtk_drop_down_init (GtkDropDown *self) /** * gtk_drop_down_new: + * @model: (transfer full) (allow-none): the model to use or %NULL for none + * @expression: (transfer full) (allow-none): the expression to use or %NULL for none * - * Creates a new empty #GtkDropDown. + * Creates a new #GtkDropDown. * - * You most likely want to call gtk_drop_down_set_factory() to - * set up a way to map its items to widgets and gtk_drop_down_set_model() - * to set a model to provide items next. + * You may want to call gtk_drop_down_set_factory() + * to set up a way to map its items to widgets. * * Returns: a new #GtkDropDown **/ GtkWidget * -gtk_drop_down_new (void) +gtk_drop_down_new (GListModel *model, + GtkExpression *expression) { - return g_object_new (GTK_TYPE_DROP_DOWN, NULL); + GtkWidget *self; + + self = g_object_new (GTK_TYPE_DROP_DOWN, + "model", model, + "expression", expression, + NULL); + + /* we're consuming the references */ + g_clear_object (&model); + g_clear_pointer (&expression, gtk_expression_unref); + + return self; +} + +/** + * gtk_drop_down_new_from_strings: + * @strings: (array zero-terminated=1): The strings to put in the dropdown + * + * Creates a new #GtkDropDown that is populated with + * the strings in @strings. + * + * Returns: a new #GtkDropDown + */ +GtkWidget * +gtk_drop_down_new_from_strings (const char * const *strings) +{ + return gtk_drop_down_new (G_LIST_MODEL (gtk_string_list_new (strings)), NULL); } /** @@ -923,27 +951,3 @@ gtk_drop_down_get_expression (GtkDropDown *self) return self->expression; } - -/** - * gtk_drop_down_set_from_strings: - * @self: a #GtkDropDown - * @texts: (array zero-terminated=1) (element-type utf8): a %NULL-terminated string array - * - * Populates @self with the strings in @text, - * by creating a suitable model and factory. - */ -void -gtk_drop_down_set_from_strings (GtkDropDown *self, - const char *const *texts) -{ - GListModel *model; - - g_return_if_fail (GTK_IS_DROP_DOWN (self)); - g_return_if_fail (texts != NULL); - - set_default_factory (self); - - model = G_LIST_MODEL (gtk_string_list_new (texts)); - gtk_drop_down_set_model (self, model); - g_object_unref (model); -} diff --git a/gtk/gtkdropdown.h b/gtk/gtkdropdown.h index 0795d0f77b..78438cab72 100644 --- a/gtk/gtkdropdown.h +++ b/gtk/gtkdropdown.h @@ -31,11 +31,11 @@ GDK_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (GtkDropDown, gtk_drop_down, GTK, DROP_DOWN, GtkWidget) GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_drop_down_new (void); +GtkWidget * gtk_drop_down_new (GListModel *model, + GtkExpression *expression); GDK_AVAILABLE_IN_ALL -void gtk_drop_down_set_from_strings (GtkDropDown *self, - const char *const *texts); +GtkWidget * gtk_drop_down_new_from_strings (const char * const * strings); GDK_AVAILABLE_IN_ALL void gtk_drop_down_set_model (GtkDropDown *self, diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c index 44d6e85653..3509cf7cf7 100644 --- a/gtk/gtkfilechooserwidget.c +++ b/gtk/gtkfilechooserwidget.c @@ -7918,19 +7918,14 @@ gtk_file_chooser_widget_add_choice (GtkFileChooser *chooser, { GtkWidget *box; GtkWidget *combo; - GListModel *model; box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_append (GTK_BOX (box), gtk_label_new (label)); - combo = gtk_drop_down_new (); + combo = gtk_drop_down_new_from_strings ((const char * const *)options); g_hash_table_insert (impl->choices, g_strdup (id), combo); gtk_box_append (GTK_BOX (box), combo); - model = G_LIST_MODEL (gtk_string_list_new ((const char * const *)options)); - gtk_drop_down_set_model (GTK_DROP_DOWN (combo), model); - g_object_unref (model); - widget = box; } else diff --git a/gtk/gtkprinteroptionwidget.c b/gtk/gtkprinteroptionwidget.c index 59cb79b113..200eef8a39 100644 --- a/gtk/gtkprinteroptionwidget.c +++ b/gtk/gtkprinteroptionwidget.c @@ -37,6 +37,7 @@ #include "gtktogglebutton.h" #include "gtkorientable.h" #include "gtkprivate.h" +#include "gtkstringlist.h" #include "gtkprinteroptionwidget.h" @@ -479,7 +480,7 @@ combo_box_entry_new (void) gtk_widget_add_css_class (hbox, "linked"); entry = gtk_entry_new (); - button = gtk_drop_down_new (); + button = gtk_drop_down_new (NULL, NULL); combo_box_set_model (button); factory = gtk_signal_list_item_factory_new (); @@ -506,7 +507,7 @@ combo_box_new (void) { GtkWidget *combo_box; - combo_box = gtk_drop_down_new (); + combo_box = gtk_drop_down_new (NULL, NULL); combo_box_set_model (combo_box); combo_box_set_view (combo_box); @@ -938,8 +939,7 @@ construct_widgets (GtkPrinterOptionWidget *widget) const char * strings[2]; strings[0] = _("Not available"); strings[1] = NULL; - priv->combo = gtk_drop_down_new (); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (priv->combo), strings); + priv->combo = gtk_drop_down_new_from_strings (strings); gtk_drop_down_set_selected (GTK_DROP_DOWN (priv->combo), 0); gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE); gtk_widget_show (priv->combo); diff --git a/gtk/inspector/controllers.c b/gtk/inspector/controllers.c index a8fa4340ed..0d5d1e7e41 100644 --- a/gtk/inspector/controllers.c +++ b/gtk/inspector/controllers.c @@ -148,8 +148,7 @@ create_controller_widget (gpointer item, phases[3] = C_("event phase", "Target"); phases[4] = NULL; - dropdown = gtk_drop_down_new (); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (dropdown), phases); + dropdown = gtk_drop_down_new_from_strings (phases); gtk_drop_down_set_selected (GTK_DROP_DOWN (dropdown), gtk_event_controller_get_propagation_phase (controller)); gtk_box_append (GTK_BOX (box), dropdown); gtk_widget_set_halign (label, GTK_ALIGN_END); diff --git a/gtk/inspector/prop-editor.c b/gtk/inspector/prop-editor.c index fa586317b8..26c586515a 100644 --- a/gtk/inspector/prop-editor.c +++ b/gtk/inspector/prop-editor.c @@ -939,20 +939,16 @@ property_editor (GObject *object, { { GEnumClass *eclass; - char **names; + GtkStringList *names; int j; eclass = G_ENUM_CLASS (g_type_class_ref (spec->value_type)); - names = g_new (char *, eclass->n_values + 1); + names = gtk_string_list_new (NULL); for (j = 0; j < eclass->n_values; j++) - names[j] = (char *)eclass->values[j].value_name; - names[eclass->n_values] = NULL; + gtk_string_list_append (names, eclass->values[j].value_name); - prop_edit = gtk_drop_down_new (); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (prop_edit), (const char **)names); - - g_free (names); + prop_edit = gtk_drop_down_new (G_LIST_MODEL (names), NULL); connect_controller (G_OBJECT (prop_edit), "notify::selected", object, spec, G_CALLBACK (enum_modified)); @@ -1298,7 +1294,7 @@ attribute_editor (GObject *object, gtk_box_append (GTK_BOX (box), button); gtk_box_append (GTK_BOX (box), gtk_label_new (_("Column:"))); - dropdown = gtk_drop_down_new (); + dropdown = gtk_drop_down_new (NULL, NULL); store = g_list_store_new (ATTRIBUTE_TYPE_HOLDER); holder = attribute_holder_new (-1, TRUE); diff --git a/gtk/inspector/size-groups.c b/gtk/inspector/size-groups.c index 83033ba21a..21c351b835 100644 --- a/gtk/inspector/size-groups.c +++ b/gtk/inspector/size-groups.c @@ -32,6 +32,7 @@ #include "gtkswitch.h" #include "gtkwidgetprivate.h" #include "gtkstack.h" +#include "gtkstringlist.h" typedef struct { @@ -246,8 +247,7 @@ add_size_group (GtkInspectorSizeGroups *sl, gtk_widget_set_valign (label, GTK_ALIGN_BASELINE); gtk_box_append (GTK_BOX (box2), label); - dropdown = gtk_drop_down_new (); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (dropdown), modes); + dropdown = gtk_drop_down_new_from_strings (modes); g_object_set (dropdown, "margin", 10, NULL); gtk_widget_set_halign (dropdown, GTK_ALIGN_END); gtk_widget_set_valign (dropdown, GTK_ALIGN_BASELINE); diff --git a/gtk/inspector/visual.c b/gtk/inspector/visual.c index 008b3e1ac7..fe8bc9954d 100644 --- a/gtk/inspector/visual.c +++ b/gtk/inspector/visual.c @@ -44,6 +44,7 @@ #include "gtkbinlayout.h" #include "gtkeditable.h" #include "gtkentry.h" +#include "gtkstringlist.h" #ifdef GDK_WINDOWING_X11 #include "x11/gdkx.h" @@ -502,13 +503,14 @@ theme_to_pos (GBinding *binding, GValue *to, gpointer user_data) { - char **names = user_data; + GtkStringList *names = user_data; const char *theme = g_value_get_string (from); - int i; + guint i, n; - for (i = 0; names[i]; i++) + for (i = 0, n = g_list_model_get_n_items (G_LIST_MODEL (names)); i < n; i++) { - if (strcmp (names[i], theme) == 0) + const char *name = gtk_string_list_get_string (names, i); + if (strcmp (name, theme) == 0) { g_value_set_uint (to, i); return TRUE; @@ -523,9 +525,9 @@ pos_to_theme (GBinding *binding, GValue *to, gpointer user_data) { - char **names = user_data; + GtkStringList *names = user_data; int pos = g_value_get_uint (from); - g_value_set_string (to, names[pos]); + g_value_set_string (to, gtk_string_list_get_string (names, pos)); return TRUE; } @@ -537,9 +539,9 @@ init_theme (GtkInspectorVisual *vis) char *theme, *path; char **builtin_themes; GList *list, *l; + GtkStringList *names; guint i; const char * const *dirs; - char **names; t = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* Builtin themes */ @@ -576,20 +578,19 @@ init_theme (GtkInspectorVisual *vis) while (g_hash_table_iter_next (&iter, (gpointer *)&theme, NULL)) list = g_list_insert_sorted (list, theme, (GCompareFunc)strcmp); - names = g_new (char *, g_list_length (list) + 1); + names = gtk_string_list_new (NULL); for (l = list, i = 0; l; l = l->next, i++) - names[i] = g_strdup (l->data); - names[i] = NULL; + gtk_string_list_append (names, (const char *)l->data); g_list_free (list); g_hash_table_destroy (t); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (vis->theme_combo), (const char **)names); + gtk_drop_down_set_model (GTK_DROP_DOWN (vis->theme_combo), G_LIST_MODEL (names)); g_object_bind_property_full (gtk_settings_get_for_display (vis->display), "gtk-theme-name", vis->theme_combo, "selected", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, - theme_to_pos, pos_to_theme, names, (GDestroyNotify)g_strfreev); + theme_to_pos, pos_to_theme, names, (GDestroyNotify)g_object_unref); if (g_getenv ("GTK_THEME") != NULL) { @@ -654,8 +655,8 @@ init_icons (GtkInspectorVisual *vis) GHashTableIter iter; char *theme, *path; GList *list, *l; - char **names; int i; + GtkStringList *names; t = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); @@ -672,20 +673,19 @@ init_icons (GtkInspectorVisual *vis) while (g_hash_table_iter_next (&iter, (gpointer *)&theme, NULL)) list = g_list_insert_sorted (list, theme, (GCompareFunc)strcmp); - names = g_new (char *, g_list_length (list) + 1); + names = gtk_string_list_new (NULL); for (l = list, i = 0; l; l = l->next, i++) - names[i] = g_strdup (l->data); - names[i] = NULL; + gtk_string_list_append (names, (const char *)l->data); g_hash_table_destroy (t); g_list_free (list); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (vis->icon_combo), (const char **)names); + gtk_drop_down_set_model (GTK_DROP_DOWN (vis->icon_combo), G_LIST_MODEL (names)); g_object_bind_property_full (gtk_settings_get_for_display (vis->display), "gtk-icon-theme-name", vis->icon_combo, "selected", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, - theme_to_pos, pos_to_theme, names, (GDestroyNotify)g_strfreev); + theme_to_pos, pos_to_theme, names, (GDestroyNotify)g_object_unref); } static void @@ -720,7 +720,7 @@ init_cursors (GtkInspectorVisual *vis) GHashTableIter iter; char *theme, *path; GList *list, *l; - char **names; + GtkStringList *names; int i; t = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); @@ -738,20 +738,19 @@ init_cursors (GtkInspectorVisual *vis) while (g_hash_table_iter_next (&iter, (gpointer *)&theme, NULL)) list = g_list_insert_sorted (list, theme, (GCompareFunc)strcmp); - names = g_new (char *, g_list_length (list) + 1); + names = gtk_string_list_new (NULL); for (l = list, i = 0; l; l = l->next, i++) - names[i] = g_strdup (l->data); - names[i] = NULL; + gtk_string_list_append (names, (const char *)l->data); g_hash_table_destroy (t); g_list_free (list); - gtk_drop_down_set_from_strings (GTK_DROP_DOWN (vis->cursor_combo), (const char **)names); + gtk_drop_down_set_model (GTK_DROP_DOWN (vis->cursor_combo), G_LIST_MODEL (names)); g_object_bind_property_full (gtk_settings_get_for_display (vis->display), "gtk-cursor-theme-name", vis->cursor_combo, "selected", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, - theme_to_pos, pos_to_theme, names, (GDestroyNotify)g_strfreev); + theme_to_pos, pos_to_theme, names, (GDestroyNotify)g_object_unref); } static void diff --git a/tests/testdropdown.c b/tests/testdropdown.c index d207256271..5dcd7fcae7 100644 --- a/tests/testdropdown.c +++ b/tests/testdropdown.c @@ -469,7 +469,7 @@ main (int argc, char *argv[]) gtk_widget_set_margin_bottom (box, 10); gtk_window_set_child (GTK_WINDOW (window), box); - button = gtk_drop_down_new (); + button = gtk_drop_down_new (NULL, NULL); model = G_LIST_MODEL (pango_cairo_font_map_get_default ()); gtk_drop_down_set_model (GTK_DROP_DOWN (button), model); @@ -513,7 +513,7 @@ main (int argc, char *argv[]) button = drop_down_new_from_strings (device_titles, device_icons, device_descriptions); gtk_box_append (GTK_BOX (box), button); - button = gtk_drop_down_new (); + button = gtk_drop_down_new (NULL, NULL); store = g_list_store_new (GTK_TYPE_STRING_PAIR); g_list_store_append (store, gtk_string_pair_new ("1", "One")); @@ -536,7 +536,7 @@ main (int argc, char *argv[]) gtk_widget_add_css_class (hbox, "linked"); entry = gtk_entry_new (); - button = gtk_drop_down_new (); + button = gtk_drop_down_new (NULL, NULL); gtk_drop_down_set_model (GTK_DROP_DOWN (button), G_LIST_MODEL (store));