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>
48 struct _GtkAppChooserWidgetPrivate {
49 GAppInfo *selected_app_info;
53 gboolean show_default;
54 gboolean show_recommended;
55 gboolean show_fallback;
59 GtkWidget *program_list;
60 GtkListStore *program_list_store;
62 GtkCellRenderer *padding_renderer;
81 PROP_CONTENT_TYPE = 1,
84 PROP_SHOW_RECOMMENDED,
93 SIGNAL_APPLICATION_SELECTED,
94 SIGNAL_APPLICATION_ACTIVATED,
95 SIGNAL_POPULATE_POPUP,
99 static guint signals[N_SIGNALS] = { 0, };
101 static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
103 G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_BOX,
104 G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
105 gtk_app_chooser_widget_iface_init));
108 refresh_and_emit_app_selected (GtkAppChooserWidget *self,
109 GtkTreeSelection *selection)
113 GAppInfo *info = NULL;
114 gboolean should_emit = FALSE;
116 if (gtk_tree_selection_get_selected (selection, &model, &iter))
117 gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1);
122 if (self->priv->selected_app_info)
124 if (!g_app_info_equal (self->priv->selected_app_info, info))
127 g_object_unref (self->priv->selected_app_info);
129 self->priv->selected_app_info = info;
135 self->priv->selected_app_info = info;
139 g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0,
140 self->priv->selected_app_info);
144 get_app_info_for_event (GtkAppChooserWidget *self,
145 GdkEventButton *event)
147 GtkTreePath *path = NULL;
151 gboolean recommended;
153 if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (self->priv->program_list),
159 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
161 if (!gtk_tree_model_get_iter (model, &iter, path))
163 gtk_tree_path_free (path);
167 /* we only allow interaction with recommended applications */
168 gtk_tree_model_get (model, &iter,
169 COLUMN_APP_INFO, &info,
170 COLUMN_RECOMMENDED, &recommended,
174 g_clear_object (&info);
180 widget_button_press_event_cb (GtkWidget *widget,
181 GdkEventButton *event,
184 GtkAppChooserWidget *self = user_data;
186 if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
193 info = get_app_info_for_event (self, event);
198 menu = gtk_menu_new ();
200 g_signal_emit (self, signals[SIGNAL_POPULATE_POPUP], 0,
203 g_object_unref (info);
205 /* see if clients added menu items to this container */
206 children = gtk_container_get_children (GTK_CONTAINER (menu));
207 n_children = g_list_length (children);
211 /* actually popup the menu */
212 gtk_menu_attach_to_widget (GTK_MENU (menu), self->priv->program_list, NULL);
213 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
214 event->button, event->time);
217 g_list_free (children);
224 path_is_heading (GtkTreeView *view,
231 model = gtk_tree_view_get_model (view);
232 gtk_tree_model_get_iter (model, &iter, path);
233 gtk_tree_model_get (model, &iter,
234 COLUMN_HEADING, &res,
241 program_list_selection_activated (GtkTreeView *view,
243 GtkTreeViewColumn *column,
246 GtkAppChooserWidget *self = user_data;
247 GtkTreeSelection *selection;
249 if (path_is_heading (view, path))
252 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
254 refresh_and_emit_app_selected (self, selection);
256 g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0,
257 self->priv->selected_app_info);
261 gtk_app_chooser_search_equal_func (GtkTreeModel *model,
267 gchar *normalized_key;
268 gchar *name, *normalized_name;
269 gchar *path, *normalized_path;
270 gchar *basename, *normalized_basename;
275 normalized_key = g_utf8_casefold (key, -1);
276 g_assert (normalized_key != NULL);
280 gtk_tree_model_get (model, iter,
287 normalized_name = g_utf8_casefold (name, -1);
288 g_assert (normalized_name != NULL);
290 if (strncmp (normalized_name, normalized_key, strlen (normalized_key)) == 0)
293 g_free (normalized_name);
296 if (ret && path != NULL)
298 normalized_path = g_utf8_casefold (path, -1);
299 g_assert (normalized_path != NULL);
301 basename = g_path_get_basename (path);
302 g_assert (basename != NULL);
304 normalized_basename = g_utf8_casefold (basename, -1);
305 g_assert (normalized_basename != NULL);
307 if (strncmp (normalized_path, normalized_key, strlen (normalized_key)) == 0 ||
308 strncmp (normalized_basename, normalized_key, strlen (normalized_key)) == 0)
312 g_free (normalized_basename);
313 g_free (normalized_path);
318 g_free (normalized_key);
329 gtk_app_chooser_sort_func (GtkTreeModel *model,
334 gboolean a_recommended, b_recommended;
335 gboolean a_fallback, b_fallback;
336 gboolean a_heading, b_heading;
337 gboolean a_default, b_default;
338 gchar *a_name, *b_name, *a_casefold, *b_casefold;
342 * - <0 if a should show before b
343 * - =0 if a is the same as b
344 * - >0 if a should show after b
347 gtk_tree_model_get (model, a,
348 COLUMN_NAME, &a_name,
349 COLUMN_RECOMMENDED, &a_recommended,
350 COLUMN_FALLBACK, &a_fallback,
351 COLUMN_HEADING, &a_heading,
352 COLUMN_DEFAULT, &a_default,
355 gtk_tree_model_get (model, b,
356 COLUMN_NAME, &b_name,
357 COLUMN_RECOMMENDED, &b_recommended,
358 COLUMN_FALLBACK, &b_fallback,
359 COLUMN_HEADING, &b_heading,
360 COLUMN_DEFAULT, &b_default,
363 /* the default one always wins */
364 if (a_default && !b_default)
370 if (b_default && !a_default)
376 /* the recommended one always wins */
377 if (a_recommended && !b_recommended)
383 if (b_recommended && !a_recommended)
389 /* the recommended one always wins */
390 if (a_fallback && !b_fallback)
396 if (b_fallback && !a_fallback)
402 /* they're both recommended/falback or not, so if one is a heading, wins */
415 /* don't order by name recommended applications, but use GLib's ordering */
418 a_casefold = a_name != NULL ?
419 g_utf8_casefold (a_name, -1) : NULL;
420 b_casefold = b_name != NULL ?
421 g_utf8_casefold (b_name, -1) : NULL;
423 retval = g_strcmp0 (a_casefold, b_casefold);
437 padding_cell_renderer_func (GtkTreeViewColumn *column,
438 GtkCellRenderer *cell,
445 gtk_tree_model_get (model, iter,
446 COLUMN_HEADING, &heading,
463 gtk_app_chooser_selection_func (GtkTreeSelection *selection,
466 gboolean path_currently_selected,
472 gtk_tree_model_get_iter (model, &iter, path);
473 gtk_tree_model_get (model, &iter,
474 COLUMN_HEADING, &heading,
481 compare_apps_func (gconstpointer a,
484 return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
488 gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self,
489 const gchar *heading_title,
490 gboolean show_headings,
491 gboolean recommended,
496 gboolean heading_added, unref_icon;
499 gchar *app_string, *bold_string;
505 heading_added = FALSE;
506 bold_string = g_strdup_printf ("<b>%s</b>", heading_title);
508 for (l = applications; l != NULL; l = l->next)
512 if (!g_app_info_supports_uris (app) &&
513 !g_app_info_supports_files (app))
516 if (g_list_find_custom (exclude_apps, app,
517 (GCompareFunc) compare_apps_func))
520 if (!heading_added && show_headings)
522 gtk_list_store_append (self->priv->program_list_store, &iter);
523 gtk_list_store_set (self->priv->program_list_store, &iter,
524 COLUMN_HEADING_TEXT, bold_string,
525 COLUMN_HEADING, TRUE,
526 COLUMN_RECOMMENDED, recommended,
527 COLUMN_FALLBACK, fallback,
530 heading_added = TRUE;
533 app_string = g_markup_printf_escaped ("<b>%s</b>\n%s",
534 g_app_info_get_display_name (app) != NULL ?
535 g_app_info_get_display_name (app) : "",
536 g_app_info_get_description (app) != NULL ?
537 g_app_info_get_description (app) : "");
539 icon = g_app_info_get_icon (app);
543 icon = g_themed_icon_new ("application-x-executable");
547 gtk_list_store_append (self->priv->program_list_store, &iter);
548 gtk_list_store_set (self->priv->program_list_store, &iter,
549 COLUMN_APP_INFO, app,
551 COLUMN_NAME, g_app_info_get_display_name (app),
552 COLUMN_DESC, app_string,
553 COLUMN_EXEC, g_app_info_get_executable (app),
554 COLUMN_HEADING, FALSE,
555 COLUMN_RECOMMENDED, recommended,
556 COLUMN_FALLBACK, fallback,
563 g_object_unref (icon);
566 g_free (bold_string);
573 gtk_app_chooser_add_default (GtkAppChooserWidget *self,
582 string = g_strdup_printf ("<b>%s</b>", _("Default Application"));
584 gtk_list_store_append (self->priv->program_list_store, &iter);
585 gtk_list_store_set (self->priv->program_list_store, &iter,
586 COLUMN_HEADING_TEXT, string,
587 COLUMN_HEADING, TRUE,
588 COLUMN_DEFAULT, TRUE,
593 string = g_markup_printf_escaped ("<b>%s</b>\n%s",
594 g_app_info_get_display_name (app) != NULL ?
595 g_app_info_get_display_name (app) : "",
596 g_app_info_get_description (app) != NULL ?
597 g_app_info_get_description (app) : "");
599 icon = g_app_info_get_icon (app);
602 icon = g_themed_icon_new ("application-x-executable");
606 gtk_list_store_append (self->priv->program_list_store, &iter);
607 gtk_list_store_set (self->priv->program_list_store, &iter,
608 COLUMN_APP_INFO, app,
610 COLUMN_NAME, g_app_info_get_display_name (app),
612 COLUMN_EXEC, g_app_info_get_executable (app),
613 COLUMN_HEADING, FALSE,
614 COLUMN_DEFAULT, TRUE,
620 g_object_unref (icon);
624 add_no_applications_label (GtkAppChooserWidget *self)
626 gchar *text = NULL, *desc;
630 if (self->priv->default_text == NULL)
632 desc = g_content_type_get_description (self->priv->content_type);
633 string = text = g_strdup_printf (_("No applications available to open \"%s\""),
639 string = self->priv->default_text;
642 gtk_list_store_append (self->priv->program_list_store, &iter);
643 gtk_list_store_set (self->priv->program_list_store, &iter,
644 COLUMN_HEADING_TEXT, string,
645 COLUMN_HEADING, TRUE,
652 gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
655 GAppInfo *info = NULL;
658 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
659 gtk_tree_model_get_iter_first (model, &iter);
663 gtk_tree_model_get (model, &iter,
664 COLUMN_APP_INFO, &info,
670 if (!gtk_tree_model_iter_next (model, &iter))
676 GtkTreeSelection *selection;
678 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
679 gtk_tree_selection_select_iter (selection, &iter);
681 g_object_unref (info);
686 gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
688 GList *all_applications = NULL;
689 GList *recommended_apps = NULL;
690 GList *fallback_apps = NULL;
691 GList *exclude_apps = NULL;
692 GAppInfo *default_app = NULL;
693 gboolean show_headings;
696 show_headings = TRUE;
699 if (self->priv->show_all)
700 show_headings = FALSE;
702 if (self->priv->show_default)
704 default_app = g_app_info_get_default_for_type (self->priv->content_type, FALSE);
706 if (default_app != NULL)
708 gtk_app_chooser_add_default (self, default_app);
710 exclude_apps = g_list_prepend (exclude_apps, default_app);
714 if (self->priv->show_recommended || self->priv->show_all)
716 recommended_apps = g_app_info_get_recommended_for_type (self->priv->content_type);
718 apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
720 !self->priv->show_all, /* mark as recommended */
721 FALSE, /* mark as fallback */
722 recommended_apps, exclude_apps);
724 exclude_apps = g_list_concat (exclude_apps,
725 g_list_copy (recommended_apps));
728 if (self->priv->show_fallback || self->priv->show_all)
730 fallback_apps = g_app_info_get_fallback_for_type (self->priv->content_type);
732 apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
734 FALSE, /* mark as recommended */
735 !self->priv->show_all, /* mark as fallback */
736 fallback_apps, exclude_apps);
737 exclude_apps = g_list_concat (exclude_apps,
738 g_list_copy (fallback_apps));
741 if (self->priv->show_other || self->priv->show_all)
743 all_applications = g_app_info_get_all ();
745 apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
749 all_applications, exclude_apps);
753 add_no_applications_label (self);
755 gtk_app_chooser_widget_select_first (self);
757 if (default_app != NULL)
758 g_object_unref (default_app);
760 if (all_applications != NULL)
761 g_list_free_full (all_applications, g_object_unref);
763 if (recommended_apps != NULL)
764 g_list_free_full (recommended_apps, g_object_unref);
766 if (fallback_apps != NULL)
767 g_list_free_full (fallback_apps, g_object_unref);
769 if (exclude_apps != NULL)
770 g_list_free (exclude_apps);
774 gtk_app_chooser_widget_add_items (GtkAppChooserWidget *self)
776 GtkCellRenderer *renderer;
777 GtkTreeViewColumn *column;
780 /* create list store */
781 self->priv->program_list_store = gtk_list_store_new (NUM_COLUMNS,
792 sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->priv->program_list_store));
794 gtk_tree_view_set_model (GTK_TREE_VIEW (self->priv->program_list),
795 GTK_TREE_MODEL (sort));
796 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort),
799 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
801 gtk_app_chooser_sort_func,
803 gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->priv->program_list),
805 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->priv->program_list),
806 gtk_app_chooser_search_equal_func,
809 column = gtk_tree_view_column_new ();
811 /* initial padding */
812 renderer = gtk_cell_renderer_text_new ();
813 gtk_tree_view_column_pack_start (column, renderer, FALSE);
814 g_object_set (renderer,
815 "xpad", self->priv->show_all ? 0 : 6,
817 self->priv->padding_renderer = renderer;
819 /* heading text renderer */
820 renderer = gtk_cell_renderer_text_new ();
821 gtk_tree_view_column_pack_start (column, renderer, FALSE);
822 gtk_tree_view_column_set_attributes (column, renderer,
823 "markup", COLUMN_HEADING_TEXT,
824 "visible", COLUMN_HEADING,
826 g_object_set (renderer,
830 "wrap-mode", PANGO_WRAP_WORD,
833 /* padding renderer for non-heading cells */
834 renderer = gtk_cell_renderer_text_new ();
835 gtk_tree_view_column_pack_start (column, renderer, FALSE);
836 gtk_tree_view_column_set_cell_data_func (column, renderer,
837 padding_cell_renderer_func,
840 /* app icon renderer */
841 renderer = gtk_cell_renderer_pixbuf_new ();
842 gtk_tree_view_column_pack_start (column, renderer, FALSE);
843 gtk_tree_view_column_set_attributes (column, renderer,
844 "gicon", COLUMN_GICON,
846 g_object_set (renderer,
847 "stock-size", GTK_ICON_SIZE_DIALOG,
850 /* app name renderer */
851 renderer = gtk_cell_renderer_text_new ();
852 gtk_tree_view_column_pack_start (column, renderer, TRUE);
853 gtk_tree_view_column_set_attributes (column, renderer,
854 "markup", COLUMN_DESC,
856 g_object_set (renderer,
857 "ellipsize", PANGO_ELLIPSIZE_END,
858 "ellipsize-set", TRUE,
861 gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
862 gtk_tree_view_append_column (GTK_TREE_VIEW (self->priv->program_list), column);
864 /* populate the widget */
865 gtk_app_chooser_widget_real_add_items (self);
869 gtk_app_chooser_widget_set_property (GObject *object,
874 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
878 case PROP_CONTENT_TYPE:
879 self->priv->content_type = g_value_dup_string (value);
881 case PROP_SHOW_DEFAULT:
882 gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value));
884 case PROP_SHOW_RECOMMENDED:
885 gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value));
887 case PROP_SHOW_FALLBACK:
888 gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value));
890 case PROP_SHOW_OTHER:
891 gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value));
894 gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value));
896 case PROP_DEFAULT_TEXT:
897 gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value));
900 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
906 gtk_app_chooser_widget_get_property (GObject *object,
911 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
915 case PROP_CONTENT_TYPE:
916 g_value_set_string (value, self->priv->content_type);
918 case PROP_SHOW_DEFAULT:
919 g_value_set_boolean (value, self->priv->show_default);
921 case PROP_SHOW_RECOMMENDED:
922 g_value_set_boolean (value, self->priv->show_recommended);
924 case PROP_SHOW_FALLBACK:
925 g_value_set_boolean (value, self->priv->show_fallback);
927 case PROP_SHOW_OTHER:
928 g_value_set_boolean (value, self->priv->show_other);
931 g_value_set_boolean (value, self->priv->show_all);
933 case PROP_DEFAULT_TEXT:
934 g_value_set_string (value, self->priv->default_text);
937 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
943 gtk_app_chooser_widget_constructed (GObject *object)
945 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
947 g_assert (self->priv->content_type != NULL);
949 if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL)
950 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object);
952 gtk_app_chooser_widget_add_items (self);
956 gtk_app_chooser_widget_finalize (GObject *object)
958 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
960 g_free (self->priv->content_type);
961 g_free (self->priv->default_text);
963 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
967 gtk_app_chooser_widget_dispose (GObject *object)
969 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
971 if (self->priv->selected_app_info != NULL)
973 g_object_unref (self->priv->selected_app_info);
974 self->priv->selected_app_info = NULL;
977 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
981 gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
983 GObjectClass *gobject_class;
986 gobject_class = G_OBJECT_CLASS (klass);
987 gobject_class->dispose = gtk_app_chooser_widget_dispose;
988 gobject_class->finalize = gtk_app_chooser_widget_finalize;
989 gobject_class->set_property = gtk_app_chooser_widget_set_property;
990 gobject_class->get_property = gtk_app_chooser_widget_get_property;
991 gobject_class->constructed = gtk_app_chooser_widget_constructed;
993 g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
996 * GtkAppChooserWidget:show-default:
998 * The ::show-default property determines whether the app chooser
999 * should show the default handler for the content type in a
1000 * separate section. If %FALSE, the default handler is listed
1001 * among the recommended applications.
1003 pspec = g_param_spec_boolean ("show-default",
1004 P_("Show default app"),
1005 P_("Whether the widget should show the default application"),
1007 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1008 g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec);
1011 * GtkAppChooserWidget:show-recommended:
1013 * The ::show-recommended property determines whether the app chooser
1014 * should show a section for recommended applications. If %FALSE, the
1015 * recommended applications are listed among the other applications.
1017 pspec = g_param_spec_boolean ("show-recommended",
1018 P_("Show recommended apps"),
1019 P_("Whether the widget should show recommended applications"),
1021 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1022 g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec);
1025 * GtkAppChooserWidget:show-fallback:
1027 * The ::show-fallback property determines whether the app chooser
1028 * should show a section for related applications. If %FALSE, the
1029 * related applications are listed among the other applications.
1031 pspec = g_param_spec_boolean ("show-fallback",
1032 P_("Show fallback apps"),
1033 P_("Whether the widget should show fallback applications"),
1035 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1036 g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec);
1039 * GtkAppChooserWidget:show-other:
1041 * The ::show-other property determines whether the app chooser
1042 * should show a section for other applications.
1044 pspec = g_param_spec_boolean ("show-other",
1045 P_("Show other apps"),
1046 P_("Whether the widget should show other applications"),
1048 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1049 g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec);
1052 * GtkAppChooserWidget:show-all:
1054 * If the ::show-all property is %TRUE, the app chooser presents
1055 * all applications in a single list, without subsections for
1056 * default, recommended or related applications.
1058 pspec = g_param_spec_boolean ("show-all",
1059 P_("Show all apps"),
1060 P_("Whether the widget should show all applications"),
1062 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1063 g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec);
1065 pspec = g_param_spec_string ("default-text",
1066 P_("Widget's default text"),
1067 P_("The default text appearing when there are no applications"),
1069 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1070 g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec);
1072 signals[SIGNAL_APPLICATION_SELECTED] =
1073 g_signal_new ("application-selected",
1074 GTK_TYPE_APP_CHOOSER_WIDGET,
1076 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
1078 _gtk_marshal_VOID__OBJECT,
1080 1, G_TYPE_APP_INFO);
1082 signals[SIGNAL_APPLICATION_ACTIVATED] =
1083 g_signal_new ("application-activated",
1084 GTK_TYPE_APP_CHOOSER_WIDGET,
1086 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
1088 _gtk_marshal_VOID__OBJECT,
1090 1, G_TYPE_APP_INFO);
1092 signals[SIGNAL_POPULATE_POPUP] =
1093 g_signal_new ("populate-popup",
1094 GTK_TYPE_APP_CHOOSER_WIDGET,
1096 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, populate_popup),
1098 _gtk_marshal_VOID__OBJECT_OBJECT,
1100 2, GTK_TYPE_MENU, G_TYPE_APP_INFO);
1102 g_type_class_add_private (klass, sizeof (GtkAppChooserWidgetPrivate));
1106 gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
1108 GtkWidget *scrolled_window;
1109 GtkTreeSelection *selection;
1111 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTK_TYPE_APP_CHOOSER_WIDGET,
1112 GtkAppChooserWidgetPrivate);
1113 gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
1115 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1116 gtk_widget_set_size_request (scrolled_window, 400, 300);
1117 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
1119 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1121 GTK_POLICY_AUTOMATIC);
1122 gtk_widget_show (scrolled_window);
1124 self->priv->program_list = gtk_tree_view_new ();
1125 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->priv->program_list),
1127 gtk_container_add (GTK_CONTAINER (scrolled_window), self->priv->program_list);
1128 gtk_box_pack_start (GTK_BOX (self), scrolled_window, TRUE, TRUE, 0);
1129 gtk_widget_show (self->priv->program_list);
1131 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
1132 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1133 gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func,
1135 g_signal_connect_swapped (selection, "changed",
1136 G_CALLBACK (refresh_and_emit_app_selected),
1138 g_signal_connect (self->priv->program_list, "row-activated",
1139 G_CALLBACK (program_list_selection_activated),
1141 g_signal_connect (self->priv->program_list, "button-press-event",
1142 G_CALLBACK (widget_button_press_event_cb),
1147 gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
1149 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1151 if (self->priv->selected_app_info == NULL)
1154 return g_object_ref (self->priv->selected_app_info);
1158 gtk_app_chooser_widget_refresh (GtkAppChooser *object)
1160 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1162 if (self->priv->program_list_store != NULL)
1164 gtk_list_store_clear (self->priv->program_list_store);
1166 /* don't add additional xpad if we don't have headings */
1167 g_object_set (self->priv->padding_renderer,
1168 "visible", !self->priv->show_all,
1171 gtk_app_chooser_widget_real_add_items (self);
1176 gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
1178 iface->get_app_info = gtk_app_chooser_widget_get_app_info;
1179 iface->refresh = gtk_app_chooser_widget_refresh;
1183 * gtk_app_chooser_widget_new:
1184 * @content_type: the content type to show applications for
1186 * Creates a new #GtkAppChooserWidget for applications
1187 * that can handle content of the given type.
1189 * Returns: a newly created #GtkAppChooserWidget
1194 gtk_app_chooser_widget_new (const gchar *content_type)
1196 return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
1197 "content-type", content_type,
1202 * gtk_app_chooser_widget_set_show_default:
1203 * @self: a #GtkAppChooserWidget
1204 * @setting: the new value for #GtkAppChooserWidget:show-default
1206 * Sets whether the app chooser should show the default handler
1207 * for the content type in a separate section.
1212 gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
1215 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1217 if (self->priv->show_default != setting)
1219 self->priv->show_default = setting;
1221 g_object_notify (G_OBJECT (self), "show-default");
1223 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1228 * gtk_app_chooser_widget_get_show_default:
1229 * @self: a #GtkAppChooserWidget
1231 * Returns the current value of the #GtkAppChooserWidget:show-default
1234 * Returns: the value of #GtkAppChooserWidget:show-default
1239 gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
1241 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1243 return self->priv->show_default;
1247 * gtk_app_chooser_widget_set_show_recommended:
1248 * @self: a #GtkAppChooserWidget
1249 * @setting: the new value for #GtkAppChooserWidget:show-recommended
1251 * Sets whether the app chooser should show recommended applications
1252 * for the content type in a separate section.
1257 gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
1260 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1262 if (self->priv->show_recommended != setting)
1264 self->priv->show_recommended = setting;
1266 g_object_notify (G_OBJECT (self), "show-recommended");
1268 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1273 * gtk_app_chooser_widget_get_show_recommended:
1274 * @self: a #GtkAppChooserWidget
1276 * Returns the current value of the #GtkAppChooserWidget:show-recommended
1279 * Returns: the value of #GtkAppChooserWidget:show-recommended
1284 gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
1286 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1288 return self->priv->show_recommended;
1292 * gtk_app_chooser_widget_set_show_fallback:
1293 * @self: a #GtkAppChooserWidget
1294 * @setting: the new value for #GtkAppChooserWidget:show-fallback
1296 * Sets whether the app chooser should show related applications
1297 * for the content type in a separate section.
1302 gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
1305 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1307 if (self->priv->show_fallback != setting)
1309 self->priv->show_fallback = setting;
1311 g_object_notify (G_OBJECT (self), "show-fallback");
1313 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1318 * gtk_app_chooser_widget_get_show_fallback:
1319 * @self: a #GtkAppChooserWidget
1321 * Returns the current value of the #GtkAppChooserWidget:show-fallback
1324 * Returns: the value of #GtkAppChooserWidget:show-fallback
1329 gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
1331 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1333 return self->priv->show_fallback;
1337 * gtk_app_chooser_widget_set_show_other:
1338 * @self: a #GtkAppChooserWidget
1339 * @setting: the new value for #GtkAppChooserWidget:show-other
1341 * Sets whether the app chooser should show applications
1342 * which are unrelated to the content type.
1347 gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
1350 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1352 if (self->priv->show_other != setting)
1354 self->priv->show_other = setting;
1356 g_object_notify (G_OBJECT (self), "show-other");
1358 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1363 * gtk_app_chooser_widget_get_show_other:
1364 * @self: a #GtkAppChooserWidget
1366 * Returns the current value of the #GtkAppChooserWidget:show-other
1369 * Returns: the value of #GtkAppChooserWidget:show-other
1374 gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
1376 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1378 return self->priv->show_other;
1382 * gtk_app_chooser_widget_set_show_all:
1383 * @self: a #GtkAppChooserWidget
1384 * @setting: the new value for #GtkAppChooserWidget:show-all
1386 * Sets whether the app chooser should show all applications
1392 gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
1395 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1397 if (self->priv->show_all != setting)
1399 self->priv->show_all = setting;
1401 g_object_notify (G_OBJECT (self), "show-all");
1403 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1408 * gtk_app_chooser_widget_get_show_all:
1409 * @self: a #GtkAppChooserWidget
1411 * Returns the current value of the #GtkAppChooserWidget:show-all
1414 * Returns: the value of #GtkAppChooserWidget:show-all
1419 gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
1421 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1423 return self->priv->show_all;
1427 * gtk_app_chooser_widget_set_default_text:
1428 * @self: a #GtkAppChooserWidget
1429 * @text: the new value for #GtkAppChooserWidget:default-text
1431 * Sets the text that is shown if there are not applications
1432 * that can handle the content type.
1435 gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
1438 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1440 if (g_strcmp0 (text, self->priv->default_text) != 0)
1442 g_free (self->priv->default_text);
1443 self->priv->default_text = g_strdup (text);
1445 g_object_notify (G_OBJECT (self), "default-text");
1447 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1452 * gtk_app_chooser_widget_get_default_text:
1453 * @self: a #GtkAppChooserWidget
1455 * Returns the text that is shown if there are not applications
1456 * that can handle the content type.
1458 * Returns: the value of #GtkAppChooserWidget:default-text
1463 gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
1465 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
1467 return self->priv->default_text;