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 this library. If not, see <http://www.gnu.org/licenses/>.
20 * Authors: Dave Camp <dave@novell.com>
21 * Alexander Larsson <alexl@redhat.com>
22 * Cosimo Cecchi <ccecchi@redhat.com>
27 #include "gtkappchooserwidget.h"
30 #include "gtkmarshalers.h"
31 #include "gtkappchooserwidget.h"
32 #include "gtkappchooserprivate.h"
33 #include "gtkliststore.h"
34 #include "gtkcellrenderertext.h"
35 #include "gtkcellrendererpixbuf.h"
36 #include "gtktreeview.h"
37 #include "gtktreeselection.h"
38 #include "gtktreemodelsort.h"
39 #include "gtkorientable.h"
40 #include "gtkscrolledwindow.h"
43 #include <glib/gi18n-lib.h>
47 * SECTION:gtkappchooserwidget
48 * @Title: GtkAppChooserWidget
49 * @Short_description: Application chooser widget that can be embedded in other widgets
51 * #GtkAppChooserWidget is a widget for selecting applications.
52 * It is the main building block for #GtkAppChooserDialog. Most
53 * applications only need to use the latter; but you can use
54 * this widget as part of a larger widget if you have special needs.
56 * #GtkAppChooserWidget offers detailed control over what applications
57 * are shown, using the
58 * #GtkAppChooserWidget:show-default,
59 * #GtkAppChooserWidget:show-recommended,
60 * #GtkAppChooserWidget:show-fallback,
61 * #GtkAppChooserWidget:show-other and
62 * #GtkAppChooserWidget:show-all
63 * properties. See the #GtkAppChooser documentation for more information
64 * about these groups of applications.
66 * To keep track of the selected application, use the
67 * #GtkAppChooserWidget::application-selected and #GtkAppChooserWidget::application-activated signals.
70 struct _GtkAppChooserWidgetPrivate {
71 GAppInfo *selected_app_info;
76 guint show_default : 1;
77 guint show_recommended : 1;
78 guint show_fallback : 1;
82 GtkWidget *program_list;
83 GtkListStore *program_list_store;
85 GtkCellRenderer *padding_renderer;
104 PROP_CONTENT_TYPE = 1,
107 PROP_SHOW_RECOMMENDED,
116 SIGNAL_APPLICATION_SELECTED,
117 SIGNAL_APPLICATION_ACTIVATED,
118 SIGNAL_POPULATE_POPUP,
122 static guint signals[N_SIGNALS] = { 0, };
124 static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
126 G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_BOX,
127 G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
128 gtk_app_chooser_widget_iface_init));
131 refresh_and_emit_app_selected (GtkAppChooserWidget *self,
132 GtkTreeSelection *selection)
136 GAppInfo *info = NULL;
137 gboolean should_emit = FALSE;
139 if (gtk_tree_selection_get_selected (selection, &model, &iter))
140 gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1);
145 if (self->priv->selected_app_info)
147 if (!g_app_info_equal (self->priv->selected_app_info, info))
150 g_object_unref (self->priv->selected_app_info);
152 self->priv->selected_app_info = info;
158 self->priv->selected_app_info = info;
162 g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0,
163 self->priv->selected_app_info);
167 get_app_info_for_event (GtkAppChooserWidget *self,
168 GdkEventButton *event)
170 GtkTreePath *path = NULL;
174 gboolean recommended;
176 if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (self->priv->program_list),
182 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
184 if (!gtk_tree_model_get_iter (model, &iter, path))
186 gtk_tree_path_free (path);
190 /* we only allow interaction with recommended applications */
191 gtk_tree_model_get (model, &iter,
192 COLUMN_APP_INFO, &info,
193 COLUMN_RECOMMENDED, &recommended,
197 g_clear_object (&info);
203 widget_button_press_event_cb (GtkWidget *widget,
204 GdkEventButton *event,
207 GtkAppChooserWidget *self = user_data;
209 if (event->button == GDK_BUTTON_SECONDARY && event->type == GDK_BUTTON_PRESS)
216 info = get_app_info_for_event (self, event);
221 menu = gtk_menu_new ();
223 g_signal_emit (self, signals[SIGNAL_POPULATE_POPUP], 0,
226 g_object_unref (info);
228 /* see if clients added menu items to this container */
229 children = gtk_container_get_children (GTK_CONTAINER (menu));
230 n_children = g_list_length (children);
234 /* actually popup the menu */
235 gtk_menu_attach_to_widget (GTK_MENU (menu), self->priv->program_list, NULL);
236 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
237 event->button, event->time);
240 g_list_free (children);
247 path_is_heading (GtkTreeView *view,
254 model = gtk_tree_view_get_model (view);
255 gtk_tree_model_get_iter (model, &iter, path);
256 gtk_tree_model_get (model, &iter,
257 COLUMN_HEADING, &res,
264 program_list_selection_activated (GtkTreeView *view,
266 GtkTreeViewColumn *column,
269 GtkAppChooserWidget *self = user_data;
270 GtkTreeSelection *selection;
272 if (path_is_heading (view, path))
275 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
277 refresh_and_emit_app_selected (self, selection);
279 g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0,
280 self->priv->selected_app_info);
284 gtk_app_chooser_search_equal_func (GtkTreeModel *model,
290 gchar *normalized_key;
291 gchar *name, *normalized_name;
292 gchar *path, *normalized_path;
293 gchar *basename, *normalized_basename;
298 normalized_key = g_utf8_casefold (key, -1);
299 g_assert (normalized_key != NULL);
303 gtk_tree_model_get (model, iter,
310 normalized_name = g_utf8_casefold (name, -1);
311 g_assert (normalized_name != NULL);
313 if (strncmp (normalized_name, normalized_key, strlen (normalized_key)) == 0)
316 g_free (normalized_name);
319 if (ret && path != NULL)
321 normalized_path = g_utf8_casefold (path, -1);
322 g_assert (normalized_path != NULL);
324 basename = g_path_get_basename (path);
325 g_assert (basename != NULL);
327 normalized_basename = g_utf8_casefold (basename, -1);
328 g_assert (normalized_basename != NULL);
330 if (strncmp (normalized_path, normalized_key, strlen (normalized_key)) == 0 ||
331 strncmp (normalized_basename, normalized_key, strlen (normalized_key)) == 0)
335 g_free (normalized_basename);
336 g_free (normalized_path);
341 g_free (normalized_key);
352 gtk_app_chooser_sort_func (GtkTreeModel *model,
357 gboolean a_recommended, b_recommended;
358 gboolean a_fallback, b_fallback;
359 gboolean a_heading, b_heading;
360 gboolean a_default, b_default;
361 gchar *a_name, *b_name, *a_casefold, *b_casefold;
365 * - <0 if a should show before b
366 * - =0 if a is the same as b
367 * - >0 if a should show after b
370 gtk_tree_model_get (model, a,
371 COLUMN_NAME, &a_name,
372 COLUMN_RECOMMENDED, &a_recommended,
373 COLUMN_FALLBACK, &a_fallback,
374 COLUMN_HEADING, &a_heading,
375 COLUMN_DEFAULT, &a_default,
378 gtk_tree_model_get (model, b,
379 COLUMN_NAME, &b_name,
380 COLUMN_RECOMMENDED, &b_recommended,
381 COLUMN_FALLBACK, &b_fallback,
382 COLUMN_HEADING, &b_heading,
383 COLUMN_DEFAULT, &b_default,
386 /* the default one always wins */
387 if (a_default && !b_default)
393 if (b_default && !a_default)
399 /* the recommended one always wins */
400 if (a_recommended && !b_recommended)
406 if (b_recommended && !a_recommended)
412 /* the recommended one always wins */
413 if (a_fallback && !b_fallback)
419 if (b_fallback && !a_fallback)
425 /* they're both recommended/falback or not, so if one is a heading, wins */
438 /* don't order by name recommended applications, but use GLib's ordering */
441 a_casefold = a_name != NULL ?
442 g_utf8_casefold (a_name, -1) : NULL;
443 b_casefold = b_name != NULL ?
444 g_utf8_casefold (b_name, -1) : NULL;
446 retval = g_strcmp0 (a_casefold, b_casefold);
460 padding_cell_renderer_func (GtkTreeViewColumn *column,
461 GtkCellRenderer *cell,
468 gtk_tree_model_get (model, iter,
469 COLUMN_HEADING, &heading,
486 gtk_app_chooser_selection_func (GtkTreeSelection *selection,
489 gboolean path_currently_selected,
495 gtk_tree_model_get_iter (model, &iter, path);
496 gtk_tree_model_get (model, &iter,
497 COLUMN_HEADING, &heading,
504 compare_apps_func (gconstpointer a,
507 return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
511 gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self,
512 const gchar *heading_title,
513 gboolean show_headings,
514 gboolean recommended,
519 gboolean heading_added, unref_icon;
522 gchar *app_string, *bold_string;
528 heading_added = FALSE;
529 bold_string = g_strdup_printf ("<b>%s</b>", heading_title);
531 for (l = applications; l != NULL; l = l->next)
535 if (!g_app_info_supports_uris (app) &&
536 !g_app_info_supports_files (app))
539 if (!g_app_info_should_show (app))
542 if (g_list_find_custom (exclude_apps, app,
543 (GCompareFunc) compare_apps_func))
546 if (!heading_added && show_headings)
548 gtk_list_store_append (self->priv->program_list_store, &iter);
549 gtk_list_store_set (self->priv->program_list_store, &iter,
550 COLUMN_HEADING_TEXT, bold_string,
551 COLUMN_HEADING, TRUE,
552 COLUMN_RECOMMENDED, recommended,
553 COLUMN_FALLBACK, fallback,
556 heading_added = TRUE;
559 app_string = g_markup_printf_escaped ("%s",
560 g_app_info_get_name (app) != NULL ?
561 g_app_info_get_name (app) : "");
563 icon = g_app_info_get_icon (app);
567 icon = g_themed_icon_new ("application-x-executable");
571 gtk_list_store_append (self->priv->program_list_store, &iter);
572 gtk_list_store_set (self->priv->program_list_store, &iter,
573 COLUMN_APP_INFO, app,
575 COLUMN_NAME, g_app_info_get_name (app),
576 COLUMN_DESC, app_string,
577 COLUMN_EXEC, g_app_info_get_executable (app),
578 COLUMN_HEADING, FALSE,
579 COLUMN_RECOMMENDED, recommended,
580 COLUMN_FALLBACK, fallback,
587 g_object_unref (icon);
590 g_free (bold_string);
597 gtk_app_chooser_add_default (GtkAppChooserWidget *self,
606 string = g_strdup_printf ("<b>%s</b>", _("Default Application"));
608 gtk_list_store_append (self->priv->program_list_store, &iter);
609 gtk_list_store_set (self->priv->program_list_store, &iter,
610 COLUMN_HEADING_TEXT, string,
611 COLUMN_HEADING, TRUE,
612 COLUMN_DEFAULT, TRUE,
617 string = g_markup_printf_escaped ("%s",
618 g_app_info_get_name (app) != NULL ?
619 g_app_info_get_name (app) : "");
621 icon = g_app_info_get_icon (app);
624 icon = g_themed_icon_new ("application-x-executable");
628 gtk_list_store_append (self->priv->program_list_store, &iter);
629 gtk_list_store_set (self->priv->program_list_store, &iter,
630 COLUMN_APP_INFO, app,
632 COLUMN_NAME, g_app_info_get_name (app),
634 COLUMN_EXEC, g_app_info_get_executable (app),
635 COLUMN_HEADING, FALSE,
636 COLUMN_DEFAULT, TRUE,
642 g_object_unref (icon);
646 add_no_applications_label (GtkAppChooserWidget *self)
648 gchar *text = NULL, *desc = NULL;
652 if (self->priv->default_text == NULL)
654 if (self->priv->content_type)
655 desc = g_content_type_get_description (self->priv->content_type);
657 string = text = g_strdup_printf (_("No applications available to open \"%s\""),
663 string = self->priv->default_text;
666 gtk_list_store_append (self->priv->program_list_store, &iter);
667 gtk_list_store_set (self->priv->program_list_store, &iter,
668 COLUMN_HEADING_TEXT, string,
669 COLUMN_HEADING, TRUE,
676 gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
679 GAppInfo *info = NULL;
682 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
683 gtk_tree_model_get_iter_first (model, &iter);
687 gtk_tree_model_get (model, &iter,
688 COLUMN_APP_INFO, &info,
694 if (!gtk_tree_model_iter_next (model, &iter))
700 GtkTreeSelection *selection;
702 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
703 gtk_tree_selection_select_iter (selection, &iter);
705 g_object_unref (info);
710 gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
712 GList *all_applications = NULL;
713 GList *recommended_apps = NULL;
714 GList *fallback_apps = NULL;
715 GList *exclude_apps = NULL;
716 GAppInfo *default_app = NULL;
717 gboolean show_headings;
720 show_headings = TRUE;
723 if (self->priv->show_all)
724 show_headings = FALSE;
726 if (self->priv->show_default && self->priv->content_type)
728 default_app = g_app_info_get_default_for_type (self->priv->content_type, FALSE);
730 if (default_app != NULL)
732 gtk_app_chooser_add_default (self, default_app);
734 exclude_apps = g_list_prepend (exclude_apps, default_app);
739 if ((self->priv->content_type && self->priv->show_recommended) || self->priv->show_all)
741 if (self->priv->content_type)
742 recommended_apps = g_app_info_get_recommended_for_type (self->priv->content_type);
744 apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
746 !self->priv->show_all, /* mark as recommended */
747 FALSE, /* mark as fallback */
748 recommended_apps, exclude_apps);
750 exclude_apps = g_list_concat (exclude_apps,
751 g_list_copy (recommended_apps));
754 if ((self->priv->content_type && self->priv->show_fallback) || self->priv->show_all)
756 if (self->priv->content_type)
757 fallback_apps = g_app_info_get_fallback_for_type (self->priv->content_type);
759 apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
761 FALSE, /* mark as recommended */
762 !self->priv->show_all, /* mark as fallback */
763 fallback_apps, exclude_apps);
764 exclude_apps = g_list_concat (exclude_apps,
765 g_list_copy (fallback_apps));
769 if (self->priv->show_other || self->priv->show_all)
771 all_applications = g_app_info_get_all ();
773 apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
777 all_applications, exclude_apps);
781 add_no_applications_label (self);
783 gtk_app_chooser_widget_select_first (self);
785 if (default_app != NULL)
786 g_object_unref (default_app);
788 if (all_applications != NULL)
789 g_list_free_full (all_applications, g_object_unref);
791 if (recommended_apps != NULL)
792 g_list_free_full (recommended_apps, g_object_unref);
794 if (fallback_apps != NULL)
795 g_list_free_full (fallback_apps, g_object_unref);
797 if (exclude_apps != NULL)
798 g_list_free (exclude_apps);
802 gtk_app_chooser_widget_add_items (GtkAppChooserWidget *self)
804 GtkCellRenderer *renderer;
805 GtkTreeViewColumn *column;
808 /* create list store */
809 self->priv->program_list_store = gtk_list_store_new (NUM_COLUMNS,
820 sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->priv->program_list_store));
822 gtk_tree_view_set_model (GTK_TREE_VIEW (self->priv->program_list),
823 GTK_TREE_MODEL (sort));
824 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort),
827 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
829 gtk_app_chooser_sort_func,
831 gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->priv->program_list),
833 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->priv->program_list),
834 gtk_app_chooser_search_equal_func,
837 column = gtk_tree_view_column_new ();
839 /* initial padding */
840 renderer = gtk_cell_renderer_text_new ();
841 gtk_tree_view_column_pack_start (column, renderer, FALSE);
842 g_object_set (renderer,
843 "xpad", self->priv->show_all ? 0 : 6,
845 self->priv->padding_renderer = renderer;
847 /* heading text renderer */
848 renderer = gtk_cell_renderer_text_new ();
849 gtk_tree_view_column_pack_start (column, renderer, FALSE);
850 gtk_tree_view_column_set_attributes (column, renderer,
851 "markup", COLUMN_HEADING_TEXT,
852 "visible", COLUMN_HEADING,
854 g_object_set (renderer,
858 "wrap-mode", PANGO_WRAP_WORD,
861 /* padding renderer for non-heading cells */
862 renderer = gtk_cell_renderer_text_new ();
863 gtk_tree_view_column_pack_start (column, renderer, FALSE);
864 gtk_tree_view_column_set_cell_data_func (column, renderer,
865 padding_cell_renderer_func,
868 /* app icon renderer */
869 renderer = gtk_cell_renderer_pixbuf_new ();
870 gtk_tree_view_column_pack_start (column, renderer, FALSE);
871 gtk_tree_view_column_set_attributes (column, renderer,
872 "gicon", COLUMN_GICON,
874 g_object_set (renderer,
875 "stock-size", GTK_ICON_SIZE_MENU,
878 /* app name renderer */
879 renderer = gtk_cell_renderer_text_new ();
880 gtk_tree_view_column_pack_start (column, renderer, TRUE);
881 gtk_tree_view_column_set_attributes (column, renderer,
882 "markup", COLUMN_DESC,
884 g_object_set (renderer,
885 "ellipsize", PANGO_ELLIPSIZE_END,
886 "ellipsize-set", TRUE,
889 gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
890 gtk_tree_view_append_column (GTK_TREE_VIEW (self->priv->program_list), column);
892 /* populate the widget */
893 gtk_app_chooser_widget_real_add_items (self);
897 gtk_app_chooser_widget_set_property (GObject *object,
902 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
906 case PROP_CONTENT_TYPE:
907 self->priv->content_type = g_value_dup_string (value);
909 case PROP_SHOW_DEFAULT:
910 gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value));
912 case PROP_SHOW_RECOMMENDED:
913 gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value));
915 case PROP_SHOW_FALLBACK:
916 gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value));
918 case PROP_SHOW_OTHER:
919 gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value));
922 gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value));
924 case PROP_DEFAULT_TEXT:
925 gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value));
928 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
934 gtk_app_chooser_widget_get_property (GObject *object,
939 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
943 case PROP_CONTENT_TYPE:
944 g_value_set_string (value, self->priv->content_type);
946 case PROP_SHOW_DEFAULT:
947 g_value_set_boolean (value, self->priv->show_default);
949 case PROP_SHOW_RECOMMENDED:
950 g_value_set_boolean (value, self->priv->show_recommended);
952 case PROP_SHOW_FALLBACK:
953 g_value_set_boolean (value, self->priv->show_fallback);
955 case PROP_SHOW_OTHER:
956 g_value_set_boolean (value, self->priv->show_other);
959 g_value_set_boolean (value, self->priv->show_all);
961 case PROP_DEFAULT_TEXT:
962 g_value_set_string (value, self->priv->default_text);
965 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
971 gtk_app_chooser_widget_constructed (GObject *object)
973 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
975 if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL)
976 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object);
978 gtk_app_chooser_widget_add_items (self);
982 gtk_app_chooser_widget_finalize (GObject *object)
984 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
986 g_free (self->priv->content_type);
987 g_free (self->priv->default_text);
989 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
993 gtk_app_chooser_widget_dispose (GObject *object)
995 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
997 g_clear_object (&self->priv->selected_app_info);
999 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
1003 gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
1005 GObjectClass *gobject_class;
1008 gobject_class = G_OBJECT_CLASS (klass);
1009 gobject_class->dispose = gtk_app_chooser_widget_dispose;
1010 gobject_class->finalize = gtk_app_chooser_widget_finalize;
1011 gobject_class->set_property = gtk_app_chooser_widget_set_property;
1012 gobject_class->get_property = gtk_app_chooser_widget_get_property;
1013 gobject_class->constructed = gtk_app_chooser_widget_constructed;
1015 g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
1018 * GtkAppChooserWidget:show-default:
1020 * The ::show-default property determines whether the app chooser
1021 * should show the default handler for the content type in a
1022 * separate section. If %FALSE, the default handler is listed
1023 * among the recommended applications.
1025 pspec = g_param_spec_boolean ("show-default",
1026 P_("Show default app"),
1027 P_("Whether the widget should show the default application"),
1029 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1030 g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec);
1033 * GtkAppChooserWidget:show-recommended:
1035 * The #GtkAppChooserWidget:show-recommended property determines
1036 * whether the app chooser should show a section for recommended
1037 * applications. If %FALSE, the recommended applications are listed
1038 * among the other applications.
1040 pspec = g_param_spec_boolean ("show-recommended",
1041 P_("Show recommended apps"),
1042 P_("Whether the widget should show recommended applications"),
1044 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1045 g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec);
1048 * GtkAppChooserWidget:show-fallback:
1050 * The #GtkAppChooserWidget:show-fallback property determines whether
1051 * the app chooser should show a section for fallback applications.
1052 * If %FALSE, the fallback applications are listed among the other
1055 pspec = g_param_spec_boolean ("show-fallback",
1056 P_("Show fallback apps"),
1057 P_("Whether the widget should show fallback applications"),
1059 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1060 g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec);
1063 * GtkAppChooserWidget:show-other:
1065 * The #GtkAppChooserWidget:show-other property determines whether
1066 * the app chooser should show a section for other applications.
1068 pspec = g_param_spec_boolean ("show-other",
1069 P_("Show other apps"),
1070 P_("Whether the widget should show other applications"),
1072 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1073 g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec);
1076 * GtkAppChooserWidget:show-all:
1078 * If the #GtkAppChooserWidget:show-all property is %TRUE, the app
1079 * chooser presents all applications in a single list, without
1080 * subsections for default, recommended or related applications.
1082 pspec = g_param_spec_boolean ("show-all",
1083 P_("Show all apps"),
1084 P_("Whether the widget should show all applications"),
1086 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1087 g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec);
1090 * GtkAppChooserWidget:default-text:
1092 * The #GtkAppChooserWidget:default-text property determines the text
1093 * that appears in the widget when there are no applications for the
1094 * given content type.
1095 * See also gtk_app_chooser_widget_set_default_text().
1097 pspec = g_param_spec_string ("default-text",
1098 P_("Widget's default text"),
1099 P_("The default text appearing when there are no applications"),
1101 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1102 g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec);
1105 * GtkAppChooserWidget::application-selected:
1106 * @self: the object which received the signal
1107 * @application: the selected #GAppInfo
1109 * Emitted when an application item is selected from the widget's list.
1111 signals[SIGNAL_APPLICATION_SELECTED] =
1112 g_signal_new ("application-selected",
1113 GTK_TYPE_APP_CHOOSER_WIDGET,
1115 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
1117 _gtk_marshal_VOID__OBJECT,
1119 1, G_TYPE_APP_INFO);
1122 * GtkAppChooserWidget::application-activated:
1123 * @self: the object which received the signal
1124 * @application: the activated #GAppInfo
1126 * Emitted when an application item is activated from the widget's list.
1128 * This usually happens when the user double clicks an item, or an item
1129 * is selected and the user presses one of the keys Space, Shift+Space,
1132 signals[SIGNAL_APPLICATION_ACTIVATED] =
1133 g_signal_new ("application-activated",
1134 GTK_TYPE_APP_CHOOSER_WIDGET,
1136 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
1138 _gtk_marshal_VOID__OBJECT,
1140 1, G_TYPE_APP_INFO);
1143 * GtkAppChooserWidget::populate-popup:
1144 * @self: the object which received the signal
1145 * @menu: the #GtkMenu to populate
1146 * @application: the current #GAppInfo
1148 * Emitted when a context menu is about to popup over an application item.
1149 * Clients can insert menu items into the provided #GtkMenu object in the
1150 * callback of this signal; the context menu will be shown over the item
1151 * if at least one item has been added to the menu.
1153 signals[SIGNAL_POPULATE_POPUP] =
1154 g_signal_new ("populate-popup",
1155 GTK_TYPE_APP_CHOOSER_WIDGET,
1157 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, populate_popup),
1159 _gtk_marshal_VOID__OBJECT_OBJECT,
1161 2, GTK_TYPE_MENU, G_TYPE_APP_INFO);
1163 g_type_class_add_private (klass, sizeof (GtkAppChooserWidgetPrivate));
1167 gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
1169 GtkWidget *scrolled_window;
1170 GtkTreeSelection *selection;
1172 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTK_TYPE_APP_CHOOSER_WIDGET,
1173 GtkAppChooserWidgetPrivate);
1174 gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
1176 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1177 gtk_widget_set_size_request (scrolled_window, 400, 300);
1178 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
1180 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1182 GTK_POLICY_AUTOMATIC);
1183 gtk_widget_show (scrolled_window);
1185 self->priv->program_list = gtk_tree_view_new ();
1186 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->priv->program_list),
1188 gtk_container_add (GTK_CONTAINER (scrolled_window), self->priv->program_list);
1189 gtk_box_pack_start (GTK_BOX (self), scrolled_window, TRUE, TRUE, 0);
1190 gtk_widget_show (self->priv->program_list);
1192 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
1193 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1194 gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func,
1196 g_signal_connect_swapped (selection, "changed",
1197 G_CALLBACK (refresh_and_emit_app_selected),
1199 g_signal_connect (self->priv->program_list, "row-activated",
1200 G_CALLBACK (program_list_selection_activated),
1202 g_signal_connect (self->priv->program_list, "button-press-event",
1203 G_CALLBACK (widget_button_press_event_cb),
1208 gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
1210 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1212 if (self->priv->selected_app_info == NULL)
1215 return g_object_ref (self->priv->selected_app_info);
1219 gtk_app_chooser_widget_refresh (GtkAppChooser *object)
1221 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1223 if (self->priv->program_list_store != NULL)
1225 gtk_list_store_clear (self->priv->program_list_store);
1227 /* don't add additional xpad if we don't have headings */
1228 g_object_set (self->priv->padding_renderer,
1229 "visible", !self->priv->show_all,
1232 gtk_app_chooser_widget_real_add_items (self);
1237 gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
1239 iface->get_app_info = gtk_app_chooser_widget_get_app_info;
1240 iface->refresh = gtk_app_chooser_widget_refresh;
1244 * gtk_app_chooser_widget_new:
1245 * @content_type: the content type to show applications for
1247 * Creates a new #GtkAppChooserWidget for applications
1248 * that can handle content of the given type.
1250 * Returns: a newly created #GtkAppChooserWidget
1255 gtk_app_chooser_widget_new (const gchar *content_type)
1257 return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
1258 "content-type", content_type,
1263 * gtk_app_chooser_widget_set_show_default:
1264 * @self: a #GtkAppChooserWidget
1265 * @setting: the new value for #GtkAppChooserWidget:show-default
1267 * Sets whether the app chooser should show the default handler
1268 * for the content type in a separate section.
1273 gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
1276 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1278 if (self->priv->show_default != setting)
1280 self->priv->show_default = setting;
1282 g_object_notify (G_OBJECT (self), "show-default");
1284 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1289 * gtk_app_chooser_widget_get_show_default:
1290 * @self: a #GtkAppChooserWidget
1292 * Returns the current value of the #GtkAppChooserWidget:show-default
1295 * Returns: the value of #GtkAppChooserWidget:show-default
1300 gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
1302 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1304 return self->priv->show_default;
1308 * gtk_app_chooser_widget_set_show_recommended:
1309 * @self: a #GtkAppChooserWidget
1310 * @setting: the new value for #GtkAppChooserWidget:show-recommended
1312 * Sets whether the app chooser should show recommended applications
1313 * for the content type in a separate section.
1318 gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
1321 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1323 if (self->priv->show_recommended != setting)
1325 self->priv->show_recommended = setting;
1327 g_object_notify (G_OBJECT (self), "show-recommended");
1329 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1334 * gtk_app_chooser_widget_get_show_recommended:
1335 * @self: a #GtkAppChooserWidget
1337 * Returns the current value of the #GtkAppChooserWidget:show-recommended
1340 * Returns: the value of #GtkAppChooserWidget:show-recommended
1345 gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
1347 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1349 return self->priv->show_recommended;
1353 * gtk_app_chooser_widget_set_show_fallback:
1354 * @self: a #GtkAppChooserWidget
1355 * @setting: the new value for #GtkAppChooserWidget:show-fallback
1357 * Sets whether the app chooser should show related applications
1358 * for the content type in a separate section.
1363 gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
1366 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1368 if (self->priv->show_fallback != setting)
1370 self->priv->show_fallback = setting;
1372 g_object_notify (G_OBJECT (self), "show-fallback");
1374 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1379 * gtk_app_chooser_widget_get_show_fallback:
1380 * @self: a #GtkAppChooserWidget
1382 * Returns the current value of the #GtkAppChooserWidget:show-fallback
1385 * Returns: the value of #GtkAppChooserWidget:show-fallback
1390 gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
1392 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1394 return self->priv->show_fallback;
1398 * gtk_app_chooser_widget_set_show_other:
1399 * @self: a #GtkAppChooserWidget
1400 * @setting: the new value for #GtkAppChooserWidget:show-other
1402 * Sets whether the app chooser should show applications
1403 * which are unrelated to the content type.
1408 gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
1411 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1413 if (self->priv->show_other != setting)
1415 self->priv->show_other = setting;
1417 g_object_notify (G_OBJECT (self), "show-other");
1419 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1424 * gtk_app_chooser_widget_get_show_other:
1425 * @self: a #GtkAppChooserWidget
1427 * Returns the current value of the #GtkAppChooserWidget:show-other
1430 * Returns: the value of #GtkAppChooserWidget:show-other
1435 gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
1437 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1439 return self->priv->show_other;
1443 * gtk_app_chooser_widget_set_show_all:
1444 * @self: a #GtkAppChooserWidget
1445 * @setting: the new value for #GtkAppChooserWidget:show-all
1447 * Sets whether the app chooser should show all applications
1453 gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
1456 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1458 if (self->priv->show_all != setting)
1460 self->priv->show_all = setting;
1462 g_object_notify (G_OBJECT (self), "show-all");
1464 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1469 * gtk_app_chooser_widget_get_show_all:
1470 * @self: a #GtkAppChooserWidget
1472 * Returns the current value of the #GtkAppChooserWidget:show-all
1475 * Returns: the value of #GtkAppChooserWidget:show-all
1480 gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
1482 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1484 return self->priv->show_all;
1488 * gtk_app_chooser_widget_set_default_text:
1489 * @self: a #GtkAppChooserWidget
1490 * @text: the new value for #GtkAppChooserWidget:default-text
1492 * Sets the text that is shown if there are not applications
1493 * that can handle the content type.
1496 gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
1499 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1501 if (g_strcmp0 (text, self->priv->default_text) != 0)
1503 g_free (self->priv->default_text);
1504 self->priv->default_text = g_strdup (text);
1506 g_object_notify (G_OBJECT (self), "default-text");
1508 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1513 * gtk_app_chooser_widget_get_default_text:
1514 * @self: a #GtkAppChooserWidget
1516 * Returns the text that is shown if there are not applications
1517 * that can handle the content type.
1519 * Returns: the value of #GtkAppChooserWidget:default-text
1524 gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
1526 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
1528 return self->priv->default_text;