diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index aca18e9a2d..63b0941276 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -7070,6 +7070,8 @@ gtk_app_chooser_button_new gtk_app_chooser_button_append_custom_item gtk_app_chooser_button_append_separator gtk_app_chooser_button_set_active_custom_item +gtk_app_chooser_button_get_show_default_item +gtk_app_chooser_button_set_show_default_item gtk_app_chooser_button_get_show_dialog_item gtk_app_chooser_button_set_show_dialog_item gtk_app_chooser_button_get_heading diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index c21babf4f7..3624280116 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -185,10 +185,12 @@ gtk_app_chooser_get_type gtk_app_chooser_refresh gtk_app_chooser_button_append_custom_item gtk_app_chooser_button_append_separator +gtk_app_chooser_button_get_show_default_item gtk_app_chooser_button_get_show_dialog_item gtk_app_chooser_button_get_type gtk_app_chooser_button_new gtk_app_chooser_button_set_active_custom_item +gtk_app_chooser_button_set_show_default_item gtk_app_chooser_button_set_show_dialog_item gtk_app_chooser_button_get_heading gtk_app_chooser_button_set_heading diff --git a/gtk/gtkappchooser.c b/gtk/gtkappchooser.c index a517002cc6..e3f8a98821 100644 --- a/gtk/gtkappchooser.c +++ b/gtk/gtkappchooser.c @@ -25,11 +25,25 @@ * SECTION:gtkappchooser * @Title: GtkAppChooser * @Short_description: Interface implemented by widgets for choosing an application + * @See_also: #GAppInfo * * #GtkAppChooser is an interface that can be implemented by widgets which * allow the user to choose an application (typically for the purpose of * opening a file). The main objects that implement this interface are * #GtkAppChooserWidget, #GtkAppChooserDialog and #GtkAppChooserButton. + * + * Applications are represented by GIO #GAppInfo objects here. + * GIO has a concept of recommended and fallback applications for a + * given content type. Recommended applications are those that claim + * to handle the content type itself, while fallback also includes + * applications that handle a more generic content type. GIO also + * knows the default and last-used application for a given content + * type. The #GtkAppChooserWidget provides detailed control over + * whether the shown list of applications should include default, + * recommended or fallback applications. + * + * To obtain the application that has been selected in a #GtkAppChooser, + * use gtk_app_chooser_get_app_info(). */ #include "config.h" diff --git a/gtk/gtkappchooserbutton.c b/gtk/gtkappchooserbutton.c index fbcd99dde6..bd1d335d3d 100644 --- a/gtk/gtkappchooserbutton.c +++ b/gtk/gtkappchooserbutton.c @@ -28,6 +28,26 @@ * * The #GtkAppChooserButton is a widget that lets the user select * an application. It implements the #GtkAppChooser interface. + * + * Initially, a #GtkAppChooserButton selects the first application + * in its list, which will either be the most-recently used application + * or, if #GtkAppChooserButton::show-default-item is %TRUE, the + * default application. + * + * The list of applications shown in a #GtkAppChooserButton includes + * the recommended applications for the given content type. When + * #GtkAppChooserButton::show-default-item is set, the default application + * is also included. To let the user chooser other applications, + * you can set the #GtkAppChooserButton::show-dialog-item property, + * which allows to open a full #GtkAppChooserDialog. + * + * It is possible to add custom items to the list, using + * gtk_app_chooser_button_append_custom_item(). These items cause + * the #GtkAppChooserButton::custom-item-activated signal to be + * emitted when they are selected. + * + * To track changes in the selected application, use the + * #GtkComboBox::changed signal. */ #include "config.h" @@ -47,6 +67,7 @@ enum { PROP_CONTENT_TYPE = 1, PROP_SHOW_DIALOG_ITEM, + PROP_SHOW_DEFAULT_ITEM, PROP_HEADING }; @@ -93,6 +114,7 @@ struct _GtkAppChooserButtonPrivate { gchar *heading; gint last_active; gboolean show_dialog_item; + gboolean show_default_item; GHashTable *custom_item_names; }; @@ -271,13 +293,36 @@ gtk_app_chooser_button_ensure_dialog_item (GtkAppChooserButton *self, FALSE, &iter); } +static void +insert_one_application (GtkAppChooserButton *self, + GAppInfo *app, + GtkTreeIter *iter) +{ + GIcon *icon; + + icon = g_app_info_get_icon (app); + + if (icon == NULL) + icon = g_themed_icon_new ("application-x-executable"); + else + g_object_ref (icon); + + gtk_list_store_set (self->priv->store, iter, + COLUMN_APP_INFO, app, + COLUMN_LABEL, g_app_info_get_name (app), + COLUMN_ICON, icon, + COLUMN_CUSTOM, FALSE, + -1); + + g_object_unref (icon); +} + static void gtk_app_chooser_button_populate (GtkAppChooserButton *self) { GList *recommended_apps = NULL, *l; - GAppInfo *app; + GAppInfo *app, *default_app = NULL; GtkTreeIter iter, iter2; - GIcon *icon; gboolean cycled_recommended; #ifndef G_OS_WIN32 @@ -286,16 +331,27 @@ gtk_app_chooser_button_populate (GtkAppChooserButton *self) #endif cycled_recommended = FALSE; + if (self->priv->show_default_item) + { + default_app = g_app_info_get_default_for_type (self->priv->content_type, FALSE); + + if (default_app != NULL) + { + get_first_iter (self->priv->store, &iter); + cycled_recommended = TRUE; + + insert_one_application (self, default_app, &iter); + + g_object_unref (default_app); + } + } + for (l = recommended_apps; l != NULL; l = l->next) { app = l->data; - icon = g_app_info_get_icon (app); - - if (icon == NULL) - icon = g_themed_icon_new ("application-x-executable"); - else - g_object_ref (icon); + if (default_app != NULL && g_app_info_equal (app, default_app)) + continue; if (cycled_recommended) { @@ -308,16 +364,12 @@ gtk_app_chooser_button_populate (GtkAppChooserButton *self) cycled_recommended = TRUE; } - gtk_list_store_set (self->priv->store, &iter, - COLUMN_APP_INFO, app, - COLUMN_LABEL, g_app_info_get_name (app), - COLUMN_ICON, icon, - COLUMN_CUSTOM, FALSE, - -1); - - g_object_unref (icon); + insert_one_application (self, app, &iter); } + if (recommended_apps != NULL) + g_list_free_full (recommended_apps, g_object_unref); + if (!cycled_recommended) gtk_app_chooser_button_ensure_dialog_item (self, NULL); else @@ -475,6 +527,9 @@ gtk_app_chooser_button_set_property (GObject *obj, case PROP_SHOW_DIALOG_ITEM: gtk_app_chooser_button_set_show_dialog_item (self, g_value_get_boolean (value)); break; + case PROP_SHOW_DEFAULT_ITEM: + gtk_app_chooser_button_set_show_default_item (self, g_value_get_boolean (value)); + break; case PROP_HEADING: gtk_app_chooser_button_set_heading (self, g_value_get_string (value)); break; @@ -500,6 +555,9 @@ gtk_app_chooser_button_get_property (GObject *obj, case PROP_SHOW_DIALOG_ITEM: g_value_set_boolean (value, self->priv->show_dialog_item); break; + case PROP_SHOW_DEFAULT_ITEM: + g_value_set_boolean (value, self->priv->show_default_item); + break; case PROP_HEADING: g_value_set_string (value, self->priv->heading); break; @@ -549,8 +607,9 @@ gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass) /** * GtkAppChooserButton:show-dialog-item: * - * The #GtkAppChooserButton:show-dialog-item property determines whether the dropdown menu - * should show an item that triggers a #GtkAppChooserDialog when clicked. + * The #GtkAppChooserButton:show-dialog-item property determines + * whether the dropdown menu should show an item that triggers + * a #GtkAppChooserDialog when clicked. */ pspec = g_param_spec_boolean ("show-dialog-item", @@ -560,6 +619,24 @@ gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); g_object_class_install_property (oclass, PROP_SHOW_DIALOG_ITEM, pspec); + /** + * GtkAppChooserButton:show-default-item: + * + * The #GtkAppChooserButton:show-default-item property determines + * whether the dropdown menu should show the default application + * on top for the provided content type. + * + * Since: 3.2 + */ + pspec = + g_param_spec_boolean ("show-default-item", + P_("Show default item"), + P_("Whether the combobox should show the default application on top"), + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_SHOW_DEFAULT_ITEM, pspec); + + /** * GtkAppChooserButton:heading: * @@ -616,8 +693,8 @@ gtk_app_chooser_button_init (GtkAppChooserButton *self) static gboolean app_chooser_button_iter_from_custom_name (GtkAppChooserButton *self, - const gchar *name, - GtkTreeIter *set_me) + const gchar *name, + GtkTreeIter *set_me) { GtkTreeIter iter; gchar *custom_name = NULL; @@ -737,9 +814,9 @@ gtk_app_chooser_button_append_separator (GtkAppChooserButton *self) * * Appends a custom item to the list of applications that is shown * in the popup; the item name must be unique per-widget. - * Clients can use the provided name as a detail for the ::custom-item-activated - * signal, to add a callback for the activation of a particular - * custom item in the list. + * Clients can use the provided name as a detail for the + * #GtkAppChooserButton::custom-item-activated signal, to add a + * callback for the activation of a particular custom item in the list. * See also gtk_app_chooser_button_append_separator(). * * Since: 3.0 @@ -823,7 +900,7 @@ gtk_app_chooser_button_get_show_dialog_item (GtkAppChooserButton *self) */ void gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self, - gboolean setting) + gboolean setting) { if (self->priv->show_dialog_item != setting) { @@ -835,6 +912,49 @@ gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self, } } +/** + * gtk_app_chooser_button_get_show_default_item: + * @self: a #GtkAppChooserButton + * + * Returns the current value of the #GtkAppChooserButton:show-default-item + * property. + * + * Returns: the value of #GtkAppChooserButton:show-default-item + * + * Since: 3.2 + */ +gboolean +gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE); + + return self->priv->show_default_item; +} + +/** + * gtk_app_chooser_button_set_show_default_item: + * @self: a #GtkAppChooserButton + * @setting: the new value for #GtkAppChooserButton:show-default-item + * + * Sets whether the dropdown menu of this button should show the + * default application for the given content type at top. + * + * Since: 3.2 + */ +void +gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self, + gboolean setting) +{ + if (self->priv->show_default_item != setting) + { + self->priv->show_default_item = setting; + + g_object_notify (G_OBJECT (self), "show-default-item"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + /** * gtk_app_chooser_button_set_heading: * @self: a #GtkAppChooserButton @@ -861,8 +981,8 @@ gtk_app_chooser_button_set_heading (GtkAppChooserButton *self, * * Returns the text to display at the top of the dialog. * - * Returns: the text to display at the top of the dialog, or %NULL, in which - * case a default text is displayed + * Returns: the text to display at the top of the dialog, + * or %NULL, in which case a default text is displayed */ const gchar * gtk_app_chooser_button_get_heading (GtkAppChooserButton *self) diff --git a/gtk/gtkappchooserbutton.h b/gtk/gtkappchooserbutton.h index dd9e9cf6a3..aeb9d9c623 100644 --- a/gtk/gtkappchooserbutton.h +++ b/gtk/gtkappchooserbutton.h @@ -80,6 +80,9 @@ void gtk_app_chooser_button_set_heading (GtkAppChooserButton *self const gchar *heading); const gchar * gtk_app_chooser_button_get_heading (GtkAppChooserButton *self); +void gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self, + gboolean setting); +gboolean gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self); G_END_DECLS diff --git a/gtk/gtkappchooserdialog.c b/gtk/gtkappchooserdialog.c index 5412e7a91e..28c6bc0a50 100644 --- a/gtk/gtkappchooserdialog.c +++ b/gtk/gtkappchooserdialog.c @@ -35,6 +35,9 @@ * of its own. Instead, you should get the embedded #GtkAppChooserWidget * using gtk_app_chooser_dialog_get_widget() and call its methods if * the generic #GtkAppChooser interface is not sufficient for your needs. + * + * To set the heading that is shown above the #GtkAppChooserWidget, + * use gtk_app_chooser_dialog_set_heading(). */ #include "config.h" diff --git a/gtk/gtkappchooserwidget.c b/gtk/gtkappchooserwidget.c index 551c1ddbb6..3ba1b59716 100644 --- a/gtk/gtkappchooserwidget.c +++ b/gtk/gtkappchooserwidget.c @@ -54,6 +54,19 @@ * It is the main building block for #GtkAppChooserDialog. Most * applications only need to use the latter; but you can use * this widget as part of a larger widget if you have special needs. + * + * #GtkAppChooserWidget offers detailed control over what applications + * are shown, using the + * #GtkAppChooserWidget:show-default, + * #GtkAppChooserWidget:show-recommended, + * #GtkAppChooserWidget:show-fallback, + * #GtkAppChooserWidget:show-other and + * #GtkAppChooserWidget:show-all + * properties. See the #GtkAppChooser documentation for more information + * about these groups of applications. + * + * To keep track of the selected application, use the + * #GtkAppChooserWidget::application-selected and #GtkAppChooserWidget::application-activated signals. */ struct _GtkAppChooserWidgetPrivate { @@ -1022,9 +1035,10 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) /** * GtkAppChooserWidget:show-recommended: * - * The #GtkAppChooserWidget:show-recommended property determines whether the app chooser - * should show a section for recommended applications. If %FALSE, the - * recommended applications are listed among the other applications. + * The #GtkAppChooserWidget:show-recommended property determines + * whether the app chooser should show a section for recommended + * applications. If %FALSE, the recommended applications are listed + * among the other applications. */ pspec = g_param_spec_boolean ("show-recommended", P_("Show recommended apps"), @@ -1036,9 +1050,10 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) /** * GtkAppChooserWidget:show-fallback: * - * The #GtkAppChooserWidget:show-fallback property determines whether the app chooser - * should show a section for related applications. If %FALSE, the - * related applications are listed among the other applications. + * The #GtkAppChooserWidget:show-fallback property determines whether + * the app chooser should show a section for fallback applications. + * If %FALSE, the fallback applications are listed among the other + * applications. */ pspec = g_param_spec_boolean ("show-fallback", P_("Show fallback apps"), @@ -1050,8 +1065,8 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) /** * GtkAppChooserWidget:show-other: * - * The #GtkAppChooserWidget:show-other property determines whether the app chooser - * should show a section for other applications. + * The #GtkAppChooserWidget:show-other property determines whether + * the app chooser should show a section for other applications. */ pspec = g_param_spec_boolean ("show-other", P_("Show other apps"), @@ -1063,9 +1078,9 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) /** * GtkAppChooserWidget:show-all: * - * If the #GtkAppChooserWidget:show-all property is %TRUE, the app chooser presents - * all applications in a single list, without subsections for - * default, recommended or related applications. + * If the #GtkAppChooserWidget:show-all property is %TRUE, the app + * chooser presents all applications in a single list, without + * subsections for default, recommended or related applications. */ pspec = g_param_spec_boolean ("show-all", P_("Show all apps"), @@ -1077,8 +1092,9 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) /** * GtkAppChooserWidget:default-text: * - * The #GtkAppChooserWidget:default-text property determines the text that appears - * in the widget when there are no applications for the given content type. + * The #GtkAppChooserWidget:default-text property determines the text + * that appears in the widget when there are no applications for the + * given content type. * See also gtk_app_chooser_widget_set_default_text(). */ pspec = g_param_spec_string ("default-text", @@ -1111,6 +1127,7 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) * @application: the activated #GAppInfo * * Emitted when an application item is activated from the widget's list. + * * This usually happens when the user double clicks an item, or an item * is selected and the user presses one of the keys Space, Shift+Space, * Return or Enter. @@ -1133,8 +1150,8 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) * * Emitted when a context menu is about to popup over an application item. * Clients can insert menu items into the provided #GtkMenu object in the - * callback of this signal; the context menu will be shown over the item if - * at least one item has been added to the menu. + * callback of this signal; the context menu will be shown over the item + * if at least one item has been added to the menu. */ signals[SIGNAL_POPULATE_POPUP] = g_signal_new ("populate-popup", diff --git a/tests/testappchooser.c b/tests/testappchooser.c index dd40ed6b87..2695c57d29 100644 --- a/tests/testappchooser.c +++ b/tests/testappchooser.c @@ -26,7 +26,7 @@ static GFile *file; static GtkWidget *grid, *file_l, *open; static GtkWidget *radio_file, *radio_content, *dialog; static GtkWidget *app_chooser_widget; -static GtkWidget *recommended, *fallback, *other, *all; +static GtkWidget *def, *recommended, *fallback, *other, *all; static void dialog_response (GtkDialog *d, @@ -58,6 +58,9 @@ dialog_response (GtkDialog *d, static void bind_props (void) { + g_object_bind_property (def, "active", + app_chooser_widget, "show-default", + G_BINDING_SYNC_CREATE); g_object_bind_property (recommended, "active", app_chooser_widget, "show-recommended", G_BINDING_SYNC_CREATE); @@ -208,6 +211,11 @@ main (int argc, char **argv) gtk_grid_attach_next_to (GTK_GRID (grid), all, other, GTK_POS_RIGHT, 1, 1); + def = gtk_check_button_new_with_label ("Show default"); + gtk_grid_attach_next_to (GTK_GRID (grid), def, + all, GTK_POS_RIGHT, 1, 1); + + g_object_set (recommended, "active", TRUE, NULL); prepare_dialog (); g_signal_connect (open, "clicked", G_CALLBACK (display_dialog), NULL); diff --git a/tests/testappchooserbutton.c b/tests/testappchooserbutton.c index 664a3291d2..d46eb2d46d 100644 --- a/tests/testappchooserbutton.c +++ b/tests/testappchooserbutton.c @@ -111,6 +111,8 @@ main (int argc, gtk_app_chooser_button_set_show_dialog_item (GTK_APP_CHOOSER_BUTTON (combobox), TRUE); + gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (combobox), + TRUE); /* connect to the detailed signal */ g_signal_connect (combobox, "custom-item-activated::" CUSTOM_ITEM, @@ -123,9 +125,10 @@ main (int argc, /* test refresh on a combo */ gtk_app_chooser_refresh (GTK_APP_CHOOSER (combobox)); +#if 0 gtk_app_chooser_button_set_active_custom_item (GTK_APP_CHOOSER_BUTTON (combobox), CUSTOM_ITEM); - +#endif gtk_widget_show_all (toplevel); g_signal_connect (toplevel, "delete-event",