]> Pileus Git - ~andy/gtk/blob - gtk/gtkappchooserwidget.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkappchooserwidget.c
1 /*
2  * gtkappchooserwidget.c: an app-chooser widget
3  *
4  * Copyright (C) 2004 Novell, Inc.
5  * Copyright (C) 2007, 2010 Red Hat, Inc.
6  *
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.
11  *
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.
16  *
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/>.
19  *
20  * Authors: Dave Camp <dave@novell.com>
21  *          Alexander Larsson <alexl@redhat.com>
22  *          Cosimo Cecchi <ccecchi@redhat.com>
23  */
24
25 #include "config.h"
26
27 #include "gtkappchooserwidget.h"
28
29 #include "gtkintl.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"
41
42 #include <string.h>
43 #include <glib/gi18n-lib.h>
44 #include <gio/gio.h>
45
46 /**
47  * SECTION:gtkappchooserwidget
48  * @Title: GtkAppChooserWidget
49  * @Short_description: Application chooser widget that can be embedded in other widgets
50  *
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.
55  *
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.
65  *
66  * To keep track of the selected application, use the
67  * #GtkAppChooserWidget::application-selected and #GtkAppChooserWidget::application-activated signals.
68  */
69
70 struct _GtkAppChooserWidgetPrivate {
71   GAppInfo *selected_app_info;
72
73   gchar *content_type;
74   gchar *default_text;
75
76   guint show_default     : 1;
77   guint show_recommended : 1;
78   guint show_fallback    : 1;
79   guint show_other       : 1;
80   guint show_all         : 1;
81
82   GtkWidget *program_list;
83   GtkListStore *program_list_store;
84
85   GtkCellRenderer *padding_renderer;
86 };
87
88 enum {
89   COLUMN_APP_INFO,
90   COLUMN_GICON,
91   COLUMN_NAME,
92   COLUMN_DESC,
93   COLUMN_EXEC,
94   COLUMN_DEFAULT,
95   COLUMN_HEADING,
96   COLUMN_HEADING_TEXT,
97   COLUMN_RECOMMENDED,
98   COLUMN_FALLBACK,
99   NUM_COLUMNS
100 };
101
102
103 enum {
104   PROP_CONTENT_TYPE = 1,
105   PROP_GFILE,
106   PROP_SHOW_DEFAULT,
107   PROP_SHOW_RECOMMENDED,
108   PROP_SHOW_FALLBACK,
109   PROP_SHOW_OTHER,
110   PROP_SHOW_ALL,
111   PROP_DEFAULT_TEXT,
112   N_PROPERTIES
113 };
114
115 enum {
116   SIGNAL_APPLICATION_SELECTED,
117   SIGNAL_APPLICATION_ACTIVATED,
118   SIGNAL_POPULATE_POPUP,
119   N_SIGNALS
120 };
121
122 static guint signals[N_SIGNALS] = { 0, };
123
124 static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
125
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));
129
130 static void
131 refresh_and_emit_app_selected (GtkAppChooserWidget *self,
132                                GtkTreeSelection    *selection)
133 {
134   GtkTreeModel *model;
135   GtkTreeIter iter;
136   GAppInfo *info = NULL;
137   gboolean should_emit = FALSE;
138
139   if (gtk_tree_selection_get_selected (selection, &model, &iter))
140     gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1);
141
142   if (info == NULL)
143     return;
144
145   if (self->priv->selected_app_info)
146     {
147       if (!g_app_info_equal (self->priv->selected_app_info, info))
148         {
149           should_emit = TRUE;
150           g_object_unref (self->priv->selected_app_info);
151
152           self->priv->selected_app_info = info;
153         }
154     }
155   else
156     {
157       should_emit = TRUE;
158       self->priv->selected_app_info = info;
159     }
160
161   if (should_emit)
162     g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0,
163                    self->priv->selected_app_info);
164 }
165
166 static GAppInfo *
167 get_app_info_for_event (GtkAppChooserWidget *self,
168                         GdkEventButton      *event)
169 {
170   GtkTreePath *path = NULL;
171   GtkTreeIter iter;
172   GtkTreeModel *model;
173   GAppInfo *info;
174   gboolean recommended;
175
176   if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (self->priv->program_list),
177                                       event->x, event->y,
178                                       &path,
179                                       NULL, NULL, NULL))
180     return NULL;
181
182   model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
183
184   if (!gtk_tree_model_get_iter (model, &iter, path))
185     {
186       gtk_tree_path_free (path);
187       return NULL;
188     }
189
190   /* we only allow interaction with recommended applications */
191   gtk_tree_model_get (model, &iter,
192                       COLUMN_APP_INFO, &info,
193                       COLUMN_RECOMMENDED, &recommended,
194                       -1);
195
196   if (!recommended)
197     g_clear_object (&info);
198
199   return info;
200 }
201
202 static gboolean
203 widget_button_press_event_cb (GtkWidget      *widget,
204                               GdkEventButton *event,
205                               gpointer        user_data)
206 {
207   GtkAppChooserWidget *self = user_data;
208
209   if (event->button == GDK_BUTTON_SECONDARY && event->type == GDK_BUTTON_PRESS)
210     {
211       GAppInfo *info;
212       GtkWidget *menu;
213       GList *children;
214       gint n_children;
215
216       info = get_app_info_for_event (self, event);
217
218       if (info == NULL)
219         return FALSE;
220
221       menu = gtk_menu_new ();
222
223       g_signal_emit (self, signals[SIGNAL_POPULATE_POPUP], 0,
224                      menu, info);
225
226       g_object_unref (info);
227
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);
231
232       if (n_children > 0)
233         {
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);
238         }
239
240       g_list_free (children);
241     }
242
243   return FALSE;
244 }
245
246 static gboolean
247 path_is_heading (GtkTreeView *view,
248                  GtkTreePath *path)
249 {
250   GtkTreeIter iter;
251   GtkTreeModel *model;
252   gboolean res;
253
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,
258                       -1);
259
260   return res;
261 }
262
263 static void
264 program_list_selection_activated (GtkTreeView       *view,
265                                   GtkTreePath       *path,
266                                   GtkTreeViewColumn *column,
267                                   gpointer           user_data)
268 {
269   GtkAppChooserWidget *self = user_data;
270   GtkTreeSelection *selection;
271
272   if (path_is_heading (view, path))
273     return;
274
275   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
276
277   refresh_and_emit_app_selected (self, selection);
278
279   g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0,
280                  self->priv->selected_app_info);
281 }
282
283 static gboolean
284 gtk_app_chooser_search_equal_func (GtkTreeModel *model,
285                                    gint          column,
286                                    const gchar  *key,
287                                    GtkTreeIter  *iter,
288                                    gpointer      user_data)
289 {
290   gchar *normalized_key;
291   gchar *name, *normalized_name;
292   gchar *path, *normalized_path;
293   gchar *basename, *normalized_basename;
294   gboolean ret;
295
296   if (key != NULL)
297     {
298       normalized_key = g_utf8_casefold (key, -1);
299       g_assert (normalized_key != NULL);
300
301       ret = TRUE;
302
303       gtk_tree_model_get (model, iter,
304                           COLUMN_NAME, &name,
305                           COLUMN_EXEC, &path,
306                           -1);
307
308       if (name != NULL)
309         {
310           normalized_name = g_utf8_casefold (name, -1);
311           g_assert (normalized_name != NULL);
312
313           if (strncmp (normalized_name, normalized_key, strlen (normalized_key)) == 0)
314             ret = FALSE;
315
316           g_free (normalized_name);
317         }
318
319       if (ret && path != NULL)
320         {
321           normalized_path = g_utf8_casefold (path, -1);
322           g_assert (normalized_path != NULL);
323
324           basename = g_path_get_basename (path);
325           g_assert (basename != NULL);
326
327           normalized_basename = g_utf8_casefold (basename, -1);
328           g_assert (normalized_basename != NULL);
329
330           if (strncmp (normalized_path, normalized_key, strlen (normalized_key)) == 0 ||
331               strncmp (normalized_basename, normalized_key, strlen (normalized_key)) == 0)
332             ret = FALSE;
333
334           g_free (basename);
335           g_free (normalized_basename);
336           g_free (normalized_path);
337         }
338
339       g_free (name);
340       g_free (path);
341       g_free (normalized_key);
342
343       return ret;
344     }
345   else
346     {
347       return TRUE;
348     }
349 }
350
351 static gint
352 gtk_app_chooser_sort_func (GtkTreeModel *model,
353                            GtkTreeIter  *a,
354                            GtkTreeIter  *b,
355                            gpointer      user_data)
356 {
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;
362   gint retval = 0;
363
364   /* this returns:
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
368    */
369
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,
376                       -1);
377
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,
384                       -1);
385
386   /* the default one always wins */
387   if (a_default && !b_default)
388     {
389       retval = -1;
390       goto out;
391     }
392
393   if (b_default && !a_default)
394     {
395       retval = 1;
396       goto out;
397     }
398   
399   /* the recommended one always wins */
400   if (a_recommended && !b_recommended)
401     {
402       retval = -1;
403       goto out;
404     }
405
406   if (b_recommended && !a_recommended)
407     {
408       retval = 1;
409       goto out;
410     }
411
412   /* the recommended one always wins */
413   if (a_fallback && !b_fallback)
414     {
415       retval = -1;
416       goto out;
417     }
418
419   if (b_fallback && !a_fallback)
420     {
421       retval = 1;
422       goto out;
423     }
424
425   /* they're both recommended/falback or not, so if one is a heading, wins */
426   if (a_heading)
427     {
428       retval = -1;
429       goto out;
430     }
431
432   if (b_heading)
433     {
434       retval = 1;
435       goto out;
436     }
437
438   /* don't order by name recommended applications, but use GLib's ordering */
439   if (!a_recommended)
440     {
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;
445
446       retval = g_strcmp0 (a_casefold, b_casefold);
447
448       g_free (a_casefold);
449       g_free (b_casefold);
450     }
451
452  out:
453   g_free (a_name);
454   g_free (b_name);
455
456   return retval;
457 }
458
459 static void
460 padding_cell_renderer_func (GtkTreeViewColumn *column,
461                             GtkCellRenderer   *cell,
462                             GtkTreeModel      *model,
463                             GtkTreeIter       *iter,
464                             gpointer           user_data)
465 {
466   gboolean heading;
467
468   gtk_tree_model_get (model, iter,
469                       COLUMN_HEADING, &heading,
470                       -1);
471   if (heading)
472     g_object_set (cell,
473                   "visible", FALSE,
474                   "xpad", 0,
475                   "ypad", 0,
476                   NULL);
477   else
478     g_object_set (cell,
479                   "visible", TRUE,
480                   "xpad", 3,
481                   "ypad", 3,
482                   NULL);
483 }
484
485 static gboolean
486 gtk_app_chooser_selection_func (GtkTreeSelection *selection,
487                                 GtkTreeModel     *model,
488                                 GtkTreePath      *path,
489                                 gboolean          path_currently_selected,
490                                 gpointer          user_data)
491 {
492   GtkTreeIter iter;
493   gboolean heading;
494
495   gtk_tree_model_get_iter (model, &iter, path);
496   gtk_tree_model_get (model, &iter,
497                       COLUMN_HEADING, &heading,
498                       -1);
499
500   return !heading;
501 }
502
503 static gint
504 compare_apps_func (gconstpointer a,
505                    gconstpointer b)
506 {
507   return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
508 }
509
510 static gboolean
511 gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self,
512                                     const gchar         *heading_title,
513                                     gboolean             show_headings,
514                                     gboolean             recommended,
515                                     gboolean             fallback,
516                                     GList               *applications,
517                                     GList               *exclude_apps)
518 {
519   gboolean heading_added, unref_icon;
520   GtkTreeIter iter;
521   GAppInfo *app;
522   gchar *app_string, *bold_string;
523   GIcon *icon;
524   GList *l;
525   gboolean retval;
526
527   retval = FALSE;
528   heading_added = FALSE;
529   bold_string = g_strdup_printf ("<b>%s</b>", heading_title);
530   
531   for (l = applications; l != NULL; l = l->next)
532     {
533       app = l->data;
534
535       if (!g_app_info_supports_uris (app) &&
536           !g_app_info_supports_files (app))
537         continue;
538
539       if (!g_app_info_should_show (app))
540         continue;
541
542       if (g_list_find_custom (exclude_apps, app,
543                               (GCompareFunc) compare_apps_func))
544         continue;
545
546       if (!heading_added && show_headings)
547         {
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,
554                               -1);
555
556           heading_added = TRUE;
557         }
558
559       app_string = g_markup_printf_escaped ("%s",
560                                             g_app_info_get_name (app) != NULL ?
561                                             g_app_info_get_name (app) : "");
562
563       icon = g_app_info_get_icon (app);
564       unref_icon = FALSE;
565       if (icon == NULL)
566         {
567           icon = g_themed_icon_new ("application-x-executable");
568           unref_icon = TRUE;
569         }
570
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,
574                           COLUMN_GICON, icon,
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,
581                           -1);
582
583       retval = TRUE;
584
585       g_free (app_string);
586       if (unref_icon)
587         g_object_unref (icon);
588     }
589
590   g_free (bold_string);
591
592   return retval;
593 }
594
595
596 static void
597 gtk_app_chooser_add_default (GtkAppChooserWidget *self,
598                              GAppInfo            *app)
599 {
600   GtkTreeIter iter;
601   GIcon *icon;
602   gchar *string;
603   gboolean unref_icon;
604
605   unref_icon = FALSE;
606   string = g_strdup_printf ("<b>%s</b>", _("Default Application"));
607
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,
613                       -1);
614
615   g_free (string);
616
617   string = g_markup_printf_escaped ("%s",
618                                     g_app_info_get_name (app) != NULL ?
619                                     g_app_info_get_name (app) : "");
620
621   icon = g_app_info_get_icon (app);
622   if (icon == NULL)
623     {
624       icon = g_themed_icon_new ("application-x-executable");
625       unref_icon = TRUE;
626     }
627
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,
631                       COLUMN_GICON, icon,
632                       COLUMN_NAME, g_app_info_get_name (app),
633                       COLUMN_DESC, string,
634                       COLUMN_EXEC, g_app_info_get_executable (app),
635                       COLUMN_HEADING, FALSE,
636                       COLUMN_DEFAULT, TRUE,
637                       -1);
638
639   g_free (string);
640
641   if (unref_icon)
642     g_object_unref (icon);
643 }
644
645 static void
646 add_no_applications_label (GtkAppChooserWidget *self)
647 {
648   gchar *text = NULL, *desc = NULL;
649   const gchar *string;
650   GtkTreeIter iter;
651
652   if (self->priv->default_text == NULL)
653     {
654       if (self->priv->content_type)
655         desc = g_content_type_get_description (self->priv->content_type);
656
657       string = text = g_strdup_printf (_("No applications available to open \"%s\""),
658                                        desc);
659       g_free (desc);
660     }
661   else
662     {
663       string = self->priv->default_text;
664     }
665
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,
670                       -1);
671
672   g_free (text);
673 }
674
675 static void
676 gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
677 {
678   GtkTreeIter iter;
679   GAppInfo *info = NULL;
680   GtkTreeModel *model;
681
682   model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
683   gtk_tree_model_get_iter_first (model, &iter);
684
685   while (info == NULL)
686     {
687       gtk_tree_model_get (model, &iter,
688                           COLUMN_APP_INFO, &info,
689                           -1);
690
691       if (info != NULL)
692         break;
693
694       if (!gtk_tree_model_iter_next (model, &iter))
695         break;
696     }
697
698   if (info != NULL)
699     {
700       GtkTreeSelection *selection;
701
702       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
703       gtk_tree_selection_select_iter (selection, &iter);
704
705       g_object_unref (info);
706     }
707 }
708
709 static void
710 gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
711 {
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;
718   gboolean apps_added;
719
720   show_headings = TRUE;
721   apps_added = FALSE;
722
723   if (self->priv->show_all)
724     show_headings = FALSE;
725
726   if (self->priv->show_default && self->priv->content_type)
727     {
728       default_app = g_app_info_get_default_for_type (self->priv->content_type, FALSE);
729
730       if (default_app != NULL)
731         {
732           gtk_app_chooser_add_default (self, default_app);
733           apps_added = TRUE;
734           exclude_apps = g_list_prepend (exclude_apps, default_app);
735         }
736     }
737
738 #ifndef G_OS_WIN32
739   if ((self->priv->content_type && self->priv->show_recommended) || self->priv->show_all)
740     {
741       if (self->priv->content_type)
742         recommended_apps = g_app_info_get_recommended_for_type (self->priv->content_type);
743
744       apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
745                                                         show_headings,
746                                                         !self->priv->show_all, /* mark as recommended */
747                                                         FALSE, /* mark as fallback */
748                                                         recommended_apps, exclude_apps);
749
750       exclude_apps = g_list_concat (exclude_apps,
751                                     g_list_copy (recommended_apps));
752     }
753
754   if ((self->priv->content_type && self->priv->show_fallback) || self->priv->show_all)
755     {
756       if (self->priv->content_type)
757         fallback_apps = g_app_info_get_fallback_for_type (self->priv->content_type);
758
759       apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
760                                                         show_headings,
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));
766     }
767 #endif
768
769   if (self->priv->show_other || self->priv->show_all)
770     {
771       all_applications = g_app_info_get_all ();
772
773       apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
774                                                         show_headings,
775                                                         FALSE,
776                                                         FALSE,
777                                                         all_applications, exclude_apps);
778     }
779
780   if (!apps_added)
781     add_no_applications_label (self);
782
783   gtk_app_chooser_widget_select_first (self);
784
785   if (default_app != NULL)
786     g_object_unref (default_app);
787
788   if (all_applications != NULL)
789     g_list_free_full (all_applications, g_object_unref);
790
791   if (recommended_apps != NULL)
792     g_list_free_full (recommended_apps, g_object_unref);
793
794   if (fallback_apps != NULL)
795     g_list_free_full (fallback_apps, g_object_unref);
796
797   if (exclude_apps != NULL)
798     g_list_free (exclude_apps);
799 }
800
801 static void
802 gtk_app_chooser_widget_add_items (GtkAppChooserWidget *self)
803 {
804   GtkCellRenderer *renderer;
805   GtkTreeViewColumn *column;
806   GtkTreeModel *sort;
807
808   /* create list store */
809   self->priv->program_list_store = gtk_list_store_new (NUM_COLUMNS,
810                                                        G_TYPE_APP_INFO,
811                                                        G_TYPE_ICON,
812                                                        G_TYPE_STRING,
813                                                        G_TYPE_STRING,
814                                                        G_TYPE_STRING,
815                                                        G_TYPE_BOOLEAN,
816                                                        G_TYPE_BOOLEAN,
817                                                        G_TYPE_STRING,
818                                                        G_TYPE_BOOLEAN,
819                                                        G_TYPE_BOOLEAN);
820   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->priv->program_list_store));
821
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),
825                                         COLUMN_NAME,
826                                         GTK_SORT_ASCENDING);
827   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
828                                    COLUMN_NAME,
829                                    gtk_app_chooser_sort_func,
830                                    self, NULL);
831   gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->priv->program_list),
832                                    COLUMN_NAME);
833   gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->priv->program_list),
834                                        gtk_app_chooser_search_equal_func,
835                                        NULL, NULL);
836
837   column = gtk_tree_view_column_new ();
838
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,
844                 NULL);
845   self->priv->padding_renderer = renderer;
846
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,
853                                        NULL);
854   g_object_set (renderer,
855                 "ypad", 6,
856                 "xpad", 0,
857                 "wrap-width", 350,
858                 "wrap-mode", PANGO_WRAP_WORD,
859                 NULL);
860
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,
866                                            NULL, NULL);
867
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,
873                                        NULL);
874   g_object_set (renderer,
875                 "stock-size", GTK_ICON_SIZE_MENU,
876                 NULL);
877
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,
883                                        NULL);
884   g_object_set (renderer,
885                 "ellipsize", PANGO_ELLIPSIZE_END,
886                 "ellipsize-set", TRUE,
887                 NULL);
888   
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);
891
892   /* populate the widget */
893   gtk_app_chooser_widget_real_add_items (self);
894 }
895
896 static void
897 gtk_app_chooser_widget_set_property (GObject      *object,
898                                      guint         property_id,
899                                      const GValue *value,
900                                      GParamSpec   *pspec)
901 {
902   GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
903
904   switch (property_id)
905     {
906     case PROP_CONTENT_TYPE:
907       self->priv->content_type = g_value_dup_string (value);
908       break;
909     case PROP_SHOW_DEFAULT:
910       gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value));
911       break;
912     case PROP_SHOW_RECOMMENDED:
913       gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value));
914       break;
915     case PROP_SHOW_FALLBACK:
916       gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value));
917       break;
918     case PROP_SHOW_OTHER:
919       gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value));
920       break;
921     case PROP_SHOW_ALL:
922       gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value));
923       break;
924     case PROP_DEFAULT_TEXT:
925       gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value));
926       break;
927     default:
928       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
929       break;
930     }
931 }
932
933 static void
934 gtk_app_chooser_widget_get_property (GObject    *object,
935                                      guint       property_id,
936                                      GValue     *value,
937                                      GParamSpec *pspec)
938 {
939   GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
940
941   switch (property_id)
942     {
943     case PROP_CONTENT_TYPE:
944       g_value_set_string (value, self->priv->content_type);
945       break;
946     case PROP_SHOW_DEFAULT:
947       g_value_set_boolean (value, self->priv->show_default);
948       break;
949     case PROP_SHOW_RECOMMENDED:
950       g_value_set_boolean (value, self->priv->show_recommended);
951       break;
952     case PROP_SHOW_FALLBACK:
953       g_value_set_boolean (value, self->priv->show_fallback);
954       break;
955     case PROP_SHOW_OTHER:
956       g_value_set_boolean (value, self->priv->show_other);
957       break;
958     case PROP_SHOW_ALL:
959       g_value_set_boolean (value, self->priv->show_all);
960       break;
961     case PROP_DEFAULT_TEXT:
962       g_value_set_string (value, self->priv->default_text);
963       break;
964     default:
965       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
966       break;
967     }
968 }
969
970 static void
971 gtk_app_chooser_widget_constructed (GObject *object)
972 {
973   GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
974
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);
977
978   gtk_app_chooser_widget_add_items (self);
979 }
980
981 static void
982 gtk_app_chooser_widget_finalize (GObject *object)
983 {
984   GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
985
986   g_free (self->priv->content_type);
987   g_free (self->priv->default_text);
988
989   G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
990 }
991
992 static void
993 gtk_app_chooser_widget_dispose (GObject *object)
994 {
995   GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
996
997   g_clear_object (&self->priv->selected_app_info);
998
999   G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
1000 }
1001
1002 static void
1003 gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
1004 {
1005   GObjectClass *gobject_class;
1006   GParamSpec *pspec;
1007
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;
1014
1015   g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
1016
1017   /**
1018    * GtkAppChooserWidget:show-default:
1019    *
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.
1024    */
1025   pspec = g_param_spec_boolean ("show-default",
1026                                 P_("Show default app"),
1027                                 P_("Whether the widget should show the default application"),
1028                                 FALSE,
1029                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1030   g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec);
1031
1032   /**
1033    * GtkAppChooserWidget:show-recommended:
1034    *
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.
1039    */
1040   pspec = g_param_spec_boolean ("show-recommended",
1041                                 P_("Show recommended apps"),
1042                                 P_("Whether the widget should show recommended applications"),
1043                                 TRUE,
1044                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1045   g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec);
1046
1047   /**
1048    * GtkAppChooserWidget:show-fallback:
1049    *
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
1053    * applications.
1054    */
1055   pspec = g_param_spec_boolean ("show-fallback",
1056                                 P_("Show fallback apps"),
1057                                 P_("Whether the widget should show fallback applications"),
1058                                 FALSE,
1059                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1060   g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec);
1061
1062   /**
1063    * GtkAppChooserWidget:show-other:
1064    *
1065    * The #GtkAppChooserWidget:show-other property determines whether
1066    * the app chooser should show a section for other applications.
1067    */
1068   pspec = g_param_spec_boolean ("show-other",
1069                                 P_("Show other apps"),
1070                                 P_("Whether the widget should show other applications"),
1071                                 FALSE,
1072                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1073   g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec);
1074
1075   /**
1076    * GtkAppChooserWidget:show-all:
1077    *
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.
1081    */
1082   pspec = g_param_spec_boolean ("show-all",
1083                                 P_("Show all apps"),
1084                                 P_("Whether the widget should show all applications"),
1085                                 FALSE,
1086                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
1087   g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec);
1088
1089   /**
1090    * GtkAppChooserWidget:default-text:
1091    *
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().
1096    */
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"),
1100                                NULL,
1101                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1102   g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec);
1103
1104   /**
1105    * GtkAppChooserWidget::application-selected:
1106    * @self: the object which received the signal
1107    * @application: the selected #GAppInfo
1108    *
1109    * Emitted when an application item is selected from the widget's list.
1110    */
1111   signals[SIGNAL_APPLICATION_SELECTED] =
1112     g_signal_new ("application-selected",
1113                   GTK_TYPE_APP_CHOOSER_WIDGET,
1114                   G_SIGNAL_RUN_FIRST,
1115                   G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
1116                   NULL, NULL,
1117                   _gtk_marshal_VOID__OBJECT,
1118                   G_TYPE_NONE,
1119                   1, G_TYPE_APP_INFO);
1120
1121   /**
1122    * GtkAppChooserWidget::application-activated:
1123    * @self: the object which received the signal
1124    * @application: the activated #GAppInfo
1125    *
1126    * Emitted when an application item is activated from the widget's list.
1127    *
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,
1130    * Return or Enter.
1131    */
1132   signals[SIGNAL_APPLICATION_ACTIVATED] =
1133     g_signal_new ("application-activated",
1134                   GTK_TYPE_APP_CHOOSER_WIDGET,
1135                   G_SIGNAL_RUN_FIRST,
1136                   G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
1137                   NULL, NULL,
1138                   _gtk_marshal_VOID__OBJECT,
1139                   G_TYPE_NONE,
1140                   1, G_TYPE_APP_INFO);
1141
1142   /**
1143    * GtkAppChooserWidget::populate-popup:
1144    * @self: the object which received the signal
1145    * @menu: the #GtkMenu to populate
1146    * @application: the current #GAppInfo
1147    *
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.
1152    */
1153   signals[SIGNAL_POPULATE_POPUP] =
1154     g_signal_new ("populate-popup",
1155                   GTK_TYPE_APP_CHOOSER_WIDGET,
1156                   G_SIGNAL_RUN_FIRST,
1157                   G_STRUCT_OFFSET (GtkAppChooserWidgetClass, populate_popup),
1158                   NULL, NULL,
1159                   _gtk_marshal_VOID__OBJECT_OBJECT,
1160                   G_TYPE_NONE,
1161                   2, GTK_TYPE_MENU, G_TYPE_APP_INFO);
1162
1163   g_type_class_add_private (klass, sizeof (GtkAppChooserWidgetPrivate));
1164 }
1165
1166 static void
1167 gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
1168 {
1169   GtkWidget *scrolled_window;
1170   GtkTreeSelection *selection;
1171
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);
1175
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),
1179                                        GTK_SHADOW_IN);
1180   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
1181                                   GTK_POLICY_NEVER,
1182                                   GTK_POLICY_AUTOMATIC);
1183   gtk_widget_show (scrolled_window);
1184
1185   self->priv->program_list = gtk_tree_view_new ();
1186   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->priv->program_list),
1187                                      FALSE);
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);
1191
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,
1195                                           self, NULL);
1196   g_signal_connect_swapped (selection, "changed",
1197                             G_CALLBACK (refresh_and_emit_app_selected),
1198                             self);
1199   g_signal_connect (self->priv->program_list, "row-activated",
1200                     G_CALLBACK (program_list_selection_activated),
1201                     self);
1202   g_signal_connect (self->priv->program_list, "button-press-event",
1203                     G_CALLBACK (widget_button_press_event_cb),
1204                     self);
1205 }
1206
1207 static GAppInfo *
1208 gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
1209 {
1210   GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1211
1212   if (self->priv->selected_app_info == NULL)
1213     return NULL;
1214
1215   return g_object_ref (self->priv->selected_app_info);
1216 }
1217
1218 static void
1219 gtk_app_chooser_widget_refresh (GtkAppChooser *object)
1220 {
1221   GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1222
1223   if (self->priv->program_list_store != NULL)
1224     {
1225       gtk_list_store_clear (self->priv->program_list_store);
1226
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,
1230                     NULL);
1231
1232       gtk_app_chooser_widget_real_add_items (self);
1233     }
1234 }
1235
1236 static void
1237 gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
1238 {
1239   iface->get_app_info = gtk_app_chooser_widget_get_app_info;
1240   iface->refresh = gtk_app_chooser_widget_refresh;
1241 }
1242
1243 /**
1244  * gtk_app_chooser_widget_new:
1245  * @content_type: the content type to show applications for
1246  *
1247  * Creates a new #GtkAppChooserWidget for applications
1248  * that can handle content of the given type.
1249  *
1250  * Returns: a newly created #GtkAppChooserWidget
1251  *
1252  * Since: 3.0
1253  */
1254 GtkWidget *
1255 gtk_app_chooser_widget_new (const gchar *content_type)
1256 {
1257   return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
1258                        "content-type", content_type,
1259                        NULL);
1260 }
1261
1262 /**
1263  * gtk_app_chooser_widget_set_show_default:
1264  * @self: a #GtkAppChooserWidget
1265  * @setting: the new value for #GtkAppChooserWidget:show-default
1266  *
1267  * Sets whether the app chooser should show the default handler
1268  * for the content type in a separate section.
1269  *
1270  * Since: 3.0
1271  */
1272 void
1273 gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
1274                                          gboolean             setting)
1275 {
1276   g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1277
1278   if (self->priv->show_default != setting)
1279     {
1280       self->priv->show_default = setting;
1281
1282       g_object_notify (G_OBJECT (self), "show-default");
1283
1284       gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1285     }
1286 }
1287
1288 /**
1289  * gtk_app_chooser_widget_get_show_default:
1290  * @self: a #GtkAppChooserWidget
1291  *
1292  * Returns the current value of the #GtkAppChooserWidget:show-default
1293  * property.
1294  *
1295  * Returns: the value of #GtkAppChooserWidget:show-default
1296  *
1297  * Since: 3.0
1298  */
1299 gboolean
1300 gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
1301 {
1302   g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1303
1304   return self->priv->show_default;
1305 }
1306
1307 /**
1308  * gtk_app_chooser_widget_set_show_recommended:
1309  * @self: a #GtkAppChooserWidget
1310  * @setting: the new value for #GtkAppChooserWidget:show-recommended
1311  *
1312  * Sets whether the app chooser should show recommended applications
1313  * for the content type in a separate section.
1314  *
1315  * Since: 3.0
1316  */
1317 void
1318 gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
1319                                              gboolean             setting)
1320 {
1321   g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1322
1323   if (self->priv->show_recommended != setting)
1324     {
1325       self->priv->show_recommended = setting;
1326
1327       g_object_notify (G_OBJECT (self), "show-recommended");
1328
1329       gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1330     }
1331 }
1332
1333 /**
1334  * gtk_app_chooser_widget_get_show_recommended:
1335  * @self: a #GtkAppChooserWidget
1336  *
1337  * Returns the current value of the #GtkAppChooserWidget:show-recommended
1338  * property.
1339  *
1340  * Returns: the value of #GtkAppChooserWidget:show-recommended
1341  *
1342  * Since: 3.0
1343  */
1344 gboolean
1345 gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
1346 {
1347   g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1348
1349   return self->priv->show_recommended;
1350 }
1351
1352 /**
1353  * gtk_app_chooser_widget_set_show_fallback:
1354  * @self: a #GtkAppChooserWidget
1355  * @setting: the new value for #GtkAppChooserWidget:show-fallback
1356  *
1357  * Sets whether the app chooser should show related applications
1358  * for the content type in a separate section.
1359  *
1360  * Since: 3.0
1361  */
1362 void
1363 gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
1364                                           gboolean             setting)
1365 {
1366   g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1367
1368   if (self->priv->show_fallback != setting)
1369     {
1370       self->priv->show_fallback = setting;
1371
1372       g_object_notify (G_OBJECT (self), "show-fallback");
1373
1374       gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1375     }
1376 }
1377
1378 /**
1379  * gtk_app_chooser_widget_get_show_fallback:
1380  * @self: a #GtkAppChooserWidget
1381  *
1382  * Returns the current value of the #GtkAppChooserWidget:show-fallback
1383  * property.
1384  *
1385  * Returns: the value of #GtkAppChooserWidget:show-fallback
1386  *
1387  * Since: 3.0
1388  */
1389 gboolean
1390 gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
1391 {
1392   g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1393
1394   return self->priv->show_fallback;
1395 }
1396
1397 /**
1398  * gtk_app_chooser_widget_set_show_other:
1399  * @self: a #GtkAppChooserWidget
1400  * @setting: the new value for #GtkAppChooserWidget:show-other
1401  *
1402  * Sets whether the app chooser should show applications
1403  * which are unrelated to the content type.
1404  *
1405  * Since: 3.0
1406  */
1407 void
1408 gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
1409                                        gboolean             setting)
1410 {
1411   g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1412
1413   if (self->priv->show_other != setting)
1414     {
1415       self->priv->show_other = setting;
1416
1417       g_object_notify (G_OBJECT (self), "show-other");
1418
1419       gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1420     }
1421 }
1422
1423 /**
1424  * gtk_app_chooser_widget_get_show_other:
1425  * @self: a #GtkAppChooserWidget
1426  *
1427  * Returns the current value of the #GtkAppChooserWidget:show-other
1428  * property.
1429  *
1430  * Returns: the value of #GtkAppChooserWidget:show-other
1431  *
1432  * Since: 3.0
1433  */
1434 gboolean
1435 gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
1436 {
1437   g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1438
1439   return self->priv->show_other;
1440 }
1441
1442 /**
1443  * gtk_app_chooser_widget_set_show_all:
1444  * @self: a #GtkAppChooserWidget
1445  * @setting: the new value for #GtkAppChooserWidget:show-all
1446  *
1447  * Sets whether the app chooser should show all applications
1448  * in a flat list.
1449  *
1450  * Since: 3.0
1451  */
1452 void
1453 gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
1454                                      gboolean             setting)
1455 {
1456   g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1457
1458   if (self->priv->show_all != setting)
1459     {
1460       self->priv->show_all = setting;
1461
1462       g_object_notify (G_OBJECT (self), "show-all");
1463
1464       gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1465     }
1466 }
1467
1468 /**
1469  * gtk_app_chooser_widget_get_show_all:
1470  * @self: a #GtkAppChooserWidget
1471  *
1472  * Returns the current value of the #GtkAppChooserWidget:show-all
1473  * property.
1474  *
1475  * Returns: the value of #GtkAppChooserWidget:show-all
1476  *
1477  * Since: 3.0
1478  */
1479 gboolean
1480 gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
1481 {
1482   g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1483
1484   return self->priv->show_all;
1485 }
1486
1487 /**
1488  * gtk_app_chooser_widget_set_default_text:
1489  * @self: a #GtkAppChooserWidget
1490  * @text: the new value for #GtkAppChooserWidget:default-text
1491  *
1492  * Sets the text that is shown if there are not applications
1493  * that can handle the content type.
1494  */
1495 void
1496 gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
1497                                          const gchar         *text)
1498 {
1499   g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1500
1501   if (g_strcmp0 (text, self->priv->default_text) != 0)
1502     {
1503       g_free (self->priv->default_text);
1504       self->priv->default_text = g_strdup (text);
1505
1506       g_object_notify (G_OBJECT (self), "default-text");
1507
1508       gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1509     }
1510 }
1511
1512 /**
1513  * gtk_app_chooser_widget_get_default_text:
1514  * @self: a #GtkAppChooserWidget
1515  *
1516  * Returns the text that is shown if there are not applications
1517  * that can handle the content type.
1518  *
1519  * Returns: the value of #GtkAppChooserWidget:default-text
1520  *
1521  * Since: 3.0
1522  */
1523 const gchar *
1524 gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
1525 {
1526   g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
1527
1528   return self->priv->default_text;
1529 }