Commit f9379adc authored by Matthias Clasen's avatar Matthias Clasen

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
parent e97ed437
......@@ -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
......
......@@ -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
......
......@@ -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"
......
......@@ -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)
......
......@@ -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
......
......@@ -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"
......
......@@ -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",
......
......@@ -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);
......
......@@ -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",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment