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