GtkAppChooserButton: Add a way to include the default app

This is necessary to use an app chooser button for selecting
default apps in the control center. Also, beef up the docs
for this widget family.

https://bugzilla.gnome.org/show_bug.cgi?id=642706
This commit is contained in:
Matthias Clasen
2011-09-10 01:40:05 -04:00
parent e97ed4374f
commit f9379adca2
9 changed files with 215 additions and 43 deletions

View File

@ -7070,6 +7070,8 @@ gtk_app_chooser_button_new
gtk_app_chooser_button_append_custom_item gtk_app_chooser_button_append_custom_item
gtk_app_chooser_button_append_separator gtk_app_chooser_button_append_separator
gtk_app_chooser_button_set_active_custom_item 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_get_show_dialog_item
gtk_app_chooser_button_set_show_dialog_item gtk_app_chooser_button_set_show_dialog_item
gtk_app_chooser_button_get_heading gtk_app_chooser_button_get_heading

View File

@ -185,10 +185,12 @@ gtk_app_chooser_get_type
gtk_app_chooser_refresh gtk_app_chooser_refresh
gtk_app_chooser_button_append_custom_item gtk_app_chooser_button_append_custom_item
gtk_app_chooser_button_append_separator 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_show_dialog_item
gtk_app_chooser_button_get_type gtk_app_chooser_button_get_type
gtk_app_chooser_button_new gtk_app_chooser_button_new
gtk_app_chooser_button_set_active_custom_item 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_set_show_dialog_item
gtk_app_chooser_button_get_heading gtk_app_chooser_button_get_heading
gtk_app_chooser_button_set_heading gtk_app_chooser_button_set_heading

View File

@ -25,11 +25,25 @@
* SECTION:gtkappchooser * SECTION:gtkappchooser
* @Title: GtkAppChooser * @Title: GtkAppChooser
* @Short_description: Interface implemented by widgets for choosing an application * @Short_description: Interface implemented by widgets for choosing an application
* @See_also: #GAppInfo
* *
* #GtkAppChooser is an interface that can be implemented by widgets which * #GtkAppChooser is an interface that can be implemented by widgets which
* allow the user to choose an application (typically for the purpose of * allow the user to choose an application (typically for the purpose of
* opening a file). The main objects that implement this interface are * opening a file). The main objects that implement this interface are
* #GtkAppChooserWidget, #GtkAppChooserDialog and #GtkAppChooserButton. * #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" #include "config.h"

View File

@ -28,6 +28,26 @@
* *
* The #GtkAppChooserButton is a widget that lets the user select * The #GtkAppChooserButton is a widget that lets the user select
* an application. It implements the #GtkAppChooser interface. * 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" #include "config.h"
@ -47,6 +67,7 @@
enum { enum {
PROP_CONTENT_TYPE = 1, PROP_CONTENT_TYPE = 1,
PROP_SHOW_DIALOG_ITEM, PROP_SHOW_DIALOG_ITEM,
PROP_SHOW_DEFAULT_ITEM,
PROP_HEADING PROP_HEADING
}; };
@ -93,6 +114,7 @@ struct _GtkAppChooserButtonPrivate {
gchar *heading; gchar *heading;
gint last_active; gint last_active;
gboolean show_dialog_item; gboolean show_dialog_item;
gboolean show_default_item;
GHashTable *custom_item_names; GHashTable *custom_item_names;
}; };
@ -271,13 +293,36 @@ gtk_app_chooser_button_ensure_dialog_item (GtkAppChooserButton *self,
FALSE, &iter); 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 static void
gtk_app_chooser_button_populate (GtkAppChooserButton *self) gtk_app_chooser_button_populate (GtkAppChooserButton *self)
{ {
GList *recommended_apps = NULL, *l; GList *recommended_apps = NULL, *l;
GAppInfo *app; GAppInfo *app, *default_app = NULL;
GtkTreeIter iter, iter2; GtkTreeIter iter, iter2;
GIcon *icon;
gboolean cycled_recommended; gboolean cycled_recommended;
#ifndef G_OS_WIN32 #ifndef G_OS_WIN32
@ -286,16 +331,27 @@ gtk_app_chooser_button_populate (GtkAppChooserButton *self)
#endif #endif
cycled_recommended = FALSE; 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) for (l = recommended_apps; l != NULL; l = l->next)
{ {
app = l->data; app = l->data;
icon = g_app_info_get_icon (app); if (default_app != NULL && g_app_info_equal (app, default_app))
continue;
if (icon == NULL)
icon = g_themed_icon_new ("application-x-executable");
else
g_object_ref (icon);
if (cycled_recommended) if (cycled_recommended)
{ {
@ -308,16 +364,12 @@ gtk_app_chooser_button_populate (GtkAppChooserButton *self)
cycled_recommended = TRUE; cycled_recommended = TRUE;
} }
gtk_list_store_set (self->priv->store, &iter, insert_one_application (self, app, &iter);
COLUMN_APP_INFO, app,
COLUMN_LABEL, g_app_info_get_name (app),
COLUMN_ICON, icon,
COLUMN_CUSTOM, FALSE,
-1);
g_object_unref (icon);
} }
if (recommended_apps != NULL)
g_list_free_full (recommended_apps, g_object_unref);
if (!cycled_recommended) if (!cycled_recommended)
gtk_app_chooser_button_ensure_dialog_item (self, NULL); gtk_app_chooser_button_ensure_dialog_item (self, NULL);
else else
@ -475,6 +527,9 @@ gtk_app_chooser_button_set_property (GObject *obj,
case PROP_SHOW_DIALOG_ITEM: case PROP_SHOW_DIALOG_ITEM:
gtk_app_chooser_button_set_show_dialog_item (self, g_value_get_boolean (value)); gtk_app_chooser_button_set_show_dialog_item (self, g_value_get_boolean (value));
break; break;
case PROP_SHOW_DEFAULT_ITEM:
gtk_app_chooser_button_set_show_default_item (self, g_value_get_boolean (value));
break;
case PROP_HEADING: case PROP_HEADING:
gtk_app_chooser_button_set_heading (self, g_value_get_string (value)); gtk_app_chooser_button_set_heading (self, g_value_get_string (value));
break; break;
@ -500,6 +555,9 @@ gtk_app_chooser_button_get_property (GObject *obj,
case PROP_SHOW_DIALOG_ITEM: case PROP_SHOW_DIALOG_ITEM:
g_value_set_boolean (value, self->priv->show_dialog_item); g_value_set_boolean (value, self->priv->show_dialog_item);
break; break;
case PROP_SHOW_DEFAULT_ITEM:
g_value_set_boolean (value, self->priv->show_default_item);
break;
case PROP_HEADING: case PROP_HEADING:
g_value_set_string (value, self->priv->heading); g_value_set_string (value, self->priv->heading);
break; break;
@ -549,8 +607,9 @@ gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass)
/** /**
* GtkAppChooserButton:show-dialog-item: * GtkAppChooserButton:show-dialog-item:
* *
* The #GtkAppChooserButton:show-dialog-item property determines whether the dropdown menu * The #GtkAppChooserButton:show-dialog-item property determines
* should show an item that triggers a #GtkAppChooserDialog when clicked. * whether the dropdown menu should show an item that triggers
* a #GtkAppChooserDialog when clicked.
*/ */
pspec = pspec =
g_param_spec_boolean ("show-dialog-item", 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_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (oclass, PROP_SHOW_DIALOG_ITEM, pspec); 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: * GtkAppChooserButton:heading:
* *
@ -737,9 +814,9 @@ gtk_app_chooser_button_append_separator (GtkAppChooserButton *self)
* *
* Appends a custom item to the list of applications that is shown * Appends a custom item to the list of applications that is shown
* in the popup; the item name must be unique per-widget. * 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 * Clients can use the provided name as a detail for the
* signal, to add a callback for the activation of a particular * #GtkAppChooserButton::custom-item-activated signal, to add a
* custom item in the list. * callback for the activation of a particular custom item in the list.
* See also gtk_app_chooser_button_append_separator(). * See also gtk_app_chooser_button_append_separator().
* *
* Since: 3.0 * Since: 3.0
@ -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: * gtk_app_chooser_button_set_heading:
* @self: a #GtkAppChooserButton * @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.
* *
* Returns: the text to display at the top of the dialog, or %NULL, in which * Returns: the text to display at the top of the dialog,
* case a default text is displayed * or %NULL, in which case a default text is displayed
*/ */
const gchar * const gchar *
gtk_app_chooser_button_get_heading (GtkAppChooserButton *self) gtk_app_chooser_button_get_heading (GtkAppChooserButton *self)

View File

@ -80,6 +80,9 @@ void gtk_app_chooser_button_set_heading (GtkAppChooserButton *self
const gchar *heading); const gchar *heading);
const gchar * const gchar *
gtk_app_chooser_button_get_heading (GtkAppChooserButton *self); 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 G_END_DECLS

View File

@ -35,6 +35,9 @@
* of its own. Instead, you should get the embedded #GtkAppChooserWidget * of its own. Instead, you should get the embedded #GtkAppChooserWidget
* using gtk_app_chooser_dialog_get_widget() and call its methods if * using gtk_app_chooser_dialog_get_widget() and call its methods if
* the generic #GtkAppChooser interface is not sufficient for your needs. * 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" #include "config.h"

View File

@ -54,6 +54,19 @@
* It is the main building block for #GtkAppChooserDialog. Most * It is the main building block for #GtkAppChooserDialog. Most
* applications only need to use the latter; but you can use * applications only need to use the latter; but you can use
* this widget as part of a larger widget if you have special needs. * 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 { struct _GtkAppChooserWidgetPrivate {
@ -1022,9 +1035,10 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
/** /**
* GtkAppChooserWidget:show-recommended: * GtkAppChooserWidget:show-recommended:
* *
* The #GtkAppChooserWidget:show-recommended property determines whether the app chooser * The #GtkAppChooserWidget:show-recommended property determines
* should show a section for recommended applications. If %FALSE, the * whether the app chooser should show a section for recommended
* recommended applications are listed among the other applications. * applications. If %FALSE, the recommended applications are listed
* among the other applications.
*/ */
pspec = g_param_spec_boolean ("show-recommended", pspec = g_param_spec_boolean ("show-recommended",
P_("Show recommended apps"), P_("Show recommended apps"),
@ -1036,9 +1050,10 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
/** /**
* GtkAppChooserWidget:show-fallback: * GtkAppChooserWidget:show-fallback:
* *
* The #GtkAppChooserWidget:show-fallback property determines whether the app chooser * The #GtkAppChooserWidget:show-fallback property determines whether
* should show a section for related applications. If %FALSE, the * the app chooser should show a section for fallback applications.
* related applications are listed among the other applications. * If %FALSE, the fallback applications are listed among the other
* applications.
*/ */
pspec = g_param_spec_boolean ("show-fallback", pspec = g_param_spec_boolean ("show-fallback",
P_("Show fallback apps"), P_("Show fallback apps"),
@ -1050,8 +1065,8 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
/** /**
* GtkAppChooserWidget:show-other: * GtkAppChooserWidget:show-other:
* *
* The #GtkAppChooserWidget:show-other property determines whether the app chooser * The #GtkAppChooserWidget:show-other property determines whether
* should show a section for other applications. * the app chooser should show a section for other applications.
*/ */
pspec = g_param_spec_boolean ("show-other", pspec = g_param_spec_boolean ("show-other",
P_("Show other apps"), P_("Show other apps"),
@ -1063,9 +1078,9 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
/** /**
* GtkAppChooserWidget:show-all: * GtkAppChooserWidget:show-all:
* *
* If the #GtkAppChooserWidget:show-all property is %TRUE, the app chooser presents * If the #GtkAppChooserWidget:show-all property is %TRUE, the app
* all applications in a single list, without subsections for * chooser presents all applications in a single list, without
* default, recommended or related applications. * subsections for default, recommended or related applications.
*/ */
pspec = g_param_spec_boolean ("show-all", pspec = g_param_spec_boolean ("show-all",
P_("Show all apps"), P_("Show all apps"),
@ -1077,8 +1092,9 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
/** /**
* GtkAppChooserWidget:default-text: * GtkAppChooserWidget:default-text:
* *
* The #GtkAppChooserWidget:default-text property determines the text that appears * The #GtkAppChooserWidget:default-text property determines the text
* in the widget when there are no applications for the given content type. * that appears in the widget when there are no applications for the
* given content type.
* See also gtk_app_chooser_widget_set_default_text(). * See also gtk_app_chooser_widget_set_default_text().
*/ */
pspec = g_param_spec_string ("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 * @application: the activated #GAppInfo
* *
* Emitted when an application item is activated from the widget's list. * 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 * 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, * is selected and the user presses one of the keys Space, Shift+Space,
* Return or Enter. * 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. * 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 * 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 * callback of this signal; the context menu will be shown over the item
* at least one item has been added to the menu. * if at least one item has been added to the menu.
*/ */
signals[SIGNAL_POPULATE_POPUP] = signals[SIGNAL_POPULATE_POPUP] =
g_signal_new ("populate-popup", g_signal_new ("populate-popup",

View File

@ -26,7 +26,7 @@ static GFile *file;
static GtkWidget *grid, *file_l, *open; static GtkWidget *grid, *file_l, *open;
static GtkWidget *radio_file, *radio_content, *dialog; static GtkWidget *radio_file, *radio_content, *dialog;
static GtkWidget *app_chooser_widget; static GtkWidget *app_chooser_widget;
static GtkWidget *recommended, *fallback, *other, *all; static GtkWidget *def, *recommended, *fallback, *other, *all;
static void static void
dialog_response (GtkDialog *d, dialog_response (GtkDialog *d,
@ -58,6 +58,9 @@ dialog_response (GtkDialog *d,
static void static void
bind_props (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", g_object_bind_property (recommended, "active",
app_chooser_widget, "show-recommended", app_chooser_widget, "show-recommended",
G_BINDING_SYNC_CREATE); G_BINDING_SYNC_CREATE);
@ -208,6 +211,11 @@ main (int argc, char **argv)
gtk_grid_attach_next_to (GTK_GRID (grid), all, gtk_grid_attach_next_to (GTK_GRID (grid), all,
other, GTK_POS_RIGHT, 1, 1); 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 (); prepare_dialog ();
g_signal_connect (open, "clicked", g_signal_connect (open, "clicked",
G_CALLBACK (display_dialog), NULL); G_CALLBACK (display_dialog), NULL);

View File

@ -111,6 +111,8 @@ main (int argc,
gtk_app_chooser_button_set_show_dialog_item (GTK_APP_CHOOSER_BUTTON (combobox), gtk_app_chooser_button_set_show_dialog_item (GTK_APP_CHOOSER_BUTTON (combobox),
TRUE); TRUE);
gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (combobox),
TRUE);
/* connect to the detailed signal */ /* connect to the detailed signal */
g_signal_connect (combobox, "custom-item-activated::" CUSTOM_ITEM, g_signal_connect (combobox, "custom-item-activated::" CUSTOM_ITEM,
@ -123,9 +125,10 @@ main (int argc,
/* test refresh on a combo */ /* test refresh on a combo */
gtk_app_chooser_refresh (GTK_APP_CHOOSER (combobox)); gtk_app_chooser_refresh (GTK_APP_CHOOSER (combobox));
#if 0
gtk_app_chooser_button_set_active_custom_item (GTK_APP_CHOOSER_BUTTON (combobox), gtk_app_chooser_button_set_active_custom_item (GTK_APP_CHOOSER_BUTTON (combobox),
CUSTOM_ITEM); CUSTOM_ITEM);
#endif
gtk_widget_show_all (toplevel); gtk_widget_show_all (toplevel);
g_signal_connect (toplevel, "delete-event", g_signal_connect (toplevel, "delete-event",