2 * gtkappchooserwidget.c: an app-chooser widget
4 * Copyright (C) 2004 Novell, Inc.
5 * Copyright (C) 2007, 2010 Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with the Gnome Library; see the file COPYING.LIB. If not,
19 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
22 * Authors: Dave Camp <dave@novell.com>
23 * Alexander Larsson <alexl@redhat.com>
24 * Cosimo Cecchi <ccecchi@redhat.com>
29 #include "gtkappchooserwidget.h"
32 #include "gtkmarshalers.h"
33 #include "gtkappchooserwidget.h"
34 #include "gtkappchooserprivate.h"
35 #include "gtkliststore.h"
36 #include "gtkcellrenderertext.h"
37 #include "gtkcellrendererpixbuf.h"
38 #include "gtktreeview.h"
39 #include "gtktreeselection.h"
40 #include "gtktreemodelsort.h"
41 #include "gtkorientable.h"
42 #include "gtkscrolledwindow.h"
45 #include <glib/gi18n-lib.h>
49 * SECTION:gtkappchooserwidget
50 * @Title: GtkAppChooserWidget
51 * @Short_description: Application chooser widget that can be embedded in other widgets
53 * #GtkAppChooserWidget is a widget for selecting applications.
54 * It is the main building block for #GtkAppChooserDialog. Most
55 * applications only need to use the latter; but you can use
56 * this widget as part of a larger widget if you have special needs.
59 struct _GtkAppChooserWidgetPrivate {
60 GAppInfo *selected_app_info;
65 guint show_default : 1;
66 guint show_recommended : 1;
67 guint show_fallback : 1;
71 GtkWidget *program_list;
72 GtkListStore *program_list_store;
74 GtkCellRenderer *padding_renderer;
93 PROP_CONTENT_TYPE = 1,
96 PROP_SHOW_RECOMMENDED,
105 SIGNAL_APPLICATION_SELECTED,
106 SIGNAL_APPLICATION_ACTIVATED,
107 SIGNAL_POPULATE_POPUP,
111 static guint signals[N_SIGNALS] = { 0, };
113 static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
115 G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_BOX,
116 G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
117 gtk_app_chooser_widget_iface_init));
120 refresh_and_emit_app_selected (GtkAppChooserWidget *self,
121 GtkTreeSelection *selection)
125 GAppInfo *info = NULL;
126 gboolean should_emit = FALSE;
128 if (gtk_tree_selection_get_selected (selection, &model, &iter))
129 gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1);
134 if (self->priv->selected_app_info)
136 if (!g_app_info_equal (self->priv->selected_app_info, info))
139 g_object_unref (self->priv->selected_app_info);
141 self->priv->selected_app_info = info;
147 self->priv->selected_app_info = info;
151 g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0,
152 self->priv->selected_app_info);
156 get_app_info_for_event (GtkAppChooserWidget *self,
157 GdkEventButton *event)
159 GtkTreePath *path = NULL;
163 gboolean recommended;
165 if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (self->priv->program_list),
171 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
173 if (!gtk_tree_model_get_iter (model, &iter, path))
175 gtk_tree_path_free (path);
179 /* we only allow interaction with recommended applications */
180 gtk_tree_model_get (model, &iter,
181 COLUMN_APP_INFO, &info,
182 COLUMN_RECOMMENDED, &recommended,
186 g_clear_object (&info);
192 widget_button_press_event_cb (GtkWidget *widget,
193 GdkEventButton *event,
196 GtkAppChooserWidget *self = user_data;
198 if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
205 info = get_app_info_for_event (self, event);
210 menu = gtk_menu_new ();
212 g_signal_emit (self, signals[SIGNAL_POPULATE_POPUP], 0,
215 g_object_unref (info);
217 /* see if clients added menu items to this container */
218 children = gtk_container_get_children (GTK_CONTAINER (menu));
219 n_children = g_list_length (children);
223 /* actually popup the menu */
224 gtk_menu_attach_to_widget (GTK_MENU (menu), self->priv->program_list, NULL);
225 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
226 event->button, event->time);
229 g_list_free (children);
236 path_is_heading (GtkTreeView *view,
243 model = gtk_tree_view_get_model (view);
244 gtk_tree_model_get_iter (model, &iter, path);
245 gtk_tree_model_get (model, &iter,
246 COLUMN_HEADING, &res,
253 program_list_selection_activated (GtkTreeView *view,
255 GtkTreeViewColumn *column,
258 GtkAppChooserWidget *self = user_data;
259 GtkTreeSelection *selection;
261 if (path_is_heading (view, path))
264 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
266 refresh_and_emit_app_selected (self, selection);
268 g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0,
269 self->priv->selected_app_info);
273 gtk_app_chooser_search_equal_func (GtkTreeModel *model,
279 gchar *normalized_key;
280 gchar *name, *normalized_name;
281 gchar *path, *normalized_path;
282 gchar *basename, *normalized_basename;
287 normalized_key = g_utf8_casefold (key, -1);
288 g_assert (normalized_key != NULL);
292 gtk_tree_model_get (model, iter,
299 normalized_name = g_utf8_casefold (name, -1);
300 g_assert (normalized_name != NULL);
302 if (strncmp (normalized_name, normalized_key, strlen (normalized_key)) == 0)
305 g_free (normalized_name);
308 if (ret && path != NULL)
310 normalized_path = g_utf8_casefold (path, -1);
311 g_assert (normalized_path != NULL);
313 basename = g_path_get_basename (path);
314 g_assert (basename != NULL);
316 normalized_basename = g_utf8_casefold (basename, -1);
317 g_assert (normalized_basename != NULL);
319 if (strncmp (normalized_path, normalized_key, strlen (normalized_key)) == 0 ||
320 strncmp (normalized_basename, normalized_key, strlen (normalized_key)) == 0)
324 g_free (normalized_basename);
325 g_free (normalized_path);
330 g_free (normalized_key);
341 gtk_app_chooser_sort_func (GtkTreeModel *model,
346 gboolean a_recommended, b_recommended;
347 gboolean a_fallback, b_fallback;
348 gboolean a_heading, b_heading;
349 gboolean a_default, b_default;
350 gchar *a_name, *b_name, *a_casefold, *b_casefold;
354 * - <0 if a should show before b
355 * - =0 if a is the same as b
356 * - >0 if a should show after b
359 gtk_tree_model_get (model, a,
360 COLUMN_NAME, &a_name,
361 COLUMN_RECOMMENDED, &a_recommended,
362 COLUMN_FALLBACK, &a_fallback,
363 COLUMN_HEADING, &a_heading,
364 COLUMN_DEFAULT, &a_default,
367 gtk_tree_model_get (model, b,
368 COLUMN_NAME, &b_name,
369 COLUMN_RECOMMENDED, &b_recommended,
370 COLUMN_FALLBACK, &b_fallback,
371 COLUMN_HEADING, &b_heading,
372 COLUMN_DEFAULT, &b_default,
375 /* the default one always wins */
376 if (a_default && !b_default)
382 if (b_default && !a_default)
388 /* the recommended one always wins */
389 if (a_recommended && !b_recommended)
395 if (b_recommended && !a_recommended)
401 /* the recommended one always wins */
402 if (a_fallback && !b_fallback)
408 if (b_fallback && !a_fallback)
414 /* they're both recommended/falback or not, so if one is a heading, wins */
427 /* don't order by name recommended applications, but use GLib's ordering */
430 a_casefold = a_name != NULL ?
431 g_utf8_casefold (a_name, -1) : NULL;
432 b_casefold = b_name != NULL ?
433 g_utf8_casefold (b_name, -1) : NULL;
435 retval = g_strcmp0 (a_casefold, b_casefold);
449 padding_cell_renderer_func (GtkTreeViewColumn *column,
450 GtkCellRenderer *cell,
457 gtk_tree_model_get (model, iter,
458 COLUMN_HEADING, &heading,
475 gtk_app_chooser_selection_func (GtkTreeSelection *selection,
478 gboolean path_currently_selected,
484 gtk_tree_model_get_iter (model, &iter, path);
485 gtk_tree_model_get (model, &iter,
486 COLUMN_HEADING, &heading,
493 compare_apps_func (gconstpointer a,
496 return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
500 gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self,
501 const gchar *heading_title,
502 gboolean show_headings,
503 gboolean recommended,
508 gboolean heading_added, unref_icon;
511 gchar *app_string, *bold_string;
517 heading_added = FALSE;
518 bold_string = g_strdup_printf ("<b>%s</b>", heading_title);
520 for (l = applications; l != NULL; l = l->next)
524 if (!g_app_info_supports_uris (app) &&
525 !g_app_info_supports_files (app))
528 if (g_list_find_custom (exclude_apps, app,
529 (GCompareFunc) compare_apps_func))
532 if (!heading_added && show_headings)
534 gtk_list_store_append (self->priv->program_list_store, &iter);
535 gtk_list_store_set (self->priv->program_list_store, &iter,
536 COLUMN_HEADING_TEXT, bold_string,
537 COLUMN_HEADING, TRUE,
538 COLUMN_RECOMMENDED, recommended,
539 COLUMN_FALLBACK, fallback,
542 heading_added = TRUE;
545 app_string = g_markup_printf_escaped ("%s",
546 g_app_info_get_name (app) != NULL ?
547 g_app_info_get_name (app) : "");
549 icon = g_app_info_get_icon (app);
553 icon = g_themed_icon_new ("application-x-executable");
557 gtk_list_store_append (self->priv->program_list_store, &iter);
558 gtk_list_store_set (self->priv->program_list_store, &iter,
559 COLUMN_APP_INFO, app,
561 COLUMN_NAME, g_app_info_get_name (app),
562 COLUMN_DESC, app_string,
563 COLUMN_EXEC, g_app_info_get_executable (app),
564 COLUMN_HEADING, FALSE,
565 COLUMN_RECOMMENDED, recommended,
566 COLUMN_FALLBACK, fallback,
573 g_object_unref (icon);
576 g_free (bold_string);
583 gtk_app_chooser_add_default (GtkAppChooserWidget *self,
592 string = g_strdup_printf ("<b>%s</b>", _("Default Application"));
594 gtk_list_store_append (self->priv->program_list_store, &iter);
595 gtk_list_store_set (self->priv->program_list_store, &iter,
596 COLUMN_HEADING_TEXT, string,
597 COLUMN_HEADING, TRUE,
598 COLUMN_DEFAULT, TRUE,
603 string = g_markup_printf_escaped ("%s",
604 g_app_info_get_name (app) != NULL ?
605 g_app_info_get_name (app) : "");
607 icon = g_app_info_get_icon (app);
610 icon = g_themed_icon_new ("application-x-executable");
614 gtk_list_store_append (self->priv->program_list_store, &iter);
615 gtk_list_store_set (self->priv->program_list_store, &iter,
616 COLUMN_APP_INFO, app,
618 COLUMN_NAME, g_app_info_get_name (app),
620 COLUMN_EXEC, g_app_info_get_executable (app),
621 COLUMN_HEADING, FALSE,
622 COLUMN_DEFAULT, TRUE,
628 g_object_unref (icon);
632 add_no_applications_label (GtkAppChooserWidget *self)
634 gchar *text = NULL, *desc = NULL;
638 if (self->priv->default_text == NULL)
640 if (self->priv->content_type)
641 desc = g_content_type_get_description (self->priv->content_type);
643 string = text = g_strdup_printf (_("No applications available to open \"%s\""),
649 string = self->priv->default_text;
652 gtk_list_store_append (self->priv->program_list_store, &iter);
653 gtk_list_store_set (self->priv->program_list_store, &iter,
654 COLUMN_HEADING_TEXT, string,
655 COLUMN_HEADING, TRUE,
662 gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
665 GAppInfo *info = NULL;
668 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
669 gtk_tree_model_get_iter_first (model, &iter);
673 gtk_tree_model_get (model, &iter,
674 COLUMN_APP_INFO, &info,
680 if (!gtk_tree_model_iter_next (model, &iter))
686 GtkTreeSelection *selection;
688 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
689 gtk_tree_selection_select_iter (selection, &iter);
691 g_object_unref (info);
696 gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
698 GList *all_applications = NULL;
699 GList *recommended_apps = NULL;
700 GList *fallback_apps = NULL;
701 GList *exclude_apps = NULL;
702 GAppInfo *default_app = NULL;
703 gboolean show_headings;
706 show_headings = TRUE;
709 if (self->priv->show_all)
710 show_headings = FALSE;
712 if (self->priv->show_default && self->priv->content_type)
714 default_app = g_app_info_get_default_for_type (self->priv->content_type, FALSE);
716 if (default_app != NULL)
718 gtk_app_chooser_add_default (self, default_app);
720 exclude_apps = g_list_prepend (exclude_apps, default_app);
725 if ((self->priv->content_type && self->priv->show_recommended) || self->priv->show_all)
727 if (self->priv->content_type)
728 recommended_apps = g_app_info_get_recommended_for_type (self->priv->content_type);
730 apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
732 !self->priv->show_all, /* mark as recommended */
733 FALSE, /* mark as fallback */
734 recommended_apps, exclude_apps);
736 exclude_apps = g_list_concat (exclude_apps,
737 g_list_copy (recommended_apps));
740 if ((self->priv->content_type && self->priv->show_fallback) || self->priv->show_all)
742 if (self->priv->content_type)
743 fallback_apps = g_app_info_get_fallback_for_type (self->priv->content_type);
745 apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
747 FALSE, /* mark as recommended */
748 !self->priv->show_all, /* mark as fallback */
749 fallback_apps, exclude_apps);
750 exclude_apps = g_list_concat (exclude_apps,
751 g_list_copy (fallback_apps));
755 if (self->priv->show_other || self->priv->show_all)
757 all_applications = g_app_info_get_all ();
759 apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
763 all_applications, exclude_apps);
767 add_no_applications_label (self);
769 gtk_app_chooser_widget_select_first (self);
771 if (default_app != NULL)
772 g_object_unref (default_app);
774 if (all_applications != NULL)
775 g_list_free_full (all_applications, g_object_unref);
777 if (recommended_apps != NULL)
778 g_list_free_full (recommended_apps, g_object_unref);
780 if (fallback_apps != NULL)
781 g_list_free_full (fallback_apps, g_object_unref);
783 if (exclude_apps != NULL)
784 g_list_free (exclude_apps);
788 gtk_app_chooser_widget_add_items (GtkAppChooserWidget *self)
790 GtkCellRenderer *renderer;
791 GtkTreeViewColumn *column;
794 /* create list store */
795 self->priv->program_list_store = gtk_list_store_new (NUM_COLUMNS,
806 sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->priv->program_list_store));
808 gtk_tree_view_set_model (GTK_TREE_VIEW (self->priv->program_list),
809 GTK_TREE_MODEL (sort));
810 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort),
813 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
815 gtk_app_chooser_sort_func,
817 gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->priv->program_list),
819 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->priv->program_list),
820 gtk_app_chooser_search_equal_func,
823 column = gtk_tree_view_column_new ();
825 /* initial padding */
826 renderer = gtk_cell_renderer_text_new ();
827 gtk_tree_view_column_pack_start (column, renderer, FALSE);
828 g_object_set (renderer,
829 "xpad", self->priv->show_all ? 0 : 6,
831 self->priv->padding_renderer = renderer;
833 /* heading text renderer */
834 renderer = gtk_cell_renderer_text_new ();
835 gtk_tree_view_column_pack_start (column, renderer, FALSE);
836 gtk_tree_view_column_set_attributes (column, renderer,
837 "markup", COLUMN_HEADING_TEXT,
838 "visible", COLUMN_HEADING,
840 g_object_set (renderer,
844 "wrap-mode", PANGO_WRAP_WORD,
847 /* padding renderer for non-heading cells */
848 renderer = gtk_cell_renderer_text_new ();
849 gtk_tree_view_column_pack_start (column, renderer, FALSE);
850 gtk_tree_view_column_set_cell_data_func (column, renderer,
851 padding_cell_renderer_func,
854 /* app icon renderer */
855 renderer = gtk_cell_renderer_pixbuf_new ();
856 gtk_tree_view_column_pack_start (column, renderer, FALSE);
857 gtk_tree_view_column_set_attributes (column, renderer,
858 "gicon", COLUMN_GICON,
860 g_object_set (renderer,
861 "stock-size", GTK_ICON_SIZE_MENU,
864 /* app name renderer */
865 renderer = gtk_cell_renderer_text_new ();
866 gtk_tree_view_column_pack_start (column, renderer, TRUE);
867 gtk_tree_view_column_set_attributes (column, renderer,
868 "markup", COLUMN_DESC,
870 g_object_set (renderer,
871 "ellipsize", PANGO_ELLIPSIZE_END,
872 "ellipsize-set", TRUE,
875 gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
876 gtk_tree_view_append_column (GTK_TREE_VIEW (self->priv->program_list), column);
878 /* populate the widget */
879 gtk_app_chooser_widget_real_add_items (self);
883 gtk_app_chooser_widget_set_property (GObject *object,
888 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
892 case PROP_CONTENT_TYPE:
893 self->priv->content_type = g_value_dup_string (value);
895 case PROP_SHOW_DEFAULT:
896 gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value));
898 case PROP_SHOW_RECOMMENDED:
899 gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value));
901 case PROP_SHOW_FALLBACK:
902 gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value));
904 case PROP_SHOW_OTHER:
905 gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value));
908 gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value));
910 case PROP_DEFAULT_TEXT:
911 gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value));
914 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
920 gtk_app_chooser_widget_get_property (GObject *object,
925 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
929 case PROP_CONTENT_TYPE:
930 g_value_set_string (value, self->priv->content_type);
932 case PROP_SHOW_DEFAULT:
933 g_value_set_boolean (value, self->priv->show_default);
935 case PROP_SHOW_RECOMMENDED:
936 g_value_set_boolean (value, self->priv->show_recommended);
938 case PROP_SHOW_FALLBACK:
939 g_value_set_boolean (value, self->priv->show_fallback);
941 case PROP_SHOW_OTHER:
942 g_value_set_boolean (value, self->priv->show_other);
945 g_value_set_boolean (value, self->priv->show_all);
947 case PROP_DEFAULT_TEXT:
948 g_value_set_string (value, self->priv->default_text);
951 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
957 gtk_app_chooser_widget_constructed (GObject *object)
959 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
961 if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL)
962 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object);
964 gtk_app_chooser_widget_add_items (self);
968 gtk_app_chooser_widget_finalize (GObject *object)
970 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
972 g_free (self->priv->content_type);
973 g_free (self->priv->default_text);
975 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
979 gtk_app_chooser_widget_dispose (GObject *object)
981 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
983 if (self->priv->selected_app_info != NULL)
985 g_object_unref (self->priv->selected_app_info);
986 self->priv->selected_app_info = NULL;
989 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
993 gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
995 GObjectClass *gobject_class;
998 gobject_class = G_OBJECT_CLASS (klass);
999 gobject_class->dispose = gtk_app_chooser_widget_dispose;
1000 gobject_class->finalize = gtk_app_chooser_widget_finalize;
1001 gobject_class->set_property = gtk_app_chooser_widget_set_property;
1002 gobject_class->get_property = gtk_app_chooser_widget_get_property;
1003 gobject_class->constructed = gtk_app_chooser_widget_constructed;
1005 g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
1008 * GtkAppChooserWidget:show-default:
1010 * The ::show-default property determines whether the app chooser
1011 * should show the default handler for the content type in a
1012 * separate section. If %FALSE, the default handler is listed
1013 * among the recommended applications.
1015 pspec = g_param_spec_boolean ("show-default",
1016 P_("Show default app"),
1017 P_("Whether the widget should show the default application"),
1019 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1020 g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec);
1023 * GtkAppChooserWidget:show-recommended:
1025 * The #GtkAppChooserWidget:show-recommended property determines whether the app chooser
1026 * should show a section for recommended applications. If %FALSE, the
1027 * recommended applications are listed among the other applications.
1029 pspec = g_param_spec_boolean ("show-recommended",
1030 P_("Show recommended apps"),
1031 P_("Whether the widget should show recommended applications"),
1033 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1034 g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec);
1037 * GtkAppChooserWidget:show-fallback:
1039 * The #GtkAppChooserWidget:show-fallback property determines whether the app chooser
1040 * should show a section for related applications. If %FALSE, the
1041 * related applications are listed among the other applications.
1043 pspec = g_param_spec_boolean ("show-fallback",
1044 P_("Show fallback apps"),
1045 P_("Whether the widget should show fallback applications"),
1047 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1048 g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec);
1051 * GtkAppChooserWidget:show-other:
1053 * The #GtkAppChooserWidget:show-other property determines whether the app chooser
1054 * should show a section for other applications.
1056 pspec = g_param_spec_boolean ("show-other",
1057 P_("Show other apps"),
1058 P_("Whether the widget should show other applications"),
1060 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1061 g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec);
1064 * GtkAppChooserWidget:show-all:
1066 * If the #GtkAppChooserWidget:show-all property is %TRUE, the app chooser presents
1067 * all applications in a single list, without subsections for
1068 * default, recommended or related applications.
1070 pspec = g_param_spec_boolean ("show-all",
1071 P_("Show all apps"),
1072 P_("Whether the widget should show all applications"),
1074 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1075 g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec);
1078 * GtkAppChooserWidget:default-text:
1080 * The #GtkAppChooserWidget:default-text property determines the text that appears
1081 * in the widget when there are no applications for the given content type.
1082 * See also gtk_app_chooser_widget_set_default_text().
1084 pspec = g_param_spec_string ("default-text",
1085 P_("Widget's default text"),
1086 P_("The default text appearing when there are no applications"),
1088 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1089 g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec);
1092 * GtkAppChooserWidget::application-selected:
1093 * @self: the object which received the signal
1094 * @application: the selected #GAppInfo
1096 * Emitted when an application item is selected from the widget's list.
1098 signals[SIGNAL_APPLICATION_SELECTED] =
1099 g_signal_new ("application-selected",
1100 GTK_TYPE_APP_CHOOSER_WIDGET,
1102 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
1104 _gtk_marshal_VOID__OBJECT,
1106 1, G_TYPE_APP_INFO);
1109 * GtkAppChooserWidget::application-activated:
1110 * @self: the object which received the signal
1111 * @application: the activated #GAppInfo
1113 * Emitted when an application item is activated from the widget's list.
1114 * This usually happens when the user double clicks an item, or an item
1115 * is selected and the user presses one of the keys Space, Shift+Space,
1118 signals[SIGNAL_APPLICATION_ACTIVATED] =
1119 g_signal_new ("application-activated",
1120 GTK_TYPE_APP_CHOOSER_WIDGET,
1122 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
1124 _gtk_marshal_VOID__OBJECT,
1126 1, G_TYPE_APP_INFO);
1129 * GtkAppChooserWidget::populate-popup:
1130 * @self: the object which received the signal
1131 * @menu: the #GtkMenu to populate
1132 * @application: the current #GAppInfo
1134 * Emitted when a context menu is about to popup over an application item.
1135 * Clients can insert menu items into the provided #GtkMenu object in the
1136 * callback of this signal; the context menu will be shown over the item if
1137 * at least one item has been added to the menu.
1139 signals[SIGNAL_POPULATE_POPUP] =
1140 g_signal_new ("populate-popup",
1141 GTK_TYPE_APP_CHOOSER_WIDGET,
1143 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, populate_popup),
1145 _gtk_marshal_VOID__OBJECT_OBJECT,
1147 2, GTK_TYPE_MENU, G_TYPE_APP_INFO);
1149 g_type_class_add_private (klass, sizeof (GtkAppChooserWidgetPrivate));
1153 gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
1155 GtkWidget *scrolled_window;
1156 GtkTreeSelection *selection;
1158 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTK_TYPE_APP_CHOOSER_WIDGET,
1159 GtkAppChooserWidgetPrivate);
1160 gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
1162 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1163 gtk_widget_set_size_request (scrolled_window, 400, 300);
1164 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
1166 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1168 GTK_POLICY_AUTOMATIC);
1169 gtk_widget_show (scrolled_window);
1171 self->priv->program_list = gtk_tree_view_new ();
1172 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->priv->program_list),
1174 gtk_container_add (GTK_CONTAINER (scrolled_window), self->priv->program_list);
1175 gtk_box_pack_start (GTK_BOX (self), scrolled_window, TRUE, TRUE, 0);
1176 gtk_widget_show (self->priv->program_list);
1178 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
1179 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1180 gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func,
1182 g_signal_connect_swapped (selection, "changed",
1183 G_CALLBACK (refresh_and_emit_app_selected),
1185 g_signal_connect (self->priv->program_list, "row-activated",
1186 G_CALLBACK (program_list_selection_activated),
1188 g_signal_connect (self->priv->program_list, "button-press-event",
1189 G_CALLBACK (widget_button_press_event_cb),
1194 gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
1196 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1198 if (self->priv->selected_app_info == NULL)
1201 return g_object_ref (self->priv->selected_app_info);
1205 gtk_app_chooser_widget_refresh (GtkAppChooser *object)
1207 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1209 if (self->priv->program_list_store != NULL)
1211 gtk_list_store_clear (self->priv->program_list_store);
1213 /* don't add additional xpad if we don't have headings */
1214 g_object_set (self->priv->padding_renderer,
1215 "visible", !self->priv->show_all,
1218 gtk_app_chooser_widget_real_add_items (self);
1223 gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
1225 iface->get_app_info = gtk_app_chooser_widget_get_app_info;
1226 iface->refresh = gtk_app_chooser_widget_refresh;
1230 * gtk_app_chooser_widget_new:
1231 * @content_type: the content type to show applications for
1233 * Creates a new #GtkAppChooserWidget for applications
1234 * that can handle content of the given type.
1236 * Returns: a newly created #GtkAppChooserWidget
1241 gtk_app_chooser_widget_new (const gchar *content_type)
1243 return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
1244 "content-type", content_type,
1249 * gtk_app_chooser_widget_set_show_default:
1250 * @self: a #GtkAppChooserWidget
1251 * @setting: the new value for #GtkAppChooserWidget:show-default
1253 * Sets whether the app chooser should show the default handler
1254 * for the content type in a separate section.
1259 gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
1262 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1264 if (self->priv->show_default != setting)
1266 self->priv->show_default = setting;
1268 g_object_notify (G_OBJECT (self), "show-default");
1270 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1275 * gtk_app_chooser_widget_get_show_default:
1276 * @self: a #GtkAppChooserWidget
1278 * Returns the current value of the #GtkAppChooserWidget:show-default
1281 * Returns: the value of #GtkAppChooserWidget:show-default
1286 gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
1288 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1290 return self->priv->show_default;
1294 * gtk_app_chooser_widget_set_show_recommended:
1295 * @self: a #GtkAppChooserWidget
1296 * @setting: the new value for #GtkAppChooserWidget:show-recommended
1298 * Sets whether the app chooser should show recommended applications
1299 * for the content type in a separate section.
1304 gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
1307 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1309 if (self->priv->show_recommended != setting)
1311 self->priv->show_recommended = setting;
1313 g_object_notify (G_OBJECT (self), "show-recommended");
1315 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1320 * gtk_app_chooser_widget_get_show_recommended:
1321 * @self: a #GtkAppChooserWidget
1323 * Returns the current value of the #GtkAppChooserWidget:show-recommended
1326 * Returns: the value of #GtkAppChooserWidget:show-recommended
1331 gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
1333 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1335 return self->priv->show_recommended;
1339 * gtk_app_chooser_widget_set_show_fallback:
1340 * @self: a #GtkAppChooserWidget
1341 * @setting: the new value for #GtkAppChooserWidget:show-fallback
1343 * Sets whether the app chooser should show related applications
1344 * for the content type in a separate section.
1349 gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
1352 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1354 if (self->priv->show_fallback != setting)
1356 self->priv->show_fallback = setting;
1358 g_object_notify (G_OBJECT (self), "show-fallback");
1360 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1365 * gtk_app_chooser_widget_get_show_fallback:
1366 * @self: a #GtkAppChooserWidget
1368 * Returns the current value of the #GtkAppChooserWidget:show-fallback
1371 * Returns: the value of #GtkAppChooserWidget:show-fallback
1376 gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
1378 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1380 return self->priv->show_fallback;
1384 * gtk_app_chooser_widget_set_show_other:
1385 * @self: a #GtkAppChooserWidget
1386 * @setting: the new value for #GtkAppChooserWidget:show-other
1388 * Sets whether the app chooser should show applications
1389 * which are unrelated to the content type.
1394 gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
1397 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1399 if (self->priv->show_other != setting)
1401 self->priv->show_other = setting;
1403 g_object_notify (G_OBJECT (self), "show-other");
1405 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1410 * gtk_app_chooser_widget_get_show_other:
1411 * @self: a #GtkAppChooserWidget
1413 * Returns the current value of the #GtkAppChooserWidget:show-other
1416 * Returns: the value of #GtkAppChooserWidget:show-other
1421 gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
1423 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1425 return self->priv->show_other;
1429 * gtk_app_chooser_widget_set_show_all:
1430 * @self: a #GtkAppChooserWidget
1431 * @setting: the new value for #GtkAppChooserWidget:show-all
1433 * Sets whether the app chooser should show all applications
1439 gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
1442 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1444 if (self->priv->show_all != setting)
1446 self->priv->show_all = setting;
1448 g_object_notify (G_OBJECT (self), "show-all");
1450 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1455 * gtk_app_chooser_widget_get_show_all:
1456 * @self: a #GtkAppChooserWidget
1458 * Returns the current value of the #GtkAppChooserWidget:show-all
1461 * Returns: the value of #GtkAppChooserWidget:show-all
1466 gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
1468 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1470 return self->priv->show_all;
1474 * gtk_app_chooser_widget_set_default_text:
1475 * @self: a #GtkAppChooserWidget
1476 * @text: the new value for #GtkAppChooserWidget:default-text
1478 * Sets the text that is shown if there are not applications
1479 * that can handle the content type.
1482 gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
1485 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1487 if (g_strcmp0 (text, self->priv->default_text) != 0)
1489 g_free (self->priv->default_text);
1490 self->priv->default_text = g_strdup (text);
1492 g_object_notify (G_OBJECT (self), "default-text");
1494 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1499 * gtk_app_chooser_widget_get_default_text:
1500 * @self: a #GtkAppChooserWidget
1502 * Returns the text that is shown if there are not applications
1503 * that can handle the content type.
1505 * Returns: the value of #GtkAppChooserWidget:default-text
1510 gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
1512 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
1514 return self->priv->default_text;