1 /*
2 * gtkappchooserwidget.c: an app-chooser widget
3 *
4 * Copyright (C) 2004 Novell, Inc.
5 * Copyright (C) 2007, 2010 Red Hat, Inc.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * Authors: Dave Camp <dave@novell.com>
21 * Alexander Larsson <alexl@redhat.com>
22 * Cosimo Cecchi <ccecchi@redhat.com>
23 */
24
25 #include "config.h"
26
27 #include "gtkappchooserwidget.h"
28
29 #include "gtkintl.h"
30 #include "gtkmarshalers.h"
31 #include "gtkappchooserwidget.h"
32 #include "gtkappchooserprivate.h"
33 #include "gtkliststore.h"
34 #include "gtkcellrenderertext.h"
35 #include "gtkcellrendererpixbuf.h"
36 #include "gtktreeview.h"
37 #include "gtktreeselection.h"
38 #include "gtktreemodelsort.h"
39 #include "gtkorientable.h"
40 #include "gtkscrolledwindow.h"
41 #include "gtklabel.h"
42
43 #include <string.h>
44 #include <glib/gi18n-lib.h>
45 #include <gio/gio.h>
46
47 /**
48 * SECTION:gtkappchooserwidget
49 * @Title: GtkAppChooserWidget
50 * @Short_description: Application chooser widget that can be embedded in other widgets
51 *
52 * #GtkAppChooserWidget is a widget for selecting applications.
53 * It is the main building block for #GtkAppChooserDialog. Most
54 * applications only need to use the latter; but you can use
55 * this widget as part of a larger widget if you have special needs.
56 *
57 * #GtkAppChooserWidget offers detailed control over what applications
58 * are shown, using the
59 * #GtkAppChooserWidget:show-default,
60 * #GtkAppChooserWidget:show-recommended,
61 * #GtkAppChooserWidget:show-fallback,
62 * #GtkAppChooserWidget:show-other and
63 * #GtkAppChooserWidget:show-all
64 * properties. See the #GtkAppChooser documentation for more information
65 * about these groups of applications.
66 *
67 * To keep track of the selected application, use the
68 * #GtkAppChooserWidget::application-selected and #GtkAppChooserWidget::application-activated signals.
69 *
70 * # CSS nodes
71 *
72 * GtkAppChooserWidget has a single CSS node with name appchooser.
73 */
74
75 struct _GtkAppChooserWidgetPrivate {
76 GAppInfo *selected_app_info;
77
78 gchar *content_type;
79 gchar *default_text;
80
81 guint show_default : 1;
82 guint show_recommended : 1;
83 guint show_fallback : 1;
84 guint show_other : 1;
85 guint show_all : 1;
86
87 GtkWidget *program_list;
88 GtkListStore *program_list_store;
89 GtkWidget *no_apps_label;
90 GtkWidget *no_apps;
91
92 GtkTreeViewColumn *column;
93 GtkCellRenderer *padding_renderer;
94 GtkCellRenderer *secondary_padding;
95
96 GAppInfoMonitor *monitor;
97
98 GtkWidget *popup_menu;
99 };
100
101 enum {
102 COLUMN_APP_INFO,
103 COLUMN_GICON,
104 COLUMN_NAME,
105 COLUMN_DESC,
106 COLUMN_EXEC,
107 COLUMN_DEFAULT,
108 COLUMN_HEADING,
109 COLUMN_HEADING_TEXT,
110 COLUMN_RECOMMENDED,
111 COLUMN_FALLBACK,
112 NUM_COLUMNS
113 };
114
115
116 enum {
117 PROP_CONTENT_TYPE = 1,
118 PROP_GFILE,
119 PROP_SHOW_DEFAULT,
120 PROP_SHOW_RECOMMENDED,
121 PROP_SHOW_FALLBACK,
122 PROP_SHOW_OTHER,
123 PROP_SHOW_ALL,
124 PROP_DEFAULT_TEXT,
125 N_PROPERTIES
126 };
127
128 enum {
129 SIGNAL_APPLICATION_SELECTED,
130 SIGNAL_APPLICATION_ACTIVATED,
131 SIGNAL_POPULATE_POPUP,
132 N_SIGNALS
133 };
134
135 static guint signals[N_SIGNALS] = { 0, };
136
137 static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
138
139 G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_BOX,
140 G_ADD_PRIVATE (GtkAppChooserWidget)
141 G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
142 gtk_app_chooser_widget_iface_init));
143
144 static void
refresh_and_emit_app_selected(GtkAppChooserWidget * self,GtkTreeSelection * selection)145 refresh_and_emit_app_selected (GtkAppChooserWidget *self,
146 GtkTreeSelection *selection)
147 {
148 GtkTreeModel *model;
149 GtkTreeIter iter;
150 GAppInfo *info = NULL;
151 gboolean should_emit = FALSE;
152
153 if (gtk_tree_selection_get_selected (selection, &model, &iter))
154 gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1);
155
156 if (info == NULL)
157 return;
158
159 if (self->priv->selected_app_info)
160 {
161 if (!g_app_info_equal (self->priv->selected_app_info, info))
162 {
163 should_emit = TRUE;
164 g_set_object (&self->priv->selected_app_info, info);
165 }
166 }
167 else
168 {
169 should_emit = TRUE;
170 g_set_object (&self->priv->selected_app_info, info);
171 }
172
173 g_object_unref (info);
174
175 if (should_emit)
176 g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0,
177 self->priv->selected_app_info);
178 }
179
180 static GAppInfo *
get_app_info_for_event(GtkAppChooserWidget * self,GdkEventButton * event)181 get_app_info_for_event (GtkAppChooserWidget *self,
182 GdkEventButton *event)
183 {
184 GtkTreePath *path = NULL;
185 GtkTreeIter iter;
186 GtkTreeModel *model;
187 GAppInfo *info;
188 gboolean recommended;
189
190 if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (self->priv->program_list),
191 event->x, event->y,
192 &path,
193 NULL, NULL, NULL))
194 return NULL;
195
196 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
197
198 if (!gtk_tree_model_get_iter (model, &iter, path))
199 {
200 gtk_tree_path_free (path);
201 return NULL;
202 }
203
204 /* we only allow interaction with recommended applications */
205 gtk_tree_model_get (model, &iter,
206 COLUMN_APP_INFO, &info,
207 COLUMN_RECOMMENDED, &recommended,
208 -1);
209
210 if (!recommended)
211 g_clear_object (&info);
212
213 return info;
214 }
215
216 static void
popup_menu_detach(GtkWidget * attach_widget,GtkMenu * menu)217 popup_menu_detach (GtkWidget *attach_widget,
218 GtkMenu *menu)
219 {
220 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (attach_widget);
221
222 self->priv->popup_menu = NULL;
223 }
224
225 static gboolean
widget_button_press_event_cb(GtkWidget * widget,GdkEventButton * event,gpointer user_data)226 widget_button_press_event_cb (GtkWidget *widget,
227 GdkEventButton *event,
228 gpointer user_data)
229 {
230 GtkAppChooserWidget *self = user_data;
231
232 if (event->button == GDK_BUTTON_SECONDARY && event->type == GDK_BUTTON_PRESS)
233 {
234 GAppInfo *info;
235 GtkWidget *menu;
236 GList *children;
237 gint n_children;
238
239 info = get_app_info_for_event (self, event);
240
241 if (info == NULL)
242 return FALSE;
243
244 if (self->priv->popup_menu)
245 gtk_widget_destroy (self->priv->popup_menu);
246
247 self->priv->popup_menu = menu = gtk_menu_new ();
248 gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (self), popup_menu_detach);
249
250 g_signal_emit (self, signals[SIGNAL_POPULATE_POPUP], 0, menu, info);
251
252 g_object_unref (info);
253
254 /* see if clients added menu items to this container */
255 children = gtk_container_get_children (GTK_CONTAINER (menu));
256 n_children = g_list_length (children);
257
258 if (n_children > 0)
259 /* actually popup the menu */
260 gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) event);
261
262 g_list_free (children);
263 }
264
265 return FALSE;
266 }
267
268 static gboolean
path_is_heading(GtkTreeView * view,GtkTreePath * path)269 path_is_heading (GtkTreeView *view,
270 GtkTreePath *path)
271 {
272 GtkTreeIter iter;
273 GtkTreeModel *model;
274 gboolean res;
275
276 model = gtk_tree_view_get_model (view);
277 gtk_tree_model_get_iter (model, &iter, path);
278 gtk_tree_model_get (model, &iter,
279 COLUMN_HEADING, &res,
280 -1);
281
282 return res;
283 }
284
285 static void
program_list_selection_activated(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer user_data)286 program_list_selection_activated (GtkTreeView *view,
287 GtkTreePath *path,
288 GtkTreeViewColumn *column,
289 gpointer user_data)
290 {
291 GtkAppChooserWidget *self = user_data;
292 GtkTreeSelection *selection;
293
294 if (path_is_heading (view, path))
295 return;
296
297 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
298
299 refresh_and_emit_app_selected (self, selection);
300
301 g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0,
302 self->priv->selected_app_info);
303 }
304
305 static gboolean
gtk_app_chooser_search_equal_func(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer user_data)306 gtk_app_chooser_search_equal_func (GtkTreeModel *model,
307 gint column,
308 const gchar *key,
309 GtkTreeIter *iter,
310 gpointer user_data)
311 {
312 gchar *name;
313 gchar *exec_name;
314 gboolean ret;
315
316 if (key != NULL)
317 {
318 ret = TRUE;
319
320 gtk_tree_model_get (model, iter,
321 COLUMN_NAME, &name,
322 COLUMN_EXEC, &exec_name,
323 -1);
324
325 if ((name != NULL && g_str_match_string (key, name, TRUE)) ||
326 (exec_name != NULL && g_str_match_string (key, exec_name, FALSE)))
327 ret = FALSE;
328
329 g_free (name);
330 g_free (exec_name);
331
332 return ret;
333 }
334 else
335 {
336 return TRUE;
337 }
338 }
339
340 static gint
gtk_app_chooser_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)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/fallback 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
padding_cell_renderer_func(GtkTreeViewColumn * column,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer user_data)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
gtk_app_chooser_selection_func(GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean path_currently_selected,gpointer user_data)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
compare_apps_func(gconstpointer a,gconstpointer b)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
gtk_app_chooser_widget_add_section(GtkAppChooserWidget * self,const gchar * heading_title,gboolean show_headings,gboolean recommended,gboolean fallback,GList * applications,GList * exclude_apps)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 (self->priv->content_type != NULL &&
525 !g_app_info_supports_uris (app) &&
526 !g_app_info_supports_files (app))
527 continue;
528
529 if (g_list_find_custom (exclude_apps, app,
530 (GCompareFunc) compare_apps_func))
531 continue;
532
533 if (!heading_added && show_headings)
534 {
535 gtk_list_store_append (self->priv->program_list_store, &iter);
536 gtk_list_store_set (self->priv->program_list_store, &iter,
537 COLUMN_HEADING_TEXT, bold_string,
538 COLUMN_HEADING, TRUE,
539 COLUMN_RECOMMENDED, recommended,
540 COLUMN_FALLBACK, fallback,
541 -1);
542
543 heading_added = TRUE;
544 }
545
546 app_string = g_markup_printf_escaped ("%s",
547 g_app_info_get_name (app) != NULL ?
548 g_app_info_get_name (app) : "");
549
550 icon = g_app_info_get_icon (app);
551 unref_icon = FALSE;
552 if (icon == NULL)
553 {
554 icon = g_themed_icon_new ("application-x-executable");
555 unref_icon = TRUE;
556 }
557
558 gtk_list_store_append (self->priv->program_list_store, &iter);
559 gtk_list_store_set (self->priv->program_list_store, &iter,
560 COLUMN_APP_INFO, app,
561 COLUMN_GICON, icon,
562 COLUMN_NAME, g_app_info_get_name (app),
563 COLUMN_DESC, app_string,
564 COLUMN_EXEC, g_app_info_get_executable (app),
565 COLUMN_HEADING, FALSE,
566 COLUMN_RECOMMENDED, recommended,
567 COLUMN_FALLBACK, fallback,
568 -1);
569
570 retval = TRUE;
571
572 g_free (app_string);
573 if (unref_icon)
574 g_object_unref (icon);
575 }
576
577 g_free (bold_string);
578
579 return retval;
580 }
581
582
583 static void
gtk_app_chooser_add_default(GtkAppChooserWidget * self,GAppInfo * app)584 gtk_app_chooser_add_default (GtkAppChooserWidget *self,
585 GAppInfo *app)
586 {
587 GtkTreeIter iter;
588 GIcon *icon;
589 gchar *string;
590 gboolean unref_icon;
591
592 unref_icon = FALSE;
593 string = g_strdup_printf ("<b>%s</b>", _("Default Application"));
594
595 gtk_list_store_append (self->priv->program_list_store, &iter);
596 gtk_list_store_set (self->priv->program_list_store, &iter,
597 COLUMN_HEADING_TEXT, string,
598 COLUMN_HEADING, TRUE,
599 COLUMN_DEFAULT, TRUE,
600 -1);
601
602 g_free (string);
603
604 string = g_markup_printf_escaped ("%s",
605 g_app_info_get_name (app) != NULL ?
606 g_app_info_get_name (app) : "");
607
608 icon = g_app_info_get_icon (app);
609 if (icon == NULL)
610 {
611 icon = g_themed_icon_new ("application-x-executable");
612 unref_icon = TRUE;
613 }
614
615 gtk_list_store_append (self->priv->program_list_store, &iter);
616 gtk_list_store_set (self->priv->program_list_store, &iter,
617 COLUMN_APP_INFO, app,
618 COLUMN_GICON, icon,
619 COLUMN_NAME, g_app_info_get_name (app),
620 COLUMN_DESC, string,
621 COLUMN_EXEC, g_app_info_get_executable (app),
622 COLUMN_HEADING, FALSE,
623 COLUMN_DEFAULT, TRUE,
624 -1);
625
626 g_free (string);
627
628 if (unref_icon)
629 g_object_unref (icon);
630 }
631
632 static void
update_no_applications_label(GtkAppChooserWidget * self)633 update_no_applications_label (GtkAppChooserWidget *self)
634 {
635 gchar *text = NULL, *desc = NULL;
636 const gchar *string;
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 found for “%s”."), desc);
644 g_free (desc);
645 }
646 else
647 {
648 string = self->priv->default_text;
649 }
650
651 gtk_label_set_text (GTK_LABEL (self->priv->no_apps_label), string);
652
653 g_free (text);
654 }
655
656 static void
gtk_app_chooser_widget_select_first(GtkAppChooserWidget * self)657 gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
658 {
659 GtkTreeIter iter;
660 GAppInfo *info = NULL;
661 GtkTreeModel *model;
662
663 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
664 if (!gtk_tree_model_get_iter_first (model, &iter))
665 return;
666
667 while (info == NULL)
668 {
669 gtk_tree_model_get (model, &iter,
670 COLUMN_APP_INFO, &info,
671 -1);
672
673 if (info != NULL)
674 break;
675
676 if (!gtk_tree_model_iter_next (model, &iter))
677 break;
678 }
679
680 if (info != NULL)
681 {
682 GtkTreeSelection *selection;
683
684 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
685 gtk_tree_selection_select_iter (selection, &iter);
686
687 g_object_unref (info);
688 }
689 }
690
691 static void
gtk_app_chooser_widget_real_add_items(GtkAppChooserWidget * self)692 gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
693 {
694 GList *all_applications = NULL;
695 GList *recommended_apps = NULL;
696 GList *fallback_apps = NULL;
697 GList *exclude_apps = NULL;
698 GAppInfo *default_app = NULL;
699 gboolean show_headings;
700 gboolean apps_added;
701
702 show_headings = TRUE;
703 apps_added = FALSE;
704
705 if (self->priv->show_all)
706 show_headings = FALSE;
707
708 if (self->priv->show_default && self->priv->content_type)
709 {
710 default_app = g_app_info_get_default_for_type (self->priv->content_type, FALSE);
711
712 if (default_app != NULL)
713 {
714 gtk_app_chooser_add_default (self, default_app);
715 apps_added = TRUE;
716 exclude_apps = g_list_prepend (exclude_apps, default_app);
717 }
718 }
719
720 #ifndef G_OS_WIN32
721 if ((self->priv->content_type && self->priv->show_recommended) || self->priv->show_all)
722 {
723 if (self->priv->content_type)
724 recommended_apps = g_app_info_get_recommended_for_type (self->priv->content_type);
725
726 apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
727 show_headings,
728 !self->priv->show_all, /* mark as recommended */
729 FALSE, /* mark as fallback */
730 recommended_apps, exclude_apps);
731
732 exclude_apps = g_list_concat (exclude_apps,
733 g_list_copy (recommended_apps));
734 }
735
736 if ((self->priv->content_type && self->priv->show_fallback) || self->priv->show_all)
737 {
738 if (self->priv->content_type)
739 fallback_apps = g_app_info_get_fallback_for_type (self->priv->content_type);
740
741 apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
742 show_headings,
743 FALSE, /* mark as recommended */
744 !self->priv->show_all, /* mark as fallback */
745 fallback_apps, exclude_apps);
746 exclude_apps = g_list_concat (exclude_apps,
747 g_list_copy (fallback_apps));
748 }
749 #endif
750
751 if (self->priv->show_other || self->priv->show_all)
752 {
753 all_applications = g_app_info_get_all ();
754
755 apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
756 show_headings,
757 FALSE,
758 FALSE,
759 all_applications, exclude_apps);
760 }
761
762 if (!apps_added)
763 update_no_applications_label (self);
764
765 gtk_widget_set_visible (self->priv->no_apps, !apps_added);
766
767 gtk_app_chooser_widget_select_first (self);
768
769 if (default_app != NULL)
770 g_object_unref (default_app);
771
772 g_list_free_full (all_applications, g_object_unref);
773 g_list_free_full (recommended_apps, g_object_unref);
774 g_list_free_full (fallback_apps, g_object_unref);
775 g_list_free (exclude_apps);
776 }
777
778 static void
gtk_app_chooser_widget_initialize_items(GtkAppChooserWidget * self)779 gtk_app_chooser_widget_initialize_items (GtkAppChooserWidget *self)
780 {
781 /* initial padding */
782 g_object_set (self->priv->padding_renderer,
783 "xpad", self->priv->show_all ? 0 : 6,
784 NULL);
785
786 /* populate the widget */
787 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
788 }
789
790 static void
app_info_changed(GAppInfoMonitor * monitor,GtkAppChooserWidget * self)791 app_info_changed (GAppInfoMonitor *monitor,
792 GtkAppChooserWidget *self)
793 {
794 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
795 }
796
797 static void
gtk_app_chooser_widget_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)798 gtk_app_chooser_widget_set_property (GObject *object,
799 guint property_id,
800 const GValue *value,
801 GParamSpec *pspec)
802 {
803 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
804
805 switch (property_id)
806 {
807 case PROP_CONTENT_TYPE:
808 self->priv->content_type = g_value_dup_string (value);
809 break;
810 case PROP_SHOW_DEFAULT:
811 gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value));
812 break;
813 case PROP_SHOW_RECOMMENDED:
814 gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value));
815 break;
816 case PROP_SHOW_FALLBACK:
817 gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value));
818 break;
819 case PROP_SHOW_OTHER:
820 gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value));
821 break;
822 case PROP_SHOW_ALL:
823 gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value));
824 break;
825 case PROP_DEFAULT_TEXT:
826 gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value));
827 break;
828 default:
829 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
830 break;
831 }
832 }
833
834 static void
gtk_app_chooser_widget_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)835 gtk_app_chooser_widget_get_property (GObject *object,
836 guint property_id,
837 GValue *value,
838 GParamSpec *pspec)
839 {
840 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
841
842 switch (property_id)
843 {
844 case PROP_CONTENT_TYPE:
845 g_value_set_string (value, self->priv->content_type);
846 break;
847 case PROP_SHOW_DEFAULT:
848 g_value_set_boolean (value, self->priv->show_default);
849 break;
850 case PROP_SHOW_RECOMMENDED:
851 g_value_set_boolean (value, self->priv->show_recommended);
852 break;
853 case PROP_SHOW_FALLBACK:
854 g_value_set_boolean (value, self->priv->show_fallback);
855 break;
856 case PROP_SHOW_OTHER:
857 g_value_set_boolean (value, self->priv->show_other);
858 break;
859 case PROP_SHOW_ALL:
860 g_value_set_boolean (value, self->priv->show_all);
861 break;
862 case PROP_DEFAULT_TEXT:
863 g_value_set_string (value, self->priv->default_text);
864 break;
865 default:
866 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
867 break;
868 }
869 }
870
871 static void
gtk_app_chooser_widget_constructed(GObject * object)872 gtk_app_chooser_widget_constructed (GObject *object)
873 {
874 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
875
876 if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL)
877 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object);
878
879 gtk_app_chooser_widget_initialize_items (self);
880 }
881
882 static void
gtk_app_chooser_widget_finalize(GObject * object)883 gtk_app_chooser_widget_finalize (GObject *object)
884 {
885 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
886
887 g_free (self->priv->content_type);
888 g_free (self->priv->default_text);
889 g_signal_handlers_disconnect_by_func (self->priv->monitor, app_info_changed, self);
890 g_object_unref (self->priv->monitor);
891
892 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
893 }
894
895 static void
gtk_app_chooser_widget_dispose(GObject * object)896 gtk_app_chooser_widget_dispose (GObject *object)
897 {
898 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
899
900 g_clear_object (&self->priv->selected_app_info);
901
902 G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
903 }
904
905 static void
gtk_app_chooser_widget_class_init(GtkAppChooserWidgetClass * klass)906 gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
907 {
908 GtkWidgetClass *widget_class;
909 GObjectClass *gobject_class;
910 GParamSpec *pspec;
911
912 gobject_class = G_OBJECT_CLASS (klass);
913 gobject_class->dispose = gtk_app_chooser_widget_dispose;
914 gobject_class->finalize = gtk_app_chooser_widget_finalize;
915 gobject_class->set_property = gtk_app_chooser_widget_set_property;
916 gobject_class->get_property = gtk_app_chooser_widget_get_property;
917 gobject_class->constructed = gtk_app_chooser_widget_constructed;
918
919 g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
920
921 /**
922 * GtkAppChooserWidget:show-default:
923 *
924 * The ::show-default property determines whether the app chooser
925 * should show the default handler for the content type in a
926 * separate section. If %FALSE, the default handler is listed
927 * among the recommended applications.
928 */
929 pspec = g_param_spec_boolean ("show-default",
930 P_("Show default app"),
931 P_("Whether the widget should show the default application"),
932 FALSE,
933 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
934 g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec);
935
936 /**
937 * GtkAppChooserWidget:show-recommended:
938 *
939 * The #GtkAppChooserWidget:show-recommended property determines
940 * whether the app chooser should show a section for recommended
941 * applications. If %FALSE, the recommended applications are listed
942 * among the other applications.
943 */
944 pspec = g_param_spec_boolean ("show-recommended",
945 P_("Show recommended apps"),
946 P_("Whether the widget should show recommended applications"),
947 TRUE,
948 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
949 g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec);
950
951 /**
952 * GtkAppChooserWidget:show-fallback:
953 *
954 * The #GtkAppChooserWidget:show-fallback property determines whether
955 * the app chooser should show a section for fallback applications.
956 * If %FALSE, the fallback applications are listed among the other
957 * applications.
958 */
959 pspec = g_param_spec_boolean ("show-fallback",
960 P_("Show fallback apps"),
961 P_("Whether the widget should show fallback applications"),
962 FALSE,
963 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
964 g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec);
965
966 /**
967 * GtkAppChooserWidget:show-other:
968 *
969 * The #GtkAppChooserWidget:show-other property determines whether
970 * the app chooser should show a section for other applications.
971 */
972 pspec = g_param_spec_boolean ("show-other",
973 P_("Show other apps"),
974 P_("Whether the widget should show other applications"),
975 FALSE,
976 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
977 g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec);
978
979 /**
980 * GtkAppChooserWidget:show-all:
981 *
982 * If the #GtkAppChooserWidget:show-all property is %TRUE, the app
983 * chooser presents all applications in a single list, without
984 * subsections for default, recommended or related applications.
985 */
986 pspec = g_param_spec_boolean ("show-all",
987 P_("Show all apps"),
988 P_("Whether the widget should show all applications"),
989 FALSE,
990 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
991 g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec);
992
993 /**
994 * GtkAppChooserWidget:default-text:
995 *
996 * The #GtkAppChooserWidget:default-text property determines the text
997 * that appears in the widget when there are no applications for the
998 * given content type.
999 * See also gtk_app_chooser_widget_set_default_text().
1000 */
1001 pspec = g_param_spec_string ("default-text",
1002 P_("Widget's default text"),
1003 P_("The default text appearing when there are no applications"),
1004 NULL,
1005 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
1006 g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec);
1007
1008 /**
1009 * GtkAppChooserWidget::application-selected:
1010 * @self: the object which received the signal
1011 * @application: the selected #GAppInfo
1012 *
1013 * Emitted when an application item is selected from the widget's list.
1014 */
1015 signals[SIGNAL_APPLICATION_SELECTED] =
1016 g_signal_new (I_("application-selected"),
1017 GTK_TYPE_APP_CHOOSER_WIDGET,
1018 G_SIGNAL_RUN_FIRST,
1019 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
1020 NULL, NULL,
1021 NULL,
1022 G_TYPE_NONE,
1023 1, G_TYPE_APP_INFO);
1024
1025 /**
1026 * GtkAppChooserWidget::application-activated:
1027 * @self: the object which received the signal
1028 * @application: the activated #GAppInfo
1029 *
1030 * Emitted when an application item is activated from the widget's list.
1031 *
1032 * This usually happens when the user double clicks an item, or an item
1033 * is selected and the user presses one of the keys Space, Shift+Space,
1034 * Return or Enter.
1035 */
1036 signals[SIGNAL_APPLICATION_ACTIVATED] =
1037 g_signal_new (I_("application-activated"),
1038 GTK_TYPE_APP_CHOOSER_WIDGET,
1039 G_SIGNAL_RUN_FIRST,
1040 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
1041 NULL, NULL,
1042 NULL,
1043 G_TYPE_NONE,
1044 1, G_TYPE_APP_INFO);
1045
1046 /**
1047 * GtkAppChooserWidget::populate-popup:
1048 * @self: the object which received the signal
1049 * @menu: the #GtkMenu to populate
1050 * @application: the current #GAppInfo
1051 *
1052 * Emitted when a context menu is about to popup over an application item.
1053 * Clients can insert menu items into the provided #GtkMenu object in the
1054 * callback of this signal; the context menu will be shown over the item
1055 * if at least one item has been added to the menu.
1056 */
1057 signals[SIGNAL_POPULATE_POPUP] =
1058 g_signal_new (I_("populate-popup"),
1059 GTK_TYPE_APP_CHOOSER_WIDGET,
1060 G_SIGNAL_RUN_FIRST,
1061 G_STRUCT_OFFSET (GtkAppChooserWidgetClass, populate_popup),
1062 NULL, NULL,
1063 _gtk_marshal_VOID__OBJECT_OBJECT,
1064 G_TYPE_NONE,
1065 2, GTK_TYPE_MENU, G_TYPE_APP_INFO);
1066
1067 /* Bind class to template
1068 */
1069 widget_class = GTK_WIDGET_CLASS (klass);
1070 gtk_widget_class_set_template_from_resource (widget_class,
1071 "/org/gtk/libgtk/ui/gtkappchooserwidget.ui");
1072 gtk_widget_class_bind_template_child_private (widget_class, GtkAppChooserWidget, program_list);
1073 gtk_widget_class_bind_template_child_private (widget_class, GtkAppChooserWidget, program_list_store);
1074 gtk_widget_class_bind_template_child_private (widget_class, GtkAppChooserWidget, column);
1075 gtk_widget_class_bind_template_child_private (widget_class, GtkAppChooserWidget, padding_renderer);
1076 gtk_widget_class_bind_template_child_private (widget_class, GtkAppChooserWidget, secondary_padding);
1077 gtk_widget_class_bind_template_child_private (widget_class, GtkAppChooserWidget, no_apps_label);
1078 gtk_widget_class_bind_template_child_private (widget_class, GtkAppChooserWidget, no_apps);
1079 gtk_widget_class_bind_template_callback (widget_class, refresh_and_emit_app_selected);
1080 gtk_widget_class_bind_template_callback (widget_class, program_list_selection_activated);
1081 gtk_widget_class_bind_template_callback (widget_class, widget_button_press_event_cb);
1082
1083 gtk_widget_class_set_css_name (widget_class, "appchooser");
1084 }
1085
1086 static void
gtk_app_chooser_widget_init(GtkAppChooserWidget * self)1087 gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
1088 {
1089 GtkTreeSelection *selection;
1090 GtkTreeModel *sort;
1091
1092 self->priv = gtk_app_chooser_widget_get_instance_private (self);
1093
1094 gtk_widget_init_template (GTK_WIDGET (self));
1095
1096 /* Various parts of the GtkTreeView code need custom code to setup, mostly
1097 * because we lack signals to connect to, or properties to set.
1098 */
1099 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->program_list));
1100 gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func,
1101 self, NULL);
1102
1103 sort = gtk_tree_view_get_model (GTK_TREE_VIEW (self->priv->program_list));
1104 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort),
1105 COLUMN_NAME,
1106 GTK_SORT_ASCENDING);
1107 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
1108 COLUMN_NAME,
1109 gtk_app_chooser_sort_func,
1110 self, NULL);
1111
1112 gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->priv->program_list), COLUMN_NAME);
1113 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->priv->program_list),
1114 gtk_app_chooser_search_equal_func,
1115 NULL, NULL);
1116
1117 gtk_tree_view_column_set_cell_data_func (self->priv->column,
1118 self->priv->secondary_padding,
1119 padding_cell_renderer_func,
1120 NULL, NULL);
1121
1122 self->priv->monitor = g_app_info_monitor_get ();
1123 g_signal_connect (self->priv->monitor, "changed",
1124 G_CALLBACK (app_info_changed), self);
1125 }
1126
1127 static GAppInfo *
gtk_app_chooser_widget_get_app_info(GtkAppChooser * object)1128 gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
1129 {
1130 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1131
1132 if (self->priv->selected_app_info == NULL)
1133 return NULL;
1134
1135 return g_object_ref (self->priv->selected_app_info);
1136 }
1137
1138 static void
gtk_app_chooser_widget_refresh(GtkAppChooser * object)1139 gtk_app_chooser_widget_refresh (GtkAppChooser *object)
1140 {
1141 GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
1142
1143 if (self->priv->program_list_store != NULL)
1144 {
1145 gtk_list_store_clear (self->priv->program_list_store);
1146
1147 /* don't add additional xpad if we don't have headings */
1148 g_object_set (self->priv->padding_renderer,
1149 "visible", !self->priv->show_all,
1150 NULL);
1151
1152 gtk_app_chooser_widget_real_add_items (self);
1153 }
1154 }
1155
1156 static void
gtk_app_chooser_widget_iface_init(GtkAppChooserIface * iface)1157 gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
1158 {
1159 iface->get_app_info = gtk_app_chooser_widget_get_app_info;
1160 iface->refresh = gtk_app_chooser_widget_refresh;
1161 }
1162
1163 /**
1164 * gtk_app_chooser_widget_new:
1165 * @content_type: the content type to show applications for
1166 *
1167 * Creates a new #GtkAppChooserWidget for applications
1168 * that can handle content of the given type.
1169 *
1170 * Returns: a newly created #GtkAppChooserWidget
1171 *
1172 * Since: 3.0
1173 */
1174 GtkWidget *
gtk_app_chooser_widget_new(const gchar * content_type)1175 gtk_app_chooser_widget_new (const gchar *content_type)
1176 {
1177 return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
1178 "content-type", content_type,
1179 NULL);
1180 }
1181
1182 /**
1183 * gtk_app_chooser_widget_set_show_default:
1184 * @self: a #GtkAppChooserWidget
1185 * @setting: the new value for #GtkAppChooserWidget:show-default
1186 *
1187 * Sets whether the app chooser should show the default handler
1188 * for the content type in a separate section.
1189 *
1190 * Since: 3.0
1191 */
1192 void
gtk_app_chooser_widget_set_show_default(GtkAppChooserWidget * self,gboolean setting)1193 gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
1194 gboolean setting)
1195 {
1196 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1197
1198 if (self->priv->show_default != setting)
1199 {
1200 self->priv->show_default = setting;
1201
1202 g_object_notify (G_OBJECT (self), "show-default");
1203
1204 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1205 }
1206 }
1207
1208 /**
1209 * gtk_app_chooser_widget_get_show_default:
1210 * @self: a #GtkAppChooserWidget
1211 *
1212 * Returns the current value of the #GtkAppChooserWidget:show-default
1213 * property.
1214 *
1215 * Returns: the value of #GtkAppChooserWidget:show-default
1216 *
1217 * Since: 3.0
1218 */
1219 gboolean
gtk_app_chooser_widget_get_show_default(GtkAppChooserWidget * self)1220 gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
1221 {
1222 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1223
1224 return self->priv->show_default;
1225 }
1226
1227 /**
1228 * gtk_app_chooser_widget_set_show_recommended:
1229 * @self: a #GtkAppChooserWidget
1230 * @setting: the new value for #GtkAppChooserWidget:show-recommended
1231 *
1232 * Sets whether the app chooser should show recommended applications
1233 * for the content type in a separate section.
1234 *
1235 * Since: 3.0
1236 */
1237 void
gtk_app_chooser_widget_set_show_recommended(GtkAppChooserWidget * self,gboolean setting)1238 gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
1239 gboolean setting)
1240 {
1241 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1242
1243 if (self->priv->show_recommended != setting)
1244 {
1245 self->priv->show_recommended = setting;
1246
1247 g_object_notify (G_OBJECT (self), "show-recommended");
1248
1249 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1250 }
1251 }
1252
1253 /**
1254 * gtk_app_chooser_widget_get_show_recommended:
1255 * @self: a #GtkAppChooserWidget
1256 *
1257 * Returns the current value of the #GtkAppChooserWidget:show-recommended
1258 * property.
1259 *
1260 * Returns: the value of #GtkAppChooserWidget:show-recommended
1261 *
1262 * Since: 3.0
1263 */
1264 gboolean
gtk_app_chooser_widget_get_show_recommended(GtkAppChooserWidget * self)1265 gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
1266 {
1267 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1268
1269 return self->priv->show_recommended;
1270 }
1271
1272 /**
1273 * gtk_app_chooser_widget_set_show_fallback:
1274 * @self: a #GtkAppChooserWidget
1275 * @setting: the new value for #GtkAppChooserWidget:show-fallback
1276 *
1277 * Sets whether the app chooser should show related applications
1278 * for the content type in a separate section.
1279 *
1280 * Since: 3.0
1281 */
1282 void
gtk_app_chooser_widget_set_show_fallback(GtkAppChooserWidget * self,gboolean setting)1283 gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
1284 gboolean setting)
1285 {
1286 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1287
1288 if (self->priv->show_fallback != setting)
1289 {
1290 self->priv->show_fallback = setting;
1291
1292 g_object_notify (G_OBJECT (self), "show-fallback");
1293
1294 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1295 }
1296 }
1297
1298 /**
1299 * gtk_app_chooser_widget_get_show_fallback:
1300 * @self: a #GtkAppChooserWidget
1301 *
1302 * Returns the current value of the #GtkAppChooserWidget:show-fallback
1303 * property.
1304 *
1305 * Returns: the value of #GtkAppChooserWidget:show-fallback
1306 *
1307 * Since: 3.0
1308 */
1309 gboolean
gtk_app_chooser_widget_get_show_fallback(GtkAppChooserWidget * self)1310 gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
1311 {
1312 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1313
1314 return self->priv->show_fallback;
1315 }
1316
1317 /**
1318 * gtk_app_chooser_widget_set_show_other:
1319 * @self: a #GtkAppChooserWidget
1320 * @setting: the new value for #GtkAppChooserWidget:show-other
1321 *
1322 * Sets whether the app chooser should show applications
1323 * which are unrelated to the content type.
1324 *
1325 * Since: 3.0
1326 */
1327 void
gtk_app_chooser_widget_set_show_other(GtkAppChooserWidget * self,gboolean setting)1328 gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
1329 gboolean setting)
1330 {
1331 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1332
1333 if (self->priv->show_other != setting)
1334 {
1335 self->priv->show_other = setting;
1336
1337 g_object_notify (G_OBJECT (self), "show-other");
1338
1339 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1340 }
1341 }
1342
1343 /**
1344 * gtk_app_chooser_widget_get_show_other:
1345 * @self: a #GtkAppChooserWidget
1346 *
1347 * Returns the current value of the #GtkAppChooserWidget:show-other
1348 * property.
1349 *
1350 * Returns: the value of #GtkAppChooserWidget:show-other
1351 *
1352 * Since: 3.0
1353 */
1354 gboolean
gtk_app_chooser_widget_get_show_other(GtkAppChooserWidget * self)1355 gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
1356 {
1357 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1358
1359 return self->priv->show_other;
1360 }
1361
1362 /**
1363 * gtk_app_chooser_widget_set_show_all:
1364 * @self: a #GtkAppChooserWidget
1365 * @setting: the new value for #GtkAppChooserWidget:show-all
1366 *
1367 * Sets whether the app chooser should show all applications
1368 * in a flat list.
1369 *
1370 * Since: 3.0
1371 */
1372 void
gtk_app_chooser_widget_set_show_all(GtkAppChooserWidget * self,gboolean setting)1373 gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
1374 gboolean setting)
1375 {
1376 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1377
1378 if (self->priv->show_all != setting)
1379 {
1380 self->priv->show_all = setting;
1381
1382 g_object_notify (G_OBJECT (self), "show-all");
1383
1384 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1385 }
1386 }
1387
1388 /**
1389 * gtk_app_chooser_widget_get_show_all:
1390 * @self: a #GtkAppChooserWidget
1391 *
1392 * Returns the current value of the #GtkAppChooserWidget:show-all
1393 * property.
1394 *
1395 * Returns: the value of #GtkAppChooserWidget:show-all
1396 *
1397 * Since: 3.0
1398 */
1399 gboolean
gtk_app_chooser_widget_get_show_all(GtkAppChooserWidget * self)1400 gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
1401 {
1402 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
1403
1404 return self->priv->show_all;
1405 }
1406
1407 /**
1408 * gtk_app_chooser_widget_set_default_text:
1409 * @self: a #GtkAppChooserWidget
1410 * @text: the new value for #GtkAppChooserWidget:default-text
1411 *
1412 * Sets the text that is shown if there are not applications
1413 * that can handle the content type.
1414 */
1415 void
gtk_app_chooser_widget_set_default_text(GtkAppChooserWidget * self,const gchar * text)1416 gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
1417 const gchar *text)
1418 {
1419 g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
1420
1421 if (g_strcmp0 (text, self->priv->default_text) != 0)
1422 {
1423 g_free (self->priv->default_text);
1424 self->priv->default_text = g_strdup (text);
1425
1426 g_object_notify (G_OBJECT (self), "default-text");
1427
1428 gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
1429 }
1430 }
1431
1432 /**
1433 * gtk_app_chooser_widget_get_default_text:
1434 * @self: a #GtkAppChooserWidget
1435 *
1436 * Returns the text that is shown if there are not applications
1437 * that can handle the content type.
1438 *
1439 * Returns: the value of #GtkAppChooserWidget:default-text
1440 *
1441 * Since: 3.0
1442 */
1443 const gchar *
gtk_app_chooser_widget_get_default_text(GtkAppChooserWidget * self)1444 gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
1445 {
1446 g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
1447
1448 return self->priv->default_text;
1449 }
1450
1451 void
_gtk_app_chooser_widget_set_search_entry(GtkAppChooserWidget * self,GtkEntry * entry)1452 _gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self,
1453 GtkEntry *entry)
1454 {
1455 gtk_tree_view_set_search_entry (GTK_TREE_VIEW (self->priv->program_list), entry);
1456
1457 g_object_bind_property (self->priv->no_apps, "visible",
1458 entry, "sensitive",
1459 G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
1460 }
1461