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 "gtktreeview.h"
35#include "gtktreeselection.h"
36#include "gtktreemodelsort.h"
37#include "gtkorientable.h"
38#include "gtkscrolledwindow.h"
39#include "gtklabel.h"
40#include "gtkgestureclick.h"
41#include "gtkwidgetprivate.h"
42
43#include <string.h>
44#include <glib/gi18n-lib.h>
45#include <gio/gio.h>
46
47/**
48 * GtkAppChooserWidget:
49 *
50 * `GtkAppChooserWidget` is a widget for selecting applications.
51 *
52 * It is the main building block for [class@Gtk.AppChooserDialog].
53 * Most 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 * [property@Gtk.AppChooserWidget:show-default],
59 * [property@Gtk.AppChooserWidget:show-recommended],
60 * [property@Gtk.AppChooserWidget:show-fallback],
61 * [property@Gtk.AppChooserWidget:show-other] and
62 * [property@Gtk.AppChooserWidget:show-all] properties. See the
63 * [iface@Gtk.AppChooser] documentation for more information about these
64 * groups of applications.
65 *
66 * To keep track of the selected application, use the
67 * [signal@Gtk.AppChooserWidget::application-selected] and
68 * [signal@Gtk.AppChooserWidget::application-activated] signals.
69 *
70 * # CSS nodes
71 *
72 * `GtkAppChooserWidget` has a single CSS node with name appchooser.
73 */
74
75typedef struct _GtkAppChooserWidgetClass GtkAppChooserWidgetClass;
76
77struct _GtkAppChooserWidget {
78 GtkWidget parent_instance;
79
80 GAppInfo *selected_app_info;
81
82 GtkWidget *overlay;
83
84 char *content_type;
85 char *default_text;
86
87 guint show_default : 1;
88 guint show_recommended : 1;
89 guint show_fallback : 1;
90 guint show_other : 1;
91 guint show_all : 1;
92
93 GtkWidget *program_list;
94 GtkListStore *program_list_store;
95 GtkWidget *no_apps_label;
96 GtkWidget *no_apps;
97
98 GtkTreeViewColumn *column;
99 GtkCellRenderer *padding_renderer;
100 GtkCellRenderer *secondary_padding;
101
102 GAppInfoMonitor *monitor;
103
104 GtkWidget *popup_menu;
105};
106
107struct _GtkAppChooserWidgetClass {
108 GtkWidgetClass parent_class;
109
110 void (* application_selected) (GtkAppChooserWidget *self,
111 GAppInfo *app_info);
112
113 void (* application_activated) (GtkAppChooserWidget *self,
114 GAppInfo *app_info);
115};
116
117enum {
118 COLUMN_APP_INFO,
119 COLUMN_GICON,
120 COLUMN_NAME,
121 COLUMN_DESC,
122 COLUMN_EXEC,
123 COLUMN_DEFAULT,
124 COLUMN_HEADING,
125 COLUMN_HEADING_TEXT,
126 COLUMN_RECOMMENDED,
127 COLUMN_FALLBACK,
128 NUM_COLUMNS
129};
130
131
132enum {
133 PROP_CONTENT_TYPE = 1,
134 PROP_GFILE,
135 PROP_SHOW_DEFAULT,
136 PROP_SHOW_RECOMMENDED,
137 PROP_SHOW_FALLBACK,
138 PROP_SHOW_OTHER,
139 PROP_SHOW_ALL,
140 PROP_DEFAULT_TEXT,
141 N_PROPERTIES
142};
143
144enum {
145 SIGNAL_APPLICATION_SELECTED,
146 SIGNAL_APPLICATION_ACTIVATED,
147 N_SIGNALS
148};
149
150static guint signals[N_SIGNALS] = { 0, };
151
152static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
153
154G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_WIDGET,
155 G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
156 gtk_app_chooser_widget_iface_init));
157
158static void
159refresh_and_emit_app_selected (GtkAppChooserWidget *self,
160 GtkTreeSelection *selection)
161{
162 GtkTreeModel *model;
163 GtkTreeIter iter;
164 GAppInfo *info = NULL;
165 gboolean should_emit = FALSE;
166
167 if (gtk_tree_selection_get_selected (selection, model: &model, iter: &iter))
168 gtk_tree_model_get (tree_model: model, iter: &iter, COLUMN_APP_INFO, &info, -1);
169
170 if (info == NULL)
171 return;
172
173 if (self->selected_app_info)
174 {
175 if (!g_app_info_equal (appinfo1: self->selected_app_info, appinfo2: info))
176 {
177 should_emit = TRUE;
178 g_set_object (&self->selected_app_info, info);
179 }
180 }
181 else
182 {
183 should_emit = TRUE;
184 g_set_object (&self->selected_app_info, info);
185 }
186
187 g_object_unref (object: info);
188
189 if (should_emit)
190 g_signal_emit (instance: self, signal_id: signals[SIGNAL_APPLICATION_SELECTED], detail: 0,
191 self->selected_app_info);
192}
193
194static gboolean
195path_is_heading (GtkTreeView *view,
196 GtkTreePath *path)
197{
198 GtkTreeIter iter;
199 GtkTreeModel *model;
200 gboolean res;
201
202 model = gtk_tree_view_get_model (tree_view: view);
203 gtk_tree_model_get_iter (tree_model: model, iter: &iter, path);
204 gtk_tree_model_get (tree_model: model, iter: &iter,
205 COLUMN_HEADING, &res,
206 -1);
207
208 return res;
209}
210
211static void
212program_list_selection_activated (GtkTreeView *view,
213 GtkTreePath *path,
214 GtkTreeViewColumn *column,
215 gpointer user_data)
216{
217 GtkAppChooserWidget *self = user_data;
218 GtkTreeSelection *selection;
219
220 if (path_is_heading (view, path))
221 return;
222
223 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
224
225 refresh_and_emit_app_selected (self, selection);
226
227 g_signal_emit (instance: self, signal_id: signals[SIGNAL_APPLICATION_ACTIVATED], detail: 0,
228 self->selected_app_info);
229}
230
231static gboolean
232gtk_app_chooser_search_equal_func (GtkTreeModel *model,
233 int column,
234 const char *key,
235 GtkTreeIter *iter,
236 gpointer user_data)
237{
238 char *name;
239 char *exec_name;
240 gboolean ret;
241
242 if (key != NULL)
243 {
244 ret = TRUE;
245
246 gtk_tree_model_get (tree_model: model, iter,
247 COLUMN_NAME, &name,
248 COLUMN_EXEC, &exec_name,
249 -1);
250
251 if ((name != NULL && g_str_match_string (search_term: key, potential_hit: name, TRUE)) ||
252 (exec_name != NULL && g_str_match_string (search_term: key, potential_hit: exec_name, FALSE)))
253 ret = FALSE;
254
255 g_free (mem: name);
256 g_free (mem: exec_name);
257
258 return ret;
259 }
260 else
261 {
262 return TRUE;
263 }
264}
265
266static int
267gtk_app_chooser_sort_func (GtkTreeModel *model,
268 GtkTreeIter *a,
269 GtkTreeIter *b,
270 gpointer user_data)
271{
272 gboolean a_recommended, b_recommended;
273 gboolean a_fallback, b_fallback;
274 gboolean a_heading, b_heading;
275 gboolean a_default, b_default;
276 char *a_name, *b_name, *a_casefold, *b_casefold;
277 int retval = 0;
278
279 /* this returns:
280 * - <0 if a should show before b
281 * - =0 if a is the same as b
282 * - >0 if a should show after b
283 */
284
285 gtk_tree_model_get (tree_model: model, iter: a,
286 COLUMN_NAME, &a_name,
287 COLUMN_RECOMMENDED, &a_recommended,
288 COLUMN_FALLBACK, &a_fallback,
289 COLUMN_HEADING, &a_heading,
290 COLUMN_DEFAULT, &a_default,
291 -1);
292
293 gtk_tree_model_get (tree_model: model, iter: b,
294 COLUMN_NAME, &b_name,
295 COLUMN_RECOMMENDED, &b_recommended,
296 COLUMN_FALLBACK, &b_fallback,
297 COLUMN_HEADING, &b_heading,
298 COLUMN_DEFAULT, &b_default,
299 -1);
300
301 /* the default one always wins */
302 if (a_default && !b_default)
303 {
304 retval = -1;
305 goto out;
306 }
307
308 if (b_default && !a_default)
309 {
310 retval = 1;
311 goto out;
312 }
313
314 /* the recommended one always wins */
315 if (a_recommended && !b_recommended)
316 {
317 retval = -1;
318 goto out;
319 }
320
321 if (b_recommended && !a_recommended)
322 {
323 retval = 1;
324 goto out;
325 }
326
327 /* the recommended one always wins */
328 if (a_fallback && !b_fallback)
329 {
330 retval = -1;
331 goto out;
332 }
333
334 if (b_fallback && !a_fallback)
335 {
336 retval = 1;
337 goto out;
338 }
339
340 /* they're both recommended/fallback or not, so if one is a heading, wins */
341 if (a_heading)
342 {
343 retval = -1;
344 goto out;
345 }
346
347 if (b_heading)
348 {
349 retval = 1;
350 goto out;
351 }
352
353 /* don't order by name recommended applications, but use GLib's ordering */
354 if (!a_recommended)
355 {
356 a_casefold = a_name != NULL ?
357 g_utf8_casefold (str: a_name, len: -1) : NULL;
358 b_casefold = b_name != NULL ?
359 g_utf8_casefold (str: b_name, len: -1) : NULL;
360
361 retval = g_strcmp0 (str1: a_casefold, str2: b_casefold);
362
363 g_free (mem: a_casefold);
364 g_free (mem: b_casefold);
365 }
366
367 out:
368 g_free (mem: a_name);
369 g_free (mem: b_name);
370
371 return retval;
372}
373
374static void
375padding_cell_renderer_func (GtkTreeViewColumn *column,
376 GtkCellRenderer *cell,
377 GtkTreeModel *model,
378 GtkTreeIter *iter,
379 gpointer user_data)
380{
381 gboolean heading;
382
383 gtk_tree_model_get (tree_model: model, iter,
384 COLUMN_HEADING, &heading,
385 -1);
386 if (heading)
387 g_object_set (object: cell,
388 first_property_name: "visible", FALSE,
389 "xpad", 0,
390 "ypad", 0,
391 NULL);
392 else
393 g_object_set (object: cell,
394 first_property_name: "visible", TRUE,
395 "xpad", 3,
396 "ypad", 3,
397 NULL);
398}
399
400static gboolean
401gtk_app_chooser_selection_func (GtkTreeSelection *selection,
402 GtkTreeModel *model,
403 GtkTreePath *path,
404 gboolean path_currently_selected,
405 gpointer user_data)
406{
407 GtkTreeIter iter;
408 gboolean heading;
409
410 gtk_tree_model_get_iter (tree_model: model, iter: &iter, path);
411 gtk_tree_model_get (tree_model: model, iter: &iter,
412 COLUMN_HEADING, &heading,
413 -1);
414
415 return !heading;
416}
417
418static int
419compare_apps_func (gconstpointer a,
420 gconstpointer b)
421{
422 return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
423}
424
425static gboolean
426gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self,
427 const char *heading_title,
428 gboolean show_headings,
429 gboolean recommended,
430 gboolean fallback,
431 GList *applications,
432 GList *exclude_apps)
433{
434 gboolean heading_added, unref_icon;
435 GtkTreeIter iter;
436 GAppInfo *app;
437 char *app_string, *bold_string;
438 GIcon *icon;
439 GList *l;
440 gboolean retval;
441
442 retval = FALSE;
443 heading_added = FALSE;
444 bold_string = g_strdup_printf (format: "<b>%s</b>", heading_title);
445
446 for (l = applications; l != NULL; l = l->next)
447 {
448 app = l->data;
449
450 if (self->content_type != NULL &&
451 !g_app_info_supports_uris (appinfo: app) &&
452 !g_app_info_supports_files (appinfo: app))
453 continue;
454
455 if (g_list_find_custom (list: exclude_apps, data: app,
456 func: (GCompareFunc) compare_apps_func))
457 continue;
458
459 if (!heading_added && show_headings)
460 {
461 gtk_list_store_append (list_store: self->program_list_store, iter: &iter);
462 gtk_list_store_set (list_store: self->program_list_store, iter: &iter,
463 COLUMN_HEADING_TEXT, bold_string,
464 COLUMN_HEADING, TRUE,
465 COLUMN_RECOMMENDED, recommended,
466 COLUMN_FALLBACK, fallback,
467 -1);
468
469 heading_added = TRUE;
470 }
471
472 app_string = g_markup_printf_escaped (format: "%s",
473 g_app_info_get_name (appinfo: app) != NULL ?
474 g_app_info_get_name (appinfo: app) : "");
475
476 icon = g_app_info_get_icon (appinfo: app);
477 unref_icon = FALSE;
478 if (icon == NULL)
479 {
480 icon = g_themed_icon_new (iconname: "application-x-executable");
481 unref_icon = TRUE;
482 }
483
484 gtk_list_store_append (list_store: self->program_list_store, iter: &iter);
485 gtk_list_store_set (list_store: self->program_list_store, iter: &iter,
486 COLUMN_APP_INFO, app,
487 COLUMN_GICON, icon,
488 COLUMN_NAME, g_app_info_get_name (appinfo: app),
489 COLUMN_DESC, app_string,
490 COLUMN_EXEC, g_app_info_get_executable (appinfo: app),
491 COLUMN_HEADING, FALSE,
492 COLUMN_RECOMMENDED, recommended,
493 COLUMN_FALLBACK, fallback,
494 -1);
495
496 retval = TRUE;
497
498 g_free (mem: app_string);
499 if (unref_icon)
500 g_object_unref (object: icon);
501 }
502
503 g_free (mem: bold_string);
504
505 return retval;
506}
507
508
509static void
510gtk_app_chooser_add_default (GtkAppChooserWidget *self,
511 GAppInfo *app)
512{
513 GtkTreeIter iter;
514 GIcon *icon;
515 char *string;
516 gboolean unref_icon;
517
518 unref_icon = FALSE;
519 string = g_strdup_printf (format: "<b>%s</b>", _("Default Application"));
520
521 gtk_list_store_append (list_store: self->program_list_store, iter: &iter);
522 gtk_list_store_set (list_store: self->program_list_store, iter: &iter,
523 COLUMN_HEADING_TEXT, string,
524 COLUMN_HEADING, TRUE,
525 COLUMN_DEFAULT, TRUE,
526 -1);
527
528 g_free (mem: string);
529
530 string = g_markup_printf_escaped (format: "%s",
531 g_app_info_get_name (appinfo: app) != NULL ?
532 g_app_info_get_name (appinfo: app) : "");
533
534 icon = g_app_info_get_icon (appinfo: app);
535 if (icon == NULL)
536 {
537 icon = g_themed_icon_new (iconname: "application-x-executable");
538 unref_icon = TRUE;
539 }
540
541 gtk_list_store_append (list_store: self->program_list_store, iter: &iter);
542 gtk_list_store_set (list_store: self->program_list_store, iter: &iter,
543 COLUMN_APP_INFO, app,
544 COLUMN_GICON, icon,
545 COLUMN_NAME, g_app_info_get_name (appinfo: app),
546 COLUMN_DESC, string,
547 COLUMN_EXEC, g_app_info_get_executable (appinfo: app),
548 COLUMN_HEADING, FALSE,
549 COLUMN_DEFAULT, TRUE,
550 -1);
551
552 g_free (mem: string);
553
554 if (unref_icon)
555 g_object_unref (object: icon);
556}
557
558static void
559update_no_applications_label (GtkAppChooserWidget *self)
560{
561 char *text = NULL, *desc = NULL;
562 const char *string;
563
564 if (self->default_text == NULL)
565 {
566 if (self->content_type)
567 desc = g_content_type_get_description (type: self->content_type);
568
569 string = text = g_strdup_printf (_("No applications found for “%s”."), desc);
570 g_free (mem: desc);
571 }
572 else
573 {
574 string = self->default_text;
575 }
576
577 gtk_label_set_text (GTK_LABEL (self->no_apps_label), str: string);
578
579 g_free (mem: text);
580}
581
582static void
583gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
584{
585 GtkTreeIter iter;
586 GAppInfo *info = NULL;
587 GtkTreeModel *model;
588
589 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list));
590 if (!gtk_tree_model_get_iter_first (tree_model: model, iter: &iter))
591 return;
592
593 while (info == NULL)
594 {
595 gtk_tree_model_get (tree_model: model, iter: &iter,
596 COLUMN_APP_INFO, &info,
597 -1);
598
599 if (info != NULL)
600 break;
601
602 if (!gtk_tree_model_iter_next (tree_model: model, iter: &iter))
603 break;
604 }
605
606 if (info != NULL)
607 {
608 GtkTreeSelection *selection;
609
610 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
611 gtk_tree_selection_select_iter (selection, iter: &iter);
612
613 g_object_unref (object: info);
614 }
615}
616
617static void
618gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
619{
620 GList *all_applications = NULL;
621 GList *recommended_apps = NULL;
622 GList *fallback_apps = NULL;
623 GList *exclude_apps = NULL;
624 GAppInfo *default_app = NULL;
625 gboolean show_headings;
626 gboolean apps_added;
627
628 show_headings = TRUE;
629 apps_added = FALSE;
630
631 if (self->show_all)
632 show_headings = FALSE;
633
634 if (self->show_default && self->content_type)
635 {
636 default_app = g_app_info_get_default_for_type (content_type: self->content_type, FALSE);
637
638 if (default_app != NULL)
639 {
640 gtk_app_chooser_add_default (self, app: default_app);
641 apps_added = TRUE;
642 exclude_apps = g_list_prepend (list: exclude_apps, data: default_app);
643 }
644 }
645
646#ifndef G_OS_WIN32
647 if ((self->content_type && self->show_recommended) || self->show_all)
648 {
649 if (self->content_type)
650 recommended_apps = g_app_info_get_recommended_for_type (content_type: self->content_type);
651
652 apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
653 show_headings,
654 recommended: !self->show_all, /* mark as recommended */
655 FALSE, /* mark as fallback */
656 applications: recommended_apps, exclude_apps);
657
658 exclude_apps = g_list_concat (list1: exclude_apps,
659 list2: g_list_copy (list: recommended_apps));
660 }
661
662 if ((self->content_type && self->show_fallback) || self->show_all)
663 {
664 if (self->content_type)
665 fallback_apps = g_app_info_get_fallback_for_type (content_type: self->content_type);
666
667 apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
668 show_headings,
669 FALSE, /* mark as recommended */
670 fallback: !self->show_all, /* mark as fallback */
671 applications: fallback_apps, exclude_apps);
672 exclude_apps = g_list_concat (list1: exclude_apps,
673 list2: g_list_copy (list: fallback_apps));
674 }
675#endif
676
677 if (self->show_other || self->show_all)
678 {
679 all_applications = g_app_info_get_all ();
680
681 apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
682 show_headings,
683 FALSE,
684 FALSE,
685 applications: all_applications, exclude_apps);
686 }
687
688 if (!apps_added)
689 update_no_applications_label (self);
690
691 gtk_widget_set_visible (widget: self->no_apps, visible: !apps_added);
692
693 gtk_app_chooser_widget_select_first (self);
694
695 if (default_app != NULL)
696 g_object_unref (object: default_app);
697
698 g_list_free_full (list: all_applications, free_func: g_object_unref);
699 g_list_free_full (list: recommended_apps, free_func: g_object_unref);
700 g_list_free_full (list: fallback_apps, free_func: g_object_unref);
701 g_list_free (list: exclude_apps);
702}
703
704static void
705gtk_app_chooser_widget_initialize_items (GtkAppChooserWidget *self)
706{
707 /* initial padding */
708 g_object_set (object: self->padding_renderer,
709 first_property_name: "xpad", self->show_all ? 0 : 6,
710 NULL);
711
712 /* populate the widget */
713 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
714}
715
716static void
717app_info_changed (GAppInfoMonitor *monitor,
718 GtkAppChooserWidget *self)
719{
720 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
721}
722
723static void
724gtk_app_chooser_widget_set_property (GObject *object,
725 guint property_id,
726 const GValue *value,
727 GParamSpec *pspec)
728{
729 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
730
731 switch (property_id)
732 {
733 case PROP_CONTENT_TYPE:
734 self->content_type = g_value_dup_string (value);
735 break;
736 case PROP_SHOW_DEFAULT:
737 gtk_app_chooser_widget_set_show_default (self, setting: g_value_get_boolean (value));
738 break;
739 case PROP_SHOW_RECOMMENDED:
740 gtk_app_chooser_widget_set_show_recommended (self, setting: g_value_get_boolean (value));
741 break;
742 case PROP_SHOW_FALLBACK:
743 gtk_app_chooser_widget_set_show_fallback (self, setting: g_value_get_boolean (value));
744 break;
745 case PROP_SHOW_OTHER:
746 gtk_app_chooser_widget_set_show_other (self, setting: g_value_get_boolean (value));
747 break;
748 case PROP_SHOW_ALL:
749 gtk_app_chooser_widget_set_show_all (self, setting: g_value_get_boolean (value));
750 break;
751 case PROP_DEFAULT_TEXT:
752 gtk_app_chooser_widget_set_default_text (self, text: g_value_get_string (value));
753 break;
754 default:
755 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
756 break;
757 }
758}
759
760static void
761gtk_app_chooser_widget_get_property (GObject *object,
762 guint property_id,
763 GValue *value,
764 GParamSpec *pspec)
765{
766 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
767
768 switch (property_id)
769 {
770 case PROP_CONTENT_TYPE:
771 g_value_set_string (value, v_string: self->content_type);
772 break;
773 case PROP_SHOW_DEFAULT:
774 g_value_set_boolean (value, v_boolean: self->show_default);
775 break;
776 case PROP_SHOW_RECOMMENDED:
777 g_value_set_boolean (value, v_boolean: self->show_recommended);
778 break;
779 case PROP_SHOW_FALLBACK:
780 g_value_set_boolean (value, v_boolean: self->show_fallback);
781 break;
782 case PROP_SHOW_OTHER:
783 g_value_set_boolean (value, v_boolean: self->show_other);
784 break;
785 case PROP_SHOW_ALL:
786 g_value_set_boolean (value, v_boolean: self->show_all);
787 break;
788 case PROP_DEFAULT_TEXT:
789 g_value_set_string (value, v_string: self->default_text);
790 break;
791 default:
792 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
793 break;
794 }
795}
796
797static void
798gtk_app_chooser_widget_constructed (GObject *object)
799{
800 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
801
802 if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL)
803 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object);
804
805 gtk_app_chooser_widget_initialize_items (self);
806}
807
808static void
809gtk_app_chooser_widget_finalize (GObject *object)
810{
811 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
812
813 g_free (mem: self->content_type);
814 g_free (mem: self->default_text);
815 g_signal_handlers_disconnect_by_func (self->monitor, app_info_changed, self);
816 g_object_unref (object: self->monitor);
817
818 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
819}
820
821static void
822gtk_app_chooser_widget_dispose (GObject *object)
823{
824 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
825
826 g_clear_object (&self->selected_app_info);
827
828 if (self->overlay)
829 {
830 gtk_widget_unparent (widget: self->overlay);
831 self->overlay = NULL;
832 }
833
834 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
835}
836
837static void
838gtk_app_chooser_widget_measure (GtkWidget *widget,
839 GtkOrientation orientation,
840 int for_size,
841 int *minimum,
842 int *natural,
843 int *minimum_baseline,
844 int *natural_baseline)
845{
846 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
847
848 gtk_widget_measure (widget: self->overlay, orientation, for_size,
849 minimum, natural,
850 minimum_baseline, natural_baseline);
851}
852
853static void
854gtk_app_chooser_widget_snapshot (GtkWidget *widget,
855 GtkSnapshot *snapshot)
856{
857 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
858
859 gtk_widget_snapshot_child (widget, child: self->overlay, snapshot);
860}
861
862static void
863gtk_app_chooser_widget_size_allocate (GtkWidget *widget,
864 int width,
865 int height,
866 int baseline)
867{
868 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
869
870 GTK_WIDGET_CLASS (gtk_app_chooser_widget_parent_class)->size_allocate (widget, width, height, baseline);
871
872 gtk_widget_size_allocate (widget: self->overlay,
873 allocation: &(GtkAllocation) {
874 0, 0,
875 width, height
876 },baseline);
877}
878
879static void
880gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
881{
882 GtkWidgetClass *widget_class;
883 GObjectClass *gobject_class;
884 GParamSpec *pspec;
885
886 gobject_class = G_OBJECT_CLASS (klass);
887 gobject_class->dispose = gtk_app_chooser_widget_dispose;
888 gobject_class->finalize = gtk_app_chooser_widget_finalize;
889 gobject_class->set_property = gtk_app_chooser_widget_set_property;
890 gobject_class->get_property = gtk_app_chooser_widget_get_property;
891 gobject_class->constructed = gtk_app_chooser_widget_constructed;
892
893 widget_class = GTK_WIDGET_CLASS (klass);
894 widget_class->measure = gtk_app_chooser_widget_measure;
895 widget_class->size_allocate = gtk_app_chooser_widget_size_allocate;
896 widget_class->snapshot = gtk_app_chooser_widget_snapshot;
897
898 g_object_class_override_property (oclass: gobject_class, property_id: PROP_CONTENT_TYPE, name: "content-type");
899
900 /**
901 * GtkAppChooserWidget:show-default: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_default org.gtk.Property.set=gtk_app_chooser_widget_set_show_default)
902 *
903 * Determines whether the app chooser should show the default
904 * handler for the content type in a separate section.
905 *
906 * If %FALSE, the default handler is listed among the recommended
907 * applications.
908 */
909 pspec = g_param_spec_boolean (name: "show-default",
910 P_("Show default app"),
911 P_("Whether the widget should show the default application"),
912 FALSE,
913 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
914 g_object_class_install_property (oclass: gobject_class, property_id: PROP_SHOW_DEFAULT, pspec);
915
916 /**
917 * GtkAppChooserWidget:show-recommended: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_recommended org.gtk.Property.set=gtk_app_chooser_widget_set_show_recommended)
918 *
919 * Determines whether the app chooser should show a section
920 * for recommended applications.
921 *
922 * If %FALSE, the recommended applications are listed
923 * among the other applications.
924 */
925 pspec = g_param_spec_boolean (name: "show-recommended",
926 P_("Show recommended apps"),
927 P_("Whether the widget should show recommended applications"),
928 TRUE,
929 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
930 g_object_class_install_property (oclass: gobject_class, property_id: PROP_SHOW_RECOMMENDED, pspec);
931
932 /**
933 * GtkAppChooserWidget:show-fallback: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_fallback org.gtk.Property.set=gtk_app_chooser_widget_set_show_fallback)
934 *
935 * Determines whether the app chooser should show a section
936 * for fallback applications.
937 *
938 * If %FALSE, the fallback applications are listed among the
939 * other applications.
940 */
941 pspec = g_param_spec_boolean (name: "show-fallback",
942 P_("Show fallback apps"),
943 P_("Whether the widget should show fallback applications"),
944 FALSE,
945 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
946 g_object_class_install_property (oclass: gobject_class, property_id: PROP_SHOW_FALLBACK, pspec);
947
948 /**
949 * GtkAppChooserWidget:show-other: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_other org.gtk.Property.set=gtk_app_chooser_widget_set_show_other)
950 *
951 * Determines whether the app chooser should show a section
952 * for other applications.
953 */
954 pspec = g_param_spec_boolean (name: "show-other",
955 P_("Show other apps"),
956 P_("Whether the widget should show other applications"),
957 FALSE,
958 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
959 g_object_class_install_property (oclass: gobject_class, property_id: PROP_SHOW_OTHER, pspec);
960
961 /**
962 * GtkAppChooserWidget:show-all: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_all org.gtk.Property.set=gtk_app_chooser_widget_set_show_all)
963 *
964 * If %TRUE, the app chooser presents all applications
965 * in a single list, without subsections for default,
966 * recommended or related applications.
967 */
968 pspec = g_param_spec_boolean (name: "show-all",
969 P_("Show all apps"),
970 P_("Whether the widget should show all applications"),
971 FALSE,
972 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
973 g_object_class_install_property (oclass: gobject_class, property_id: PROP_SHOW_ALL, pspec);
974
975 /**
976 * GtkAppChooserWidget:default-text: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_default_text org.gtk.Property.set=gtk_app_chooser_widget_set_default_text)
977 *
978 * The text that appears in the widget when there are no applications
979 * for the given content type.
980 */
981 pspec = g_param_spec_string (name: "default-text",
982 P_("Widget’s default text"),
983 P_("The default text appearing when there are no applications"),
984 NULL,
985 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
986 g_object_class_install_property (oclass: gobject_class, property_id: PROP_DEFAULT_TEXT, pspec);
987
988 /**
989 * GtkAppChooserWidget::application-selected:
990 * @self: the object which received the signal
991 * @application: the selected `GAppInfo`
992 *
993 * Emitted when an application item is selected from the widget's list.
994 */
995 signals[SIGNAL_APPLICATION_SELECTED] =
996 g_signal_new (I_("application-selected"),
997 GTK_TYPE_APP_CHOOSER_WIDGET,
998 signal_flags: G_SIGNAL_RUN_FIRST,
999 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
1000 NULL, NULL,
1001 NULL,
1002 G_TYPE_NONE,
1003 n_params: 1, G_TYPE_APP_INFO);
1004
1005 /**
1006 * GtkAppChooserWidget::application-activated:
1007 * @self: the object which received the signal
1008 * @application: the activated `GAppInfo`
1009 *
1010 * Emitted when an application item is activated from the widget's list.
1011 *
1012 * This usually happens when the user double clicks an item, or an item
1013 * is selected and the user presses one of the keys Space, Shift+Space,
1014 * Return or Enter.
1015 */
1016 signals[SIGNAL_APPLICATION_ACTIVATED] =
1017 g_signal_new (I_("application-activated"),
1018 GTK_TYPE_APP_CHOOSER_WIDGET,
1019 signal_flags: G_SIGNAL_RUN_FIRST,
1020 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
1021 NULL, NULL,
1022 NULL,
1023 G_TYPE_NONE,
1024 n_params: 1, G_TYPE_APP_INFO);
1025
1026 /* Bind class to template
1027 */
1028 gtk_widget_class_set_template_from_resource (widget_class,
1029 resource_name: "/org/gtk/libgtk/ui/gtkappchooserwidget.ui");
1030 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list);
1031 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list_store);
1032 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, column);
1033 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, padding_renderer);
1034 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, secondary_padding);
1035 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps_label);
1036 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps);
1037 gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, overlay);
1038 gtk_widget_class_bind_template_callback (widget_class, refresh_and_emit_app_selected);
1039 gtk_widget_class_bind_template_callback (widget_class, program_list_selection_activated);
1040
1041 gtk_widget_class_set_css_name (widget_class, I_("appchooser"));
1042}
1043
1044static void
1045gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
1046{
1047 GtkTreeSelection *selection;
1048 GtkTreeModel *sort;
1049
1050 gtk_widget_init_template (GTK_WIDGET (self));
1051
1052 /* Various parts of the GtkTreeView code need custom code to setup, mostly
1053 * because we lack signals to connect to, or properties to set.
1054 */
1055 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
1056 gtk_tree_selection_set_select_function (selection, func: gtk_app_chooser_selection_func,
1057 data: self, NULL);
1058
1059 sort = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list));
1060 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort),
1061 sort_column_id: COLUMN_NAME,
1062 order: GTK_SORT_ASCENDING);
1063 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
1064 sort_column_id: COLUMN_NAME,
1065 sort_func: gtk_app_chooser_sort_func,
1066 user_data: self, NULL);
1067
1068 gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->program_list), column: COLUMN_NAME);
1069 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->program_list),
1070 search_equal_func: gtk_app_chooser_search_equal_func,
1071 NULL, NULL);
1072
1073 gtk_tree_view_column_set_cell_data_func (tree_column: self->column,
1074 cell_renderer: self->secondary_padding,
1075 func: padding_cell_renderer_func,
1076 NULL, NULL);
1077
1078 self->monitor = g_app_info_monitor_get ();
1079 g_signal_connect (self->monitor, "changed",
1080 G_CALLBACK (app_info_changed), self);
1081}
1082
1083static GAppInfo *
1084gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
1085{
1086 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1087
1088 if (self->selected_app_info == NULL)
1089 return NULL;
1090
1091 return g_object_ref (self->selected_app_info);
1092}
1093
1094static void
1095gtk_app_chooser_widget_refresh (GtkAppChooser *object)
1096{
1097 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1098
1099 if (self->program_list_store != NULL)
1100 {
1101 gtk_list_store_clear (list_store: self->program_list_store);
1102
1103 /* don't add additional xpad if we don't have headings */
1104 g_object_set (object: self->padding_renderer,
1105 first_property_name: "visible", !self->show_all,
1106 NULL);
1107
1108 gtk_app_chooser_widget_real_add_items (self);
1109 }
1110}
1111
1112static void
1113gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
1114{
1115 iface->get_app_info = gtk_app_chooser_widget_get_app_info;
1116 iface->refresh = gtk_app_chooser_widget_refresh;
1117}
1118
1119/**
1120 * gtk_app_chooser_widget_new:
1121 * @content_type: the content type to show applications for
1122 *
1123 * Creates a new `GtkAppChooserWidget` for applications
1124 * that can handle content of the given type.
1125 *
1126 * Returns: a newly created `GtkAppChooserWidget`
1127 */
1128GtkWidget *
1129gtk_app_chooser_widget_new (const char *content_type)
1130{
1131 return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
1132 first_property_name: "content-type", content_type,
1133 NULL);
1134}
1135
1136/**
1137 * gtk_app_chooser_widget_set_show_default: (attributes org.gtk.Method.set_property=show-default)
1138 * @self: a `GtkAppChooserWidget`
1139 * @setting: the new value for [property@Gtk.AppChooserWidget:show-default]
1140 *
1141 * Sets whether the app chooser should show the default handler
1142 * for the content type in a separate section.
1143 */
1144void
1145gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
1146 gboolean setting)
1147{
1148 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1149
1150 if (self->show_default != setting)
1151 {
1152 self->show_default = setting;
1153
1154 g_object_notify (G_OBJECT (self), property_name: "show-default");
1155
1156 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1157 }
1158}
1159
1160/**
1161 * gtk_app_chooser_widget_get_show_default: (attributes org.gtk.Method.get_property=show-default)
1162 * @self: a `GtkAppChooserWidget`
1163 *
1164 * Gets whether the app chooser should show the default handler
1165 * for the content type in a separate section.
1166 *
1167 * Returns: the value of [property@Gtk.AppChooserWidget:show-default]
1168 */
1169gboolean
1170gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
1171{
1172 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1173
1174 return self->show_default;
1175}
1176
1177/**
1178 * gtk_app_chooser_widget_set_show_recommended: (attributes org.gtk.Method.set_property=show-recommended)
1179 * @self: a `GtkAppChooserWidget`
1180 * @setting: the new value for [property@Gtk.AppChooserWidget:show-recommended]
1181 *
1182 * Sets whether the app chooser should show recommended applications
1183 * for the content type in a separate section.
1184 */
1185void
1186gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
1187 gboolean setting)
1188{
1189 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1190
1191 if (self->show_recommended != setting)
1192 {
1193 self->show_recommended = setting;
1194
1195 g_object_notify (G_OBJECT (self), property_name: "show-recommended");
1196
1197 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1198 }
1199}
1200
1201/**
1202 * gtk_app_chooser_widget_get_show_recommended: (attributes org.gtk.Method.get_property=show-recommended)
1203 * @self: a `GtkAppChooserWidget`
1204 *
1205 * Gets whether the app chooser should show recommended applications
1206 * for the content type in a separate section.
1207 *
1208 * Returns: the value of [property@Gtk.AppChooserWidget:show-recommended]
1209 */
1210gboolean
1211gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
1212{
1213 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1214
1215 return self->show_recommended;
1216}
1217
1218/**
1219 * gtk_app_chooser_widget_set_show_fallback: (attributes org.gtk.Method.set_property=show-fallback)
1220 * @self: a `GtkAppChooserWidget`
1221 * @setting: the new value for [property@Gtk.AppChooserWidget:show-fallback]
1222 *
1223 * Sets whether the app chooser should show related applications
1224 * for the content type in a separate section.
1225 */
1226void
1227gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
1228 gboolean setting)
1229{
1230 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1231
1232 if (self->show_fallback != setting)
1233 {
1234 self->show_fallback = setting;
1235
1236 g_object_notify (G_OBJECT (self), property_name: "show-fallback");
1237
1238 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1239 }
1240}
1241
1242/**
1243 * gtk_app_chooser_widget_get_show_fallback: (attributes org.gtk.Method.get_property=show-fallback)
1244 * @self: a `GtkAppChooserWidget`
1245 *
1246 * Gets whether the app chooser should show related applications
1247 * for the content type in a separate section.
1248 *
1249 * Returns: the value of [property@Gtk.AppChooserWidget:show-fallback]
1250 */
1251gboolean
1252gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
1253{
1254 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1255
1256 return self->show_fallback;
1257}
1258
1259/**
1260 * gtk_app_chooser_widget_set_show_other: (attributes org.gtk.Method.set_property=show-other)
1261 * @self: a `GtkAppChooserWidget`
1262 * @setting: the new value for [property@Gtk.AppChooserWidget:show-other]
1263 *
1264 * Sets whether the app chooser should show applications
1265 * which are unrelated to the content type.
1266 */
1267void
1268gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
1269 gboolean setting)
1270{
1271 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1272
1273 if (self->show_other != setting)
1274 {
1275 self->show_other = setting;
1276
1277 g_object_notify (G_OBJECT (self), property_name: "show-other");
1278
1279 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1280 }
1281}
1282
1283/**
1284 * gtk_app_chooser_widget_get_show_other: (attributes org.gtk.Method.get_property=show-other)
1285 * @self: a `GtkAppChooserWidget`
1286 *
1287 * Gets whether the app chooser should show applications
1288 * which are unrelated to the content type.
1289 *
1290 * Returns: the value of [property@Gtk.AppChooserWidget:show-other]
1291 */
1292gboolean
1293gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
1294{
1295 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1296
1297 return self->show_other;
1298}
1299
1300/**
1301 * gtk_app_chooser_widget_set_show_all: (attributes org.gtk.Method.set_property=show-all)
1302 * @self: a `GtkAppChooserWidget`
1303 * @setting: the new value for [property@Gtk.AppChooserWidget:show-all]
1304 *
1305 * Sets whether the app chooser should show all applications
1306 * in a flat list.
1307 */
1308void
1309gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
1310 gboolean setting)
1311{
1312 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1313
1314 if (self->show_all != setting)
1315 {
1316 self->show_all = setting;
1317
1318 g_object_notify (G_OBJECT (self), property_name: "show-all");
1319
1320 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1321 }
1322}
1323
1324/**
1325 * gtk_app_chooser_widget_get_show_all: (attributes org.gtk.Method.get_property=show-all)
1326 * @self: a `GtkAppChooserWidget`
1327 *
1328 * Gets whether the app chooser should show all applications
1329 * in a flat list.
1330 *
1331 * Returns: the value of [property@Gtk.AppChooserWidget:show-all]
1332 */
1333gboolean
1334gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
1335{
1336 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1337
1338 return self->show_all;
1339}
1340
1341/**
1342 * gtk_app_chooser_widget_set_default_text: (attributes org.gtk.Method.set_property=default-text)
1343 * @self: a `GtkAppChooserWidget`
1344 * @text: the new value for [property@Gtk.AppChooserWidget:default-text]
1345 *
1346 * Sets the text that is shown if there are not applications
1347 * that can handle the content type.
1348 */
1349void
1350gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
1351 const char *text)
1352{
1353 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1354
1355 if (g_strcmp0 (str1: text, str2: self->default_text) != 0)
1356 {
1357 g_free (mem: self->default_text);
1358 self->default_text = g_strdup (str: text);
1359
1360 g_object_notify (G_OBJECT (self), property_name: "default-text");
1361
1362 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1363 }
1364}
1365
1366/**
1367 * gtk_app_chooser_widget_get_default_text: (attributes org.gtk.Method.get_property=default-text)
1368 * @self: a `GtkAppChooserWidget`
1369 *
1370 * Returns the text that is shown if there are not applications
1371 * that can handle the content type.
1372 *
1373 * Returns: (nullable): the value of [property@Gtk.AppChooserWidget:default-text]
1374 */
1375const char *
1376gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
1377{
1378 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
1379
1380 return self->default_text;
1381}
1382
1383void
1384_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self,
1385 GtkEditable *entry)
1386{
1387 gtk_tree_view_set_search_entry (GTK_TREE_VIEW (self->program_list), entry);
1388
1389 g_object_bind_property (source: self->no_apps, source_property: "visible",
1390 target: entry, target_property: "sensitive",
1391 flags: G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
1392}
1393

source code of gtk/gtk/gtkappchooserwidget.c