Deprecate the app chooser widgets
authorMatthias Clasen <mclasen@redhat.com>
Tue, 4 Oct 2022 01:54:57 +0000 (21:54 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 4 Oct 2022 03:02:09 +0000 (23:02 -0400)
These are a family of pretty specialized widgets, and
are very rarely used. Instead of porting them away
from GtkTreeView and GtkComboBox, deprecate them.

25 files changed:
demos/gtk-demo/pickers.c
gtk/deprecated/gtkappchooser.c [new file with mode: 0644]
gtk/deprecated/gtkappchooser.h [new file with mode: 0644]
gtk/deprecated/gtkappchooserbutton.c [new file with mode: 0644]
gtk/deprecated/gtkappchooserbutton.h [new file with mode: 0644]
gtk/deprecated/gtkappchooserdialog.c [new file with mode: 0644]
gtk/deprecated/gtkappchooserdialog.h [new file with mode: 0644]
gtk/deprecated/gtkappchooserprivate.h [new file with mode: 0644]
gtk/deprecated/gtkappchooserwidget.c [new file with mode: 0644]
gtk/deprecated/gtkappchooserwidget.h [new file with mode: 0644]
gtk/deprecated/meson.build
gtk/gtk.h
gtk/gtkappchooser.c [deleted file]
gtk/gtkappchooser.h [deleted file]
gtk/gtkappchooserbutton.c [deleted file]
gtk/gtkappchooserbutton.h [deleted file]
gtk/gtkappchooserdialog.c [deleted file]
gtk/gtkappchooserdialog.h [deleted file]
gtk/gtkappchooserprivate.h [deleted file]
gtk/gtkappchooserwidget.c [deleted file]
gtk/gtkappchooserwidget.h [deleted file]
gtk/meson.build
tests/testappchooser.c
tests/testappchooserbutton.c
testsuite/gtk/templates.c

index 05d831221f0786b6aa004496b84493c41e17c632..1ecd9a3adf30688c8c5f1b1679c3aa4f1a403bcc 100644 (file)
@@ -123,8 +123,14 @@ do_pickers (GtkWidget *do_widget)
     gtk_widget_set_halign (label, GTK_ALIGN_START);
     gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
     gtk_widget_set_hexpand (label, TRUE);
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
     picker = gtk_app_chooser_button_new ("x-scheme-handler/mailto");
     gtk_app_chooser_button_set_show_dialog_item (GTK_APP_CHOOSER_BUTTON (picker), TRUE);
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
     gtk_grid_attach (GTK_GRID (table), label, 0, 3, 1, 1);
     gtk_grid_attach (GTK_GRID (table), picker, 1, 3, 1, 1);
   }
diff --git a/gtk/deprecated/gtkappchooser.c b/gtk/deprecated/gtkappchooser.c
new file mode 100644 (file)
index 0000000..db2e9fe
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * gtkappchooser.c: app-chooser interface
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+/**
+ * GtkAppChooser:
+ *
+ * `GtkAppChooser` is an interface for widgets which allow the user to
+ * choose an application.
+ *
+ * The main objects that implement this interface are
+ * [class@Gtk.AppChooserWidget],
+ * [class@Gtk.AppChooserDialog] and [class@Gtk.AppChooserButton].
+ *
+ * Applications are represented by GIO `GAppInfo` objects here.
+ * GIO has a concept of recommended and fallback applications for a
+ * given content type. Recommended applications are those that claim
+ * to handle the content type itself, while fallback also includes
+ * applications that handle a more generic content type. GIO also
+ * knows the default and last-used application for a given content
+ * type. The `GtkAppChooserWidget` provides detailed control over
+ * whether the shown list of applications should include default,
+ * recommended or fallback applications.
+ *
+ * To obtain the application that has been selected in a `GtkAppChooser`,
+ * use [method@Gtk.AppChooser.get_app_info].
+ */
+
+#include "config.h"
+
+#include "gtkappchooser.h"
+
+#include "gtkappchooserprivate.h"
+#include "gtkwidget.h"
+
+#include <glib.h>
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+G_DEFINE_INTERFACE (GtkAppChooser, gtk_app_chooser, GTK_TYPE_WIDGET);
+
+static void
+gtk_app_chooser_default_init (GtkAppChooserIface *iface)
+{
+  GParamSpec *pspec;
+
+  /**
+   * GtkAppChooser:content-type: (attributes org.gtk.Property.get=gtk_app_chooser_get_content_type)
+   *
+   * The content type of the `GtkAppChooser` object.
+   *
+   * See `GContentType` for more information about content types.
+   */
+  pspec = g_param_spec_string ("content-type", NULL, NULL,
+                               NULL,
+                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+                               G_PARAM_STATIC_STRINGS);
+  g_object_interface_install_property (iface, pspec);
+}
+
+
+/**
+ * gtk_app_chooser_get_content_type: (attributes org.gtk.Method.get_property=content-type)
+ * @self: a `GtkAppChooser`
+ *
+ * Returns the content type for which the `GtkAppChooser`
+ * shows applications.
+ *
+ * Returns: the content type of @self. Free with g_free()
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+char *
+gtk_app_chooser_get_content_type (GtkAppChooser *self)
+{
+  char *retval = NULL;
+
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER (self), NULL);
+
+  g_object_get (self,
+                "content-type", &retval,
+                NULL);
+
+  return retval;
+}
+
+/**
+ * gtk_app_chooser_get_app_info:
+ * @self: a `GtkAppChooser`
+ *
+ * Returns the currently selected application.
+ *
+ * Returns: (nullable) (transfer full): a `GAppInfo` for the
+ *   currently selected application
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+GAppInfo *
+gtk_app_chooser_get_app_info (GtkAppChooser *self)
+{
+  return GTK_APP_CHOOSER_GET_IFACE (self)->get_app_info (self);
+}
+
+/**
+ * gtk_app_chooser_refresh:
+ * @self: a `GtkAppChooser`
+ *
+ * Reloads the list of applications.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_refresh (GtkAppChooser *self)
+{
+  GTK_APP_CHOOSER_GET_IFACE (self)->refresh (self);
+}
diff --git a/gtk/deprecated/gtkappchooser.h b/gtk/deprecated/gtkappchooser.h
new file mode 100644 (file)
index 0000000..4c928a0
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * gtkappchooser.h: app-chooser interface
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+#ifndef __GTK_APP_CHOOSER_H__
+#define __GTK_APP_CHOOSER_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_APP_CHOOSER    (gtk_app_chooser_get_type ())
+#define GTK_APP_CHOOSER(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER, GtkAppChooser))
+#define GTK_IS_APP_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER))
+
+typedef struct _GtkAppChooser GtkAppChooser;
+
+GDK_AVAILABLE_IN_ALL
+GType      gtk_app_chooser_get_type         (void) G_GNUC_CONST;
+
+GDK_DEPRECATED_IN_4_10
+GAppInfo * gtk_app_chooser_get_app_info     (GtkAppChooser *self);
+GDK_DEPRECATED_IN_4_10
+char *    gtk_app_chooser_get_content_type (GtkAppChooser *self);
+GDK_DEPRECATED_IN_4_10
+void       gtk_app_chooser_refresh          (GtkAppChooser *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooser, g_object_unref)
+
+G_END_DECLS
+
+#endif /* __GTK_APP_CHOOSER_H__ */
+
diff --git a/gtk/deprecated/gtkappchooserbutton.c b/gtk/deprecated/gtkappchooserbutton.c
new file mode 100644 (file)
index 0000000..6a5044f
--- /dev/null
@@ -0,0 +1,1158 @@
+/* gtkappchooserbutton.c: an app-chooser button
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+/**
+ * GtkAppChooserButton:
+ *
+ * The `GtkAppChooserButton` lets the user select an application.
+ *
+ * ![An example GtkAppChooserButton](appchooserbutton.png)
+ *
+ * Initially, a `GtkAppChooserButton` selects the first application
+ * in its list, which will either be the most-recently used application
+ * or, if [property@Gtk.AppChooserButton:show-default-item] is %TRUE, the
+ * default application.
+ *
+ * The list of applications shown in a `GtkAppChooserButton` includes
+ * the recommended applications for the given content type. When
+ * [property@Gtk.AppChooserButton:show-default-item] is set, the default
+ * application is also included. To let the user chooser other applications,
+ * you can set the [property@Gtk.AppChooserButton:show-dialog-item] property,
+ * which allows to open a full [class@Gtk.AppChooserDialog].
+ *
+ * It is possible to add custom items to the list, using
+ * [method@Gtk.AppChooserButton.append_custom_item]. These items cause
+ * the [signal@Gtk.AppChooserButton::custom-item-activated] signal to be
+ * emitted when they are selected.
+ *
+ * To track changes in the selected application, use the
+ * [signal@Gtk.AppChooserButton::changed] signal.
+ *
+ * # CSS nodes
+ *
+ * `GtkAppChooserButton` has a single CSS node with the name “appchooserbutton”.
+ */
+#include "config.h"
+
+#include "gtkappchooserbutton.h"
+
+#include "gtkappchooser.h"
+#include "gtkappchooserdialog.h"
+#include "gtkappchooserprivate.h"
+#include "gtkcelllayout.h"
+#include "gtkcellrendererpixbuf.h"
+#include "gtkcellrenderertext.h"
+#include "gtkcombobox.h"
+#include "gtkwidgetprivate.h"
+#include "gtkdialog.h"
+#include <glib/gi18n-lib.h>
+#include "gtkmarshalers.h"
+#include "gtkliststore.h"
+#include "gtkprivate.h"
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+enum {
+  PROP_SHOW_DIALOG_ITEM = 1,
+  PROP_SHOW_DEFAULT_ITEM,
+  PROP_HEADING,
+  PROP_MODAL,
+  NUM_PROPERTIES,
+
+  PROP_CONTENT_TYPE = NUM_PROPERTIES
+};
+
+enum {
+  SIGNAL_CHANGED,
+  SIGNAL_CUSTOM_ITEM_ACTIVATED,
+  ACTIVATE,
+  NUM_SIGNALS
+};
+
+enum {
+  COLUMN_APP_INFO,
+  COLUMN_NAME,
+  COLUMN_LABEL,
+  COLUMN_ICON,
+  COLUMN_CUSTOM,
+  COLUMN_SEPARATOR,
+  NUM_COLUMNS,
+};
+
+#define CUSTOM_ITEM_OTHER_APP "gtk-internal-item-other-app"
+
+static void app_chooser_iface_init  (GtkAppChooserIface *iface);
+
+static void real_insert_custom_item (GtkAppChooserButton *self,
+                                     const char          *name,
+                                     const char          *label,
+                                     GIcon               *icon,
+                                     gboolean             custom,
+                                     GtkTreeIter         *iter);
+
+static void real_insert_separator   (GtkAppChooserButton *self,
+                                     gboolean             custom,
+                                     GtkTreeIter         *iter);
+
+static guint signals[NUM_SIGNALS] = { 0, };
+static GParamSpec *properties[NUM_PROPERTIES];
+
+typedef struct _GtkAppChooserButtonClass   GtkAppChooserButtonClass;
+
+struct _GtkAppChooserButton {
+  GtkWidget parent_instance;
+
+  GtkWidget *combobox;
+  GtkListStore *store;
+
+  char *content_type;
+  char *heading;
+  int last_active;
+  gboolean show_dialog_item;
+  gboolean show_default_item;
+  gboolean modal;
+
+  GHashTable *custom_item_names;
+};
+
+struct _GtkAppChooserButtonClass {
+  GtkWidgetClass parent_class;
+
+  void (* changed)               (GtkAppChooserButton *self);
+  void (* custom_item_activated) (GtkAppChooserButton *self,
+                                  const char *item_name);
+  void (* activate)              (GtkAppChooserButton *self);
+};
+
+G_DEFINE_TYPE_WITH_CODE (GtkAppChooserButton, gtk_app_chooser_button, GTK_TYPE_WIDGET,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
+                                                app_chooser_iface_init));
+
+static gboolean
+row_separator_func (GtkTreeModel *model,
+                    GtkTreeIter  *iter,
+                    gpointer      user_data)
+{
+  gboolean separator;
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_SEPARATOR, &separator,
+                      -1);
+
+  return separator;
+}
+
+static void
+get_first_iter (GtkListStore *store,
+                GtkTreeIter  *iter)
+{
+  GtkTreeIter iter2;
+
+  if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), iter))
+    {
+      /* the model is empty, append */
+      gtk_list_store_append (store, iter);
+    }
+  else
+    {
+      gtk_list_store_insert_before (store, &iter2, iter);
+      *iter = iter2;
+    }
+}
+
+typedef struct {
+  GtkAppChooserButton *self;
+  GAppInfo *info;
+  int active_index;
+} SelectAppData;
+
+static void
+select_app_data_free (SelectAppData *data)
+{
+  g_clear_object (&data->self);
+  g_clear_object (&data->info);
+
+  g_slice_free (SelectAppData, data);
+}
+
+static gboolean
+select_application_func_cb (GtkTreeModel *model,
+                            GtkTreePath  *path,
+                            GtkTreeIter  *iter,
+                            gpointer      user_data)
+{
+  SelectAppData *data = user_data;
+  GtkAppChooserButton *self = data->self;
+  GAppInfo *app_to_match = data->info;
+  GAppInfo *app = NULL;
+  gboolean custom;
+  gboolean result;
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_APP_INFO, &app,
+                      COLUMN_CUSTOM, &custom,
+                      -1);
+
+  /* custom items are always after GAppInfos, so iterating further here
+   * is just useless.
+   */
+  if (custom)
+    result = TRUE;
+  else if (g_app_info_equal (app, app_to_match))
+    {
+      gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), iter);
+      result = TRUE;
+    }
+  else
+    result = FALSE;
+
+  g_object_unref (app);
+
+  return result;
+}
+
+static void
+gtk_app_chooser_button_select_application (GtkAppChooserButton *self,
+                                           GAppInfo            *info)
+{
+  SelectAppData *data;
+
+  data = g_slice_new0 (SelectAppData);
+  data->self = g_object_ref (self);
+  data->info = g_object_ref (info);
+
+  gtk_tree_model_foreach (GTK_TREE_MODEL (self->store),
+                          select_application_func_cb, data);
+
+  select_app_data_free (data);
+}
+
+static void
+other_application_dialog_response_cb (GtkDialog *dialog,
+                                      int        response_id,
+                                      gpointer   user_data)
+{
+  GtkAppChooserButton *self = user_data;
+  GAppInfo *info;
+
+  if (response_id != GTK_RESPONSE_OK)
+    {
+      /* reset the active item, otherwise we are stuck on
+       * 'Other application…'
+       */
+      gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), self->last_active);
+      gtk_window_destroy (GTK_WINDOW (dialog));
+      return;
+    }
+
+  info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog));
+
+  gtk_window_destroy (GTK_WINDOW (dialog));
+
+  /* refresh the combobox to get the new application */
+  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+  gtk_app_chooser_button_select_application (self, info);
+
+  g_object_unref (info);
+}
+
+static void
+other_application_item_activated_cb (GtkAppChooserButton *self)
+{
+  GtkWidget *dialog, *widget;
+  GtkRoot *root;
+
+  root = gtk_widget_get_root (GTK_WIDGET (self));
+  dialog = gtk_app_chooser_dialog_new_for_content_type (GTK_WINDOW (root),
+                                                        GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                        self->content_type);
+  gtk_window_set_modal (GTK_WINDOW (dialog), self->modal | gtk_window_get_modal (GTK_WINDOW (root)));
+  gtk_app_chooser_dialog_set_heading (GTK_APP_CHOOSER_DIALOG (dialog), self->heading);
+
+  widget = gtk_app_chooser_dialog_get_widget (GTK_APP_CHOOSER_DIALOG (dialog));
+  g_object_set (widget,
+                "show-fallback", TRUE,
+                "show-other", TRUE,
+                NULL);
+  gtk_widget_show (dialog);
+
+  g_signal_connect (dialog, "response",
+                    G_CALLBACK (other_application_dialog_response_cb), self);
+}
+
+static void
+gtk_app_chooser_button_ensure_dialog_item (GtkAppChooserButton *self,
+                                           GtkTreeIter         *prev_iter)
+{
+  GtkTreeIter iter, iter2;
+
+  if (!self->show_dialog_item || !self->content_type)
+    return;
+
+  if (prev_iter == NULL)
+    gtk_list_store_append (self->store, &iter);
+  else
+    gtk_list_store_insert_after (self->store, &iter, prev_iter);
+
+  real_insert_separator (self, FALSE, &iter);
+  iter2 = iter;
+
+  gtk_list_store_insert_after (self->store, &iter, &iter2);
+  real_insert_custom_item (self, CUSTOM_ITEM_OTHER_APP,
+                           _("Other application…"), NULL,
+                           FALSE, &iter);
+}
+
+static void
+insert_one_application (GtkAppChooserButton *self,
+                        GAppInfo            *app,
+                        GtkTreeIter         *iter)
+{
+  GIcon *icon;
+
+  icon = g_app_info_get_icon (app);
+
+  if (icon == NULL)
+    icon = g_themed_icon_new ("application-x-executable");
+  else
+    g_object_ref (icon);
+
+  gtk_list_store_set (self->store, iter,
+                      COLUMN_APP_INFO, app,
+                      COLUMN_LABEL, g_app_info_get_name (app),
+                      COLUMN_ICON, icon,
+                      COLUMN_CUSTOM, FALSE,
+                      -1);
+
+  g_object_unref (icon);
+}
+
+static void
+gtk_app_chooser_button_populate (GtkAppChooserButton *self)
+{
+  GList *recommended_apps = NULL, *l;
+  GAppInfo *app, *default_app = NULL;
+  GtkTreeIter iter, iter2;
+  gboolean cycled_recommended;
+
+#ifndef G_OS_WIN32
+  if (self->content_type)
+    recommended_apps = g_app_info_get_recommended_for_type (self->content_type);
+#endif
+  cycled_recommended = FALSE;
+
+  if (self->show_default_item)
+    {
+      if (self->content_type)
+        default_app = g_app_info_get_default_for_type (self->content_type, FALSE);
+
+      if (default_app != NULL)
+        {
+          get_first_iter (self->store, &iter);
+          cycled_recommended = TRUE;
+
+          insert_one_application (self, default_app, &iter);
+
+          g_object_unref (default_app);
+        }
+    }
+
+  for (l = recommended_apps; l != NULL; l = l->next)
+    {
+      app = l->data;
+
+      if (default_app != NULL && g_app_info_equal (app, default_app))
+        continue;
+
+      if (cycled_recommended)
+        {
+          gtk_list_store_insert_after (self->store, &iter2, &iter);
+          iter = iter2;
+        }
+      else
+        {
+          get_first_iter (self->store, &iter);
+          cycled_recommended = TRUE;
+        }
+
+      insert_one_application (self, app, &iter);
+    }
+
+  if (recommended_apps != NULL)
+    g_list_free_full (recommended_apps, g_object_unref);
+
+  if (!cycled_recommended)
+    gtk_app_chooser_button_ensure_dialog_item (self, NULL);
+  else
+    gtk_app_chooser_button_ensure_dialog_item (self, &iter);
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), 0);
+}
+
+static void
+gtk_app_chooser_button_build_ui (GtkAppChooserButton *self)
+{
+  GtkCellRenderer *cell;
+  GtkCellArea *area;
+
+  gtk_combo_box_set_model (GTK_COMBO_BOX (self->combobox),
+                           GTK_TREE_MODEL (self->store));
+
+  area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (self->combobox));
+
+  gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (self->combobox),
+                                        row_separator_func, NULL, NULL);
+
+  cell = gtk_cell_renderer_pixbuf_new ();
+  gtk_cell_area_add_with_properties (area, cell,
+                                     "align", FALSE,
+                                     "expand", FALSE,
+                                     "fixed-size", FALSE,
+                                     NULL);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell,
+                                  "gicon", COLUMN_ICON,
+                                  NULL);
+
+  cell = gtk_cell_renderer_text_new ();
+  gtk_cell_area_add_with_properties (area, cell,
+                                     "align", FALSE,
+                                     "expand", TRUE,
+                                     NULL);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell,
+                                  "text", COLUMN_LABEL,
+                                  NULL);
+
+  gtk_app_chooser_button_populate (self);
+}
+
+static void
+gtk_app_chooser_button_remove_non_custom (GtkAppChooserButton *self)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gboolean custom, res;
+
+  model = GTK_TREE_MODEL (self->store);
+
+  if (!gtk_tree_model_get_iter_first (model, &iter))
+    return;
+
+  do {
+    gtk_tree_model_get (model, &iter,
+                        COLUMN_CUSTOM, &custom,
+                        -1);
+    if (custom)
+      res = gtk_tree_model_iter_next (model, &iter);
+    else
+      res = gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+  } while (res);
+}
+
+static void
+gtk_app_chooser_button_changed (GtkComboBox *object,
+                                gpointer     user_data)
+{
+  GtkAppChooserButton *self = user_data;
+  GtkTreeIter iter;
+  char *name = NULL;
+  gboolean custom;
+  GQuark name_quark;
+
+  if (!gtk_combo_box_get_active_iter (object, &iter))
+    return;
+
+  gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
+                      COLUMN_NAME, &name,
+                      COLUMN_CUSTOM, &custom,
+                      -1);
+
+  if (name != NULL)
+    {
+      if (custom)
+        {
+          name_quark = g_quark_from_string (name);
+          g_signal_emit (self, signals[SIGNAL_CUSTOM_ITEM_ACTIVATED], name_quark, name);
+          self->last_active = gtk_combo_box_get_active (object);
+        }
+      else
+        {
+          /* trigger the dialog internally */
+          other_application_item_activated_cb (self);
+        }
+
+      g_free (name);
+    }
+  else
+    self->last_active = gtk_combo_box_get_active (object);
+
+  g_signal_emit (self, signals[SIGNAL_CHANGED], 0);
+}
+
+static void
+gtk_app_chooser_button_refresh (GtkAppChooser *object)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object);
+
+  gtk_app_chooser_button_remove_non_custom (self);
+  gtk_app_chooser_button_populate (self);
+}
+
+static GAppInfo *
+gtk_app_chooser_button_get_app_info (GtkAppChooser *object)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object);
+  GtkTreeIter iter;
+  GAppInfo *info;
+
+  if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->combobox), &iter))
+    return NULL;
+
+  gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
+                      COLUMN_APP_INFO, &info,
+                      -1);
+
+  return info;
+}
+
+static void
+gtk_app_chooser_button_constructed (GObject *obj)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
+
+  if (G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed (obj);
+
+  gtk_app_chooser_button_build_ui (self);
+}
+
+static void
+gtk_app_chooser_button_set_property (GObject      *obj,
+                                     guint         property_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
+
+  switch (property_id)
+    {
+    case PROP_CONTENT_TYPE:
+      self->content_type = g_value_dup_string (value);
+      break;
+    case PROP_SHOW_DIALOG_ITEM:
+      gtk_app_chooser_button_set_show_dialog_item (self, g_value_get_boolean (value));
+      break;
+    case PROP_SHOW_DEFAULT_ITEM:
+      gtk_app_chooser_button_set_show_default_item (self, g_value_get_boolean (value));
+      break;
+    case PROP_HEADING:
+      gtk_app_chooser_button_set_heading (self, g_value_get_string (value));
+      break;
+    case PROP_MODAL:
+      gtk_app_chooser_button_set_modal (self, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_app_chooser_button_get_property (GObject    *obj,
+                                     guint       property_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
+
+  switch (property_id)
+    {
+    case PROP_CONTENT_TYPE:
+      g_value_set_string (value, self->content_type);
+      break;
+    case PROP_SHOW_DIALOG_ITEM:
+      g_value_set_boolean (value, self->show_dialog_item);
+      break;
+    case PROP_SHOW_DEFAULT_ITEM:
+      g_value_set_boolean (value, self->show_default_item);
+      break;
+    case PROP_HEADING:
+      g_value_set_string (value, self->heading);
+      break;
+    case PROP_MODAL:
+      g_value_set_boolean (value, self->modal);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_app_chooser_button_finalize (GObject *obj)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
+
+  g_hash_table_destroy (self->custom_item_names);
+  g_free (self->content_type);
+  g_free (self->heading);
+  g_object_unref (self->store);
+  gtk_widget_unparent (self->combobox);
+
+  G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->finalize (obj);
+}
+
+static void
+gtk_app_chooser_button_measure (GtkWidget       *widget,
+                                GtkOrientation  orientation,
+                                int             for_size,
+                                int            *minimum,
+                                int            *natural,
+                                int            *minimum_baseline,
+                                int            *natural_baseline)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget);
+
+  gtk_widget_measure (self->combobox, orientation, for_size,
+                      minimum, natural,
+                      minimum_baseline, natural_baseline);
+}
+
+static void
+gtk_app_chooser_button_size_allocate (GtkWidget *widget,
+                                      int        width,
+                                      int        height,
+                                      int        baseline)
+{
+  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget);
+
+  gtk_widget_size_allocate (self->combobox, &(GtkAllocation){0, 0, width, height}, baseline);
+}
+
+static void
+app_chooser_iface_init (GtkAppChooserIface *iface)
+{
+  iface->get_app_info = gtk_app_chooser_button_get_app_info;
+  iface->refresh = gtk_app_chooser_button_refresh;
+}
+
+static void
+gtk_app_chooser_button_activate (GtkAppChooserButton *self)
+{
+  gtk_widget_activate (self->combobox);
+}
+
+static void
+gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass)
+{
+  GObjectClass *oclass = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  oclass->set_property = gtk_app_chooser_button_set_property;
+  oclass->get_property = gtk_app_chooser_button_get_property;
+  oclass->finalize = gtk_app_chooser_button_finalize;
+  oclass->constructed = gtk_app_chooser_button_constructed;
+
+  widget_class->measure = gtk_app_chooser_button_measure;
+  widget_class->size_allocate = gtk_app_chooser_button_size_allocate;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
+
+  klass->activate = gtk_app_chooser_button_activate;
+
+  g_object_class_override_property (oclass, PROP_CONTENT_TYPE, "content-type");
+
+  /**
+   * GtkAppChooserButton:show-dialog-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_dialog_item org.gtk.Property.set=gtk_app_chooser_button_set_show_dialog_item)
+   *
+   * Determines whether the dropdown menu shows an item to open
+   * a `GtkAppChooserDialog`.
+   */
+  properties[PROP_SHOW_DIALOG_ITEM] =
+    g_param_spec_boolean ("show-dialog-item", NULL, NULL,
+                          FALSE,
+                          G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkAppChooserButton:show-default-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_default_item org.gtk.Property.set=gtk_app_chooser_button_set_show_default_item)
+   *
+   * Determines whether the dropdown menu shows the default application
+   * on top for the provided content type.
+   */
+  properties[PROP_SHOW_DEFAULT_ITEM] =
+    g_param_spec_boolean ("show-default-item", NULL, NULL,
+                          FALSE,
+                          G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkAppChooserButton:heading: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_heading org.gtk.Property.set=gtk_app_chooser_button_set_heading)
+   *
+   * The text to show at the top of the dialog that can be
+   * opened from the button.
+   *
+   * The string may contain Pango markup.
+   */
+  properties[PROP_HEADING] =
+    g_param_spec_string ("heading", NULL, NULL,
+                         NULL,
+                         G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkAppChooserButton:modal: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_modal org.gtk.Property.set=gtk_app_chooser_button_set_modal)
+   *
+   * Whether the app chooser dialog should be modal.
+   */
+  properties[PROP_MODAL] =
+    g_param_spec_boolean ("modal", NULL, NULL,
+                          TRUE,
+                          G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
+
+  /**
+   * GtkAppChooserButton::changed:
+   * @self: the object which received the signal
+   *
+   * Emitted when the active application changes.
+   */
+  signals[SIGNAL_CHANGED] =
+    g_signal_new (I_("changed"),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkAppChooserButtonClass, changed),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE, 0);
+
+
+  /**
+   * GtkAppChooserButton::custom-item-activated:
+   * @self: the object which received the signal
+   * @item_name: the name of the activated item
+   *
+   * Emitted when a custom item is activated.
+   *
+   * Use [method@Gtk.AppChooserButton.append_custom_item],
+   * to add custom items.
+   */
+  signals[SIGNAL_CUSTOM_ITEM_ACTIVATED] =
+    g_signal_new (I_("custom-item-activated"),
+                  GTK_TYPE_APP_CHOOSER_BUTTON,
+                  G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+                  G_STRUCT_OFFSET (GtkAppChooserButtonClass, custom_item_activated),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  1, G_TYPE_STRING);
+
+  /**
+   * GtkAppChooserButton::activate:
+   * @widget: the object which received the signal.
+   *
+   * Emitted to when the button is activated.
+   *
+   * The `::activate` signal on `GtkAppChooserButton` is an action signal and
+   * emitting it causes the button to pop up its dialog.
+   *
+   * Since: 4.4
+   */
+  signals[ACTIVATE] =
+      g_signal_new (I_ ("activate"),
+                    G_OBJECT_CLASS_TYPE (oclass),
+                    G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+                    G_STRUCT_OFFSET (GtkAppChooserButtonClass, activate),
+                    NULL, NULL,
+                    NULL,
+                    G_TYPE_NONE, 0);
+
+  gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE]);
+
+
+  gtk_widget_class_set_css_name (widget_class, I_("appchooserbutton"));
+}
+
+static void
+gtk_app_chooser_button_init (GtkAppChooserButton *self)
+{
+  self->modal = TRUE;
+
+  self->custom_item_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  self->store = gtk_list_store_new (NUM_COLUMNS,
+                                    G_TYPE_APP_INFO,
+                                    G_TYPE_STRING, /* name */
+                                    G_TYPE_STRING, /* label */
+                                    G_TYPE_ICON,
+                                    G_TYPE_BOOLEAN, /* separator */
+                                    G_TYPE_BOOLEAN); /* custom */
+  self->combobox = gtk_combo_box_new_with_model (GTK_TREE_MODEL (self->store));
+  gtk_widget_set_parent (self->combobox, GTK_WIDGET (self));
+
+  g_signal_connect (self->combobox, "changed",
+                    G_CALLBACK (gtk_app_chooser_button_changed), self);
+}
+
+static gboolean
+app_chooser_button_iter_from_custom_name (GtkAppChooserButton *self,
+                                          const char          *name,
+                                          GtkTreeIter         *set_me)
+{
+  GtkTreeIter iter;
+  char *custom_name = NULL;
+
+  if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter))
+    return FALSE;
+
+  do {
+    gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
+                        COLUMN_NAME, &custom_name,
+                        -1);
+
+    if (g_strcmp0 (custom_name, name) == 0)
+      {
+        g_free (custom_name);
+        *set_me = iter;
+
+        return TRUE;
+      }
+
+    g_free (custom_name);
+  } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter));
+
+  return FALSE;
+}
+
+static void
+real_insert_custom_item (GtkAppChooserButton *self,
+                         const char          *name,
+                         const char          *label,
+                         GIcon               *icon,
+                         gboolean             custom,
+                         GtkTreeIter         *iter)
+{
+  if (custom)
+    {
+      if (g_hash_table_lookup (self->custom_item_names, name) != NULL)
+        {
+          g_warning ("Attempting to add custom item %s to GtkAppChooserButton, "
+                     "when there's already an item with the same name", name);
+          return;
+        }
+
+      g_hash_table_insert (self->custom_item_names,
+                           g_strdup (name), GINT_TO_POINTER (1));
+    }
+
+  gtk_list_store_set (self->store, iter,
+                      COLUMN_NAME, name,
+                      COLUMN_LABEL, label,
+                      COLUMN_ICON, icon,
+                      COLUMN_CUSTOM, custom,
+                      COLUMN_SEPARATOR, FALSE,
+                      -1);
+}
+
+static void
+real_insert_separator (GtkAppChooserButton *self,
+                       gboolean             custom,
+                       GtkTreeIter         *iter)
+{
+  gtk_list_store_set (self->store, iter,
+                      COLUMN_CUSTOM, custom,
+                      COLUMN_SEPARATOR, TRUE,
+                      -1);
+}
+
+/**
+ * gtk_app_chooser_button_new:
+ * @content_type: the content type to show applications for
+ *
+ * Creates a new `GtkAppChooserButton` for applications
+ * that can handle content of the given type.
+ *
+ * Returns: a newly created `GtkAppChooserButton`
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+GtkWidget *
+gtk_app_chooser_button_new (const char *content_type)
+{
+  g_return_val_if_fail (content_type != NULL, NULL);
+
+  return g_object_new (GTK_TYPE_APP_CHOOSER_BUTTON,
+                       "content-type", content_type,
+                       NULL);
+}
+
+/**
+ * gtk_app_chooser_button_append_separator:
+ * @self: a `GtkAppChooserButton`
+ *
+ * Appends a separator to the list of applications that is shown
+ * in the popup.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_button_append_separator (GtkAppChooserButton *self)
+{
+  GtkTreeIter iter;
+
+  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
+
+  gtk_list_store_append (self->store, &iter);
+  real_insert_separator (self, TRUE, &iter);
+}
+
+/**
+ * gtk_app_chooser_button_append_custom_item:
+ * @self: a `GtkAppChooserButton`
+ * @name: the name of the custom item
+ * @label: the label for the custom item
+ * @icon: the icon for the custom item
+ *
+ * Appends a custom item to the list of applications that is shown
+ * in the popup.
+ *
+ * The item name must be unique per-widget. Clients can use the
+ * provided name as a detail for the
+ * [signal@Gtk.AppChooserButton::custom-item-activated] signal, to add a
+ * callback for the activation of a particular custom item in the list.
+ *
+ * See also [method@Gtk.AppChooserButton.append_separator].
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self,
+                                           const char          *name,
+                                           const char          *label,
+                                           GIcon               *icon)
+{
+  GtkTreeIter iter;
+
+  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
+  g_return_if_fail (name != NULL);
+
+  gtk_list_store_append (self->store, &iter);
+  real_insert_custom_item (self, name, label, icon, TRUE, &iter);
+}
+
+/**
+ * gtk_app_chooser_button_set_active_custom_item:
+ * @self: a `GtkAppChooserButton`
+ * @name: the name of the custom item
+ *
+ * Selects a custom item.
+ *
+ * See [method@Gtk.AppChooserButton.append_custom_item].
+ *
+ * Use [method@Gtk.AppChooser.refresh] to bring the selection
+ * to its initial state.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self,
+                                               const char          *name)
+{
+  GtkTreeIter iter;
+
+  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
+  g_return_if_fail (name != NULL);
+
+  if (!g_hash_table_contains (self->custom_item_names, name) ||
+      !app_chooser_button_iter_from_custom_name (self, name, &iter))
+    {
+      g_warning ("Can't find the item named %s in the app chooser.", name);
+      return;
+    }
+
+  gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), &iter);
+}
+
+/**
+ * gtk_app_chooser_button_get_show_dialog_item: (attributes org.gtk.Method.get_property=show-dialog-item)
+ * @self: a `GtkAppChooserButton`
+ *
+ * Returns whether the dropdown menu shows an item
+ * for a `GtkAppChooserDialog`.
+ *
+ * Returns: the value of [property@Gtk.AppChooserButton:show-dialog-item]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_button_get_show_dialog_item (GtkAppChooserButton *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE);
+
+  return self->show_dialog_item;
+}
+
+/**
+ * gtk_app_chooser_button_set_show_dialog_item: (attributes org.gtk.Method.set_property=show-dialog-item)
+ * @self: a `GtkAppChooserButton`
+ * @setting: the new value for [property@Gtk.AppChooserButton:show-dialog-item]
+ *
+ * Sets whether the dropdown menu of this button should show an
+ * entry to trigger a `GtkAppChooserDialog`.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self,
+                                             gboolean             setting)
+{
+  if (self->show_dialog_item != setting)
+    {
+      self->show_dialog_item = setting;
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DIALOG_ITEM]);
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_button_get_show_default_item: (attributes org.gtk.Method.get_property=show-default-item)
+ * @self: a `GtkAppChooserButton`
+ *
+ * Returns whether the dropdown menu should show the default
+ * application at the top.
+ *
+ * Returns: the value of [property@Gtk.AppChooserButton:show-default-item]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE);
+
+  return self->show_default_item;
+}
+
+/**
+ * gtk_app_chooser_button_set_show_default_item: (attributes org.gtk.Method.set_property=show-default-item)
+ * @self: a `GtkAppChooserButton`
+ * @setting: the new value for [property@Gtk.AppChooserButton:show-default-item]
+ *
+ * Sets whether the dropdown menu of this button should show the
+ * default application for the given content type at top.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self,
+                                              gboolean             setting)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
+
+  if (self->show_default_item != setting)
+    {
+      self->show_default_item = setting;
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DEFAULT_ITEM]);
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_button_set_heading: (attributes org.gtk.Method.set_property=heading)
+ * @self: a `GtkAppChooserButton`
+ * @heading: a string containing Pango markup
+ *
+ * Sets the text to display at the top of the dialog.
+ *
+ * If the heading is not set, the dialog displays a default text.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_button_set_heading (GtkAppChooserButton *self,
+                                    const char          *heading)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
+
+  g_free (self->heading);
+  self->heading = g_strdup (heading);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADING]);
+}
+
+/**
+ * gtk_app_chooser_button_get_heading: (attributes org.gtk.Method.get_property=heading)
+ * @self: a `GtkAppChooserButton`
+ *
+ * Returns the text to display at the top of the dialog.
+ *
+ * Returns: (nullable): the text to display at the top of the dialog,
+ *   or %NULL, in which case a default text is displayed
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+const char *
+gtk_app_chooser_button_get_heading (GtkAppChooserButton *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), NULL);
+
+  return self->heading;
+}
+
+/**
+ * gtk_app_chooser_button_set_modal: (attributes org.gtk.Method.set_property=modal)
+ * @self: a `GtkAppChooserButton`
+ * @modal: %TRUE to make the dialog modal
+ *
+ * Sets whether the dialog should be modal.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_button_set_modal (GtkAppChooserButton *self,
+                                  gboolean             modal)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
+
+  if (self->modal == modal)
+    return;
+
+  self->modal = modal;
+
+  g_object_notify (G_OBJECT (self), "modal");
+}
+
+/**
+ * gtk_app_chooser_button_get_modal: (attributes org.gtk.Method.get_property=modal)
+ * @self: a `GtkAppChooserButton`
+ *
+ * Gets whether the dialog is modal.
+ *
+ * Returns: %TRUE if the dialog is modal
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_button_get_modal (GtkAppChooserButton *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE);
+
+  return self->modal;
+}
+
diff --git a/gtk/deprecated/gtkappchooserbutton.h b/gtk/deprecated/gtkappchooserbutton.h
new file mode 100644 (file)
index 0000000..6f3a739
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * gtkappchooserbutton.h: an app-chooser button
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+#ifndef __GTK_APP_CHOOSER_BUTTON_H__
+#define __GTK_APP_CHOOSER_BUTTON_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkwidget.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_APP_CHOOSER_BUTTON            (gtk_app_chooser_button_get_type ())
+#define GTK_APP_CHOOSER_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_BUTTON, GtkAppChooserButton))
+#define GTK_IS_APP_CHOOSER_BUTTON(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_BUTTON))
+
+typedef struct _GtkAppChooserButton        GtkAppChooserButton;
+
+GDK_AVAILABLE_IN_ALL
+GType       gtk_app_chooser_button_get_type           (void) G_GNUC_CONST;
+
+GDK_DEPRECATED_IN_4_10
+GtkWidget * gtk_app_chooser_button_new                (const char          *content_type);
+
+GDK_DEPRECATED_IN_4_10
+void        gtk_app_chooser_button_append_separator   (GtkAppChooserButton *self);
+GDK_DEPRECATED_IN_4_10
+void        gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self,
+                                                       const char          *name,
+                                                       const char          *label,
+                                                       GIcon               *icon);
+GDK_DEPRECATED_IN_4_10
+void     gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self,
+                                                        const char          *name);
+
+GDK_DEPRECATED_IN_4_10
+void     gtk_app_chooser_button_set_show_dialog_item  (GtkAppChooserButton *self,
+                                                       gboolean             setting);
+GDK_DEPRECATED_IN_4_10
+gboolean gtk_app_chooser_button_get_show_dialog_item  (GtkAppChooserButton *self);
+GDK_DEPRECATED_IN_4_10
+void     gtk_app_chooser_button_set_heading           (GtkAppChooserButton *self,
+                                                       const char          *heading);
+GDK_DEPRECATED_IN_4_10
+const char *
+         gtk_app_chooser_button_get_heading           (GtkAppChooserButton *self);
+GDK_DEPRECATED_IN_4_10
+void     gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self,
+                                                       gboolean             setting);
+GDK_DEPRECATED_IN_4_10
+gboolean gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self);
+
+GDK_DEPRECATED_IN_4_10
+gboolean gtk_app_chooser_button_get_modal             (GtkAppChooserButton *self);
+GDK_DEPRECATED_IN_4_10
+void     gtk_app_chooser_button_set_modal             (GtkAppChooserButton *self,
+                                                       gboolean             modal);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserButton, g_object_unref)
+
+G_END_DECLS
+
+#endif /* __GTK_APP_CHOOSER_BUTTON_H__ */
diff --git a/gtk/deprecated/gtkappchooserdialog.c b/gtk/deprecated/gtkappchooserdialog.c
new file mode 100644 (file)
index 0000000..96c7ed6
--- /dev/null
@@ -0,0 +1,799 @@
+/*
+ * gtkappchooserdialog.c: an app-chooser dialog
+ *
+ * Copyright (C) 2004 Novell, Inc.
+ * Copyright (C) 2007, 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Dave Camp <dave@novell.com>
+ *          Alexander Larsson <alexl@redhat.com>
+ *          Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+/**
+ * GtkAppChooserDialog:
+ *
+ * `GtkAppChooserDialog` shows a `GtkAppChooserWidget` inside a `GtkDialog`.
+ *
+ * ![An example GtkAppChooserDialog](appchooserdialog.png)
+ *
+ * Note that `GtkAppChooserDialog` does not have any interesting methods
+ * of its own. Instead, you should get the embedded `GtkAppChooserWidget`
+ * using [method@Gtk.AppChooserDialog.get_widget] and call its methods if
+ * the generic [iface@Gtk.AppChooser] interface is not sufficient for
+ * your needs.
+ *
+ * To set the heading that is shown above the `GtkAppChooserWidget`,
+ * use [method@Gtk.AppChooserDialog.set_heading].
+ */
+#include "config.h"
+
+#include "gtkappchooserdialog.h"
+
+#include "gtkappchooser.h"
+#include "gtkappchooserprivate.h"
+
+#include "gtkmessagedialog.h"
+#include "gtksettings.h"
+#include "gtklabel.h"
+#include "gtkbox.h"
+#include "gtkbutton.h"
+#include "gtkentry.h"
+#include "gtktogglebutton.h"
+#include "gtkheaderbar.h"
+#include "gtkdialogprivate.h"
+#include "gtksearchbar.h"
+#include "gtksizegroup.h"
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+typedef struct _GtkAppChooserDialogClass   GtkAppChooserDialogClass;
+
+struct _GtkAppChooserDialog {
+  GtkDialog parent;
+
+  char *content_type;
+  GFile *gfile;
+  char *heading;
+
+  GtkWidget *label;
+  GtkWidget *inner_box;
+
+  GtkWidget *open_label;
+
+  GtkWidget *search_bar;
+  GtkWidget *search_entry;
+  GtkWidget *app_chooser_widget;
+  GtkWidget *show_more_button;
+  GtkWidget *software_button;
+
+  GtkSizeGroup *buttons;
+
+  gboolean show_more_clicked;
+  gboolean dismissed;
+};
+
+struct _GtkAppChooserDialogClass {
+  GtkDialogClass parent_class;
+};
+
+enum {
+  PROP_GFILE = 1,
+  PROP_CONTENT_TYPE,
+  PROP_HEADING
+};
+
+static void gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface);
+G_DEFINE_TYPE_WITH_CODE (GtkAppChooserDialog, gtk_app_chooser_dialog, GTK_TYPE_DIALOG,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
+                                                gtk_app_chooser_dialog_iface_init));
+
+
+static void
+add_or_find_application (GtkAppChooserDialog *self)
+{
+  GAppInfo *app;
+
+  app = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self));
+
+  if (app)
+    {
+      /* we don't care about reporting errors here */
+      if (self->content_type)
+        g_app_info_set_as_last_used_for_type (app,
+                                              self->content_type,
+                                              NULL);
+      g_object_unref (app);
+    }
+}
+
+static void
+gtk_app_chooser_dialog_response (GtkDialog *dialog,
+                                 int        response_id,
+                                 gpointer   user_data)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (dialog);
+
+  switch (response_id)
+    {
+    case GTK_RESPONSE_OK:
+      add_or_find_application (self);
+      break;
+    case GTK_RESPONSE_CANCEL:
+    case GTK_RESPONSE_DELETE_EVENT:
+      self->dismissed = TRUE;
+      break;
+    default:
+      break;
+    }
+}
+
+static void
+widget_application_selected_cb (GtkAppChooserWidget *widget,
+                                GAppInfo            *app_info,
+                                gpointer             user_data)
+{
+  gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, TRUE);
+}
+
+static void
+widget_application_activated_cb (GtkAppChooserWidget *widget,
+                                 GAppInfo            *app_info,
+                                 gpointer             user_data)
+{
+  gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
+}
+
+static char *
+get_extension (const char *basename)
+{
+  char *p;
+
+  p = strrchr (basename, '.');
+
+  if (p && *(p + 1) != '\0')
+    return g_strdup (p + 1);
+
+  return NULL;
+}
+
+static void
+set_dialog_properties (GtkAppChooserDialog *self)
+{
+  char *name;
+  char *extension;
+  char *description;
+  char *string;
+  gboolean unknown;
+  char *title;
+  char *subtitle;
+  gboolean use_header;
+  GtkWidget *header;
+
+  name = NULL;
+  extension = NULL;
+  description = NULL;
+  unknown = TRUE;
+
+  if (self->gfile != NULL)
+    {
+      name = g_file_get_basename (self->gfile);
+      extension = get_extension (name);
+    }
+
+  if (self->content_type)
+    {
+      description = g_content_type_get_description (self->content_type);
+      unknown = g_content_type_is_unknown (self->content_type);
+    }
+
+  title = g_strdup (_("Select Application"));
+  subtitle = NULL;
+  string = NULL;
+
+  if (name != NULL)
+    {
+      /* Translators: %s is a filename */
+      subtitle = g_strdup_printf (_("Opening “%s”."), name);
+      string = g_strdup_printf (_("No applications found for “%s”"), name);
+    }
+  else if (self->content_type)
+    {
+      /* Translators: %s is a file type description */
+      subtitle = g_strdup_printf (_("Opening “%s” files."), 
+                                  unknown ? self->content_type : description);
+      string = g_strdup_printf (_("No applications found for “%s” files"),
+                                unknown ? self->content_type : description);
+    }
+
+  g_object_get (self, "use-header-bar", &use_header, NULL); 
+  if (use_header)
+    {
+      GtkWidget *box, *label;
+
+      header = gtk_dialog_get_header_bar (GTK_DIALOG (self));
+
+      box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+      gtk_widget_set_valign (box, GTK_ALIGN_CENTER);
+
+      label = gtk_label_new (title);
+      gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
+      gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
+      gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+      gtk_label_set_width_chars (GTK_LABEL (label), 5);
+      gtk_widget_add_css_class (label, "title");
+      gtk_widget_set_parent (label, box);
+
+      if (subtitle)
+        {
+          label = gtk_label_new (subtitle);
+          gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
+          gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
+          gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+          gtk_widget_add_css_class (label, "subtitle");
+          gtk_widget_set_parent (label, box);
+        }
+
+      gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header), box);
+    }
+  else
+    {
+      gtk_window_set_title (GTK_WINDOW (self), _("Select Application"));
+    }
+
+  if (self->heading != NULL)
+    {
+      gtk_label_set_markup (GTK_LABEL (self->label), self->heading);
+      gtk_widget_show (self->label);
+    }
+  else
+    {
+      gtk_widget_hide (self->label);
+    }
+
+  gtk_app_chooser_widget_set_default_text (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget),
+                                           string);
+
+  g_free (title);
+  g_free (subtitle);
+  g_free (name);
+  g_free (extension);
+  g_free (description);
+  g_free (string);
+}
+
+static void
+show_more_button_clicked_cb (GtkButton *button,
+                             gpointer   user_data)
+{
+  GtkAppChooserDialog *self = user_data;
+
+  g_object_set (self->app_chooser_widget,
+                "show-recommended", TRUE,
+                "show-fallback", TRUE,
+                "show-other", TRUE,
+                NULL);
+
+  gtk_widget_hide (self->show_more_button);
+  self->show_more_clicked = TRUE;
+}
+
+static void
+widget_notify_for_button_cb (GObject    *source,
+                             GParamSpec *pspec,
+                             gpointer    user_data)
+{
+  GtkAppChooserDialog *self = user_data;
+  GtkAppChooserWidget *widget = GTK_APP_CHOOSER_WIDGET (source);
+  gboolean should_hide;
+
+  should_hide = gtk_app_chooser_widget_get_show_other (widget) ||
+    self->show_more_clicked;
+
+  if (should_hide)
+    gtk_widget_hide (self->show_more_button);
+}
+
+static void
+construct_appchooser_widget (GtkAppChooserDialog *self)
+{
+  GAppInfo *info;
+
+  /* Need to build the appchooser widget after, because of the content-type construct-only property */
+  self->app_chooser_widget = gtk_app_chooser_widget_new (self->content_type);
+  gtk_widget_set_vexpand (self->app_chooser_widget, TRUE);
+  gtk_box_append (GTK_BOX (self->inner_box), self->app_chooser_widget);
+
+  g_signal_connect (self->app_chooser_widget, "application-selected",
+                    G_CALLBACK (widget_application_selected_cb), self);
+  g_signal_connect (self->app_chooser_widget, "application-activated",
+                    G_CALLBACK (widget_application_activated_cb), self);
+  g_signal_connect (self->app_chooser_widget, "notify::show-other",
+                    G_CALLBACK (widget_notify_for_button_cb), self);
+
+  /* Add the custom button to the new appchooser */
+  gtk_box_append (GTK_BOX (self->inner_box),
+                     self->show_more_button);
+
+  gtk_box_append (GTK_BOX (self->inner_box),
+                     self->software_button);
+
+  info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget));
+  gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK, info != NULL);
+  if (info)
+    g_object_unref (info);
+
+  _gtk_app_chooser_widget_set_search_entry (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget),
+                                            GTK_EDITABLE (self->search_entry));
+
+  gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (self->search_bar),
+                                         GTK_WIDGET (self));
+}
+
+static void
+set_gfile_and_content_type (GtkAppChooserDialog *self,
+                            GFile               *file)
+{
+  GFileInfo *info;
+
+  if (file == NULL)
+    return;
+
+  self->gfile = g_object_ref (file);
+
+  info = g_file_query_info (self->gfile,
+                            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                            0, NULL, NULL);
+  self->content_type = g_strdup (g_file_info_get_content_type (info));
+
+  g_object_unref (info);
+}
+
+static GAppInfo *
+gtk_app_chooser_dialog_get_app_info (GtkAppChooser *object)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
+
+  return gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget));
+}
+
+static void
+gtk_app_chooser_dialog_refresh (GtkAppChooser *object)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
+
+  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self->app_chooser_widget));
+}
+
+static void
+show_error_dialog (const char *primary,
+                   const char *secondary,
+                   GtkWindow   *parent)
+{
+  GtkWidget *message_dialog;
+
+  message_dialog = gtk_message_dialog_new (parent, 0,
+                                           GTK_MESSAGE_ERROR,
+                                           GTK_BUTTONS_OK,
+                                           NULL);
+  g_object_set (message_dialog,
+                "text", primary,
+                "secondary-text", secondary,
+                NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (message_dialog), GTK_RESPONSE_OK);
+
+  gtk_widget_show (message_dialog);
+
+  g_signal_connect (message_dialog, "response",
+                    G_CALLBACK (gtk_window_destroy), NULL);
+}
+
+static void
+software_button_clicked_cb (GtkButton           *button,
+                            GtkAppChooserDialog *self)
+{
+  GSubprocess *process;
+  GError *error = NULL;
+  char *option;
+
+  if (self->content_type)
+    option = g_strconcat ("--search=", self->content_type, NULL);
+  else
+    option = g_strdup ("--mode=overview");
+
+  process = g_subprocess_new (0, &error, "gnome-software", option, NULL);
+  if (!process)
+    {
+      show_error_dialog (_("Failed to start GNOME Software"),
+                         error->message, GTK_WINDOW (self));
+      g_error_free (error);
+    }
+  else
+    g_object_unref (process);
+
+  g_free (option);
+}
+
+static void
+ensure_software_button (GtkAppChooserDialog *self)
+{
+  char *path;
+
+  path = g_find_program_in_path ("gnome-software");
+  if (path != NULL)
+    gtk_widget_show (self->software_button);
+  else
+    gtk_widget_hide (self->software_button);
+
+  g_free (path);
+}
+
+static void
+setup_search (GtkAppChooserDialog *self)
+{
+  gboolean use_header;
+
+  g_object_get (self, "use-header-bar", &use_header, NULL);
+  if (use_header)
+    {
+      GtkWidget *button;
+      GtkWidget *image;
+      GtkWidget *header;
+
+      button = gtk_toggle_button_new ();
+      gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
+      image = gtk_image_new_from_icon_name ("edit-find-symbolic");
+      gtk_button_set_child (GTK_BUTTON (button), image);
+      gtk_widget_add_css_class (button, "image-button");
+      gtk_widget_remove_css_class (button, "text-button");
+
+      header = gtk_dialog_get_header_bar (GTK_DIALOG (self));
+      gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
+      gtk_size_group_add_widget (self->buttons, button);
+
+      g_object_bind_property (button, "active",
+                              self->search_bar, "search-mode-enabled",
+                              G_BINDING_BIDIRECTIONAL);
+      g_object_bind_property (self->search_entry, "sensitive",
+                              button, "sensitive",
+                              G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+    }
+}
+
+static void
+gtk_app_chooser_dialog_constructed (GObject *object)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
+
+  if (G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed (object);
+
+  construct_appchooser_widget (self);
+  set_dialog_properties (self);
+  ensure_software_button (self);
+  setup_search (self);
+}
+
+static void
+gtk_app_chooser_dialog_dispose (GObject *object)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
+  
+  g_clear_object (&self->gfile);
+
+  self->dismissed = TRUE;
+
+  G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->dispose (object);
+}
+
+static void
+gtk_app_chooser_dialog_finalize (GObject *object)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
+
+  g_free (self->content_type);
+  g_free (self->heading);
+
+  G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtk_app_chooser_dialog_set_property (GObject      *object,
+                                     guint         property_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
+
+  switch (property_id)
+    {
+    case PROP_GFILE:
+      set_gfile_and_content_type (self, g_value_get_object (value));
+      break;
+    case PROP_CONTENT_TYPE:
+      /* don't try to override a value previously set with the GFile */
+      if (self->content_type == NULL)
+        self->content_type = g_value_dup_string (value);
+      break;
+    case PROP_HEADING:
+      gtk_app_chooser_dialog_set_heading (self, g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_app_chooser_dialog_get_property (GObject    *object,
+                                     guint       property_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
+
+  switch (property_id)
+    {
+    case PROP_GFILE:
+      if (self->gfile != NULL)
+        g_value_set_object (value, self->gfile);
+      break;
+    case PROP_CONTENT_TYPE:
+      g_value_set_string (value, self->content_type);
+      break;
+    case PROP_HEADING:
+      g_value_set_string (value, self->heading);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface)
+{
+  iface->get_app_info = gtk_app_chooser_dialog_get_app_info;
+  iface->refresh = gtk_app_chooser_dialog_refresh;
+}
+
+static void
+gtk_app_chooser_dialog_class_init (GtkAppChooserDialogClass *klass)
+{
+  GObjectClass *gobject_class;
+  GtkWidgetClass *widget_class;
+  GParamSpec *pspec;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  widget_class = GTK_WIDGET_CLASS (klass);
+
+  gobject_class->dispose = gtk_app_chooser_dialog_dispose;
+  gobject_class->finalize = gtk_app_chooser_dialog_finalize;
+  gobject_class->set_property = gtk_app_chooser_dialog_set_property;
+  gobject_class->get_property = gtk_app_chooser_dialog_get_property;
+  gobject_class->constructed = gtk_app_chooser_dialog_constructed;
+
+  g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
+
+  /**
+   * GtkAppChooserDialog:gfile:
+   *
+   * The GFile used by the `GtkAppChooserDialog`.
+   *
+   * The dialog's `GtkAppChooserWidget` content type will
+   * be guessed from the file, if present.
+   */
+  pspec = g_param_spec_object ("gfile", NULL, NULL,
+                               G_TYPE_FILE,
+                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+                               G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (gobject_class, PROP_GFILE, pspec);
+
+  /**
+   * GtkAppChooserDialog:heading: (attributes org.gtk.Property.get=gtk_app_chooser_dialog_get_heading org.gtk.Property.set=gtk_app_chooser_dialog_set_heading)
+   *
+   * The text to show at the top of the dialog.
+   *
+   * The string may contain Pango markup.
+   */
+  pspec = g_param_spec_string ("heading", NULL, NULL,
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+                               G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_property (gobject_class, PROP_HEADING, pspec);
+
+  /* Bind class to template
+   */
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                              "/org/gtk/libgtk/ui/gtkappchooserdialog.ui");
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, label);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, show_more_button);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, software_button);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, inner_box);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_bar);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_entry);
+  gtk_widget_class_bind_template_child(widget_class, GtkAppChooserDialog, buttons);
+  gtk_widget_class_bind_template_callback (widget_class, show_more_button_clicked_cb);
+  gtk_widget_class_bind_template_callback (widget_class, software_button_clicked_cb);
+}
+
+static void
+gtk_app_chooser_dialog_init (GtkAppChooserDialog *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+  gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (self));
+
+  /* we can't override the class signal handler here, as it's a RUN_LAST;
+   * we want our signal handler instead to be executed before any user code.
+   */
+  g_signal_connect (self, "response",
+                    G_CALLBACK (gtk_app_chooser_dialog_response), NULL);
+}
+
+static void
+set_parent_and_flags (GtkWidget      *dialog,
+                      GtkWindow      *parent,
+                      GtkDialogFlags  flags)
+{
+  if (parent != NULL)
+    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+
+  if (flags & GTK_DIALOG_MODAL)
+    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+  if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
+    gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+}
+
+/**
+ * gtk_app_chooser_dialog_new:
+ * @parent: (nullable): a `GtkWindow`
+ * @flags: flags for this dialog
+ * @file: a `GFile`
+ *
+ * Creates a new `GtkAppChooserDialog` for the provided `GFile`.
+ *
+ * The dialog will show applications that can open the file.
+ *
+ * Returns: a newly created `GtkAppChooserDialog`
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+GtkWidget *
+gtk_app_chooser_dialog_new (GtkWindow      *parent,
+                            GtkDialogFlags  flags,
+                            GFile          *file)
+{
+  GtkWidget *retval;
+
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG,
+                         "gfile", file,
+                         NULL);
+
+  set_parent_and_flags (retval, parent, flags);
+
+  return retval;
+}
+
+/**
+ * gtk_app_chooser_dialog_new_for_content_type:
+ * @parent: (nullable): a `GtkWindow`
+ * @flags: flags for this dialog
+ * @content_type: a content type string
+ *
+ * Creates a new `GtkAppChooserDialog` for the provided content type.
+ *
+ * The dialog will show applications that can open the content type.
+ *
+ * Returns: a newly created `GtkAppChooserDialog`
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+GtkWidget *
+gtk_app_chooser_dialog_new_for_content_type (GtkWindow      *parent,
+                                             GtkDialogFlags  flags,
+                                             const char     *content_type)
+{
+  GtkWidget *retval;
+
+  g_return_val_if_fail (content_type != NULL, NULL);
+
+  retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG,
+                         "content-type", content_type,
+                         NULL);
+
+  set_parent_and_flags (retval, parent, flags);
+
+  return retval;
+}
+
+/**
+ * gtk_app_chooser_dialog_get_widget:
+ * @self: a `GtkAppChooserDialog`
+ *
+ * Returns the `GtkAppChooserWidget` of this dialog.
+ *
+ * Returns: (transfer none): the `GtkAppChooserWidget` of @self
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+GtkWidget *
+gtk_app_chooser_dialog_get_widget (GtkAppChooserDialog *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL);
+
+  return self->app_chooser_widget;
+}
+
+/**
+ * gtk_app_chooser_dialog_set_heading: (attributes org.gtk.Method.set_property=heading)
+ * @self: a `GtkAppChooserDialog`
+ * @heading: a string containing Pango markup
+ *
+ * Sets the text to display at the top of the dialog.
+ *
+ * If the heading is not set, the dialog displays a default text.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_dialog_set_heading (GtkAppChooserDialog *self,
+                                    const char          *heading)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self));
+
+  g_free (self->heading);
+  self->heading = g_strdup (heading);
+
+  if (self->label)
+    {
+      if (self->heading)
+        {
+          gtk_label_set_markup (GTK_LABEL (self->label), self->heading);
+          gtk_widget_show (self->label);
+        }
+      else
+        {
+          gtk_widget_hide (self->label);
+        }
+    }
+
+  g_object_notify (G_OBJECT (self), "heading");
+}
+
+/**
+ * gtk_app_chooser_dialog_get_heading: (attributes org.gtk.Method.get_property=heading)
+ * @self: a `GtkAppChooserDialog`
+ *
+ * Returns the text to display at the top of the dialog.
+ *
+ * Returns: (nullable): the text to display at the top of the dialog,
+ *   or %NULL, in which case a default text is displayed
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+const char *
+gtk_app_chooser_dialog_get_heading (GtkAppChooserDialog *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL);
+
+  return self->heading;
+}
diff --git a/gtk/deprecated/gtkappchooserdialog.h b/gtk/deprecated/gtkappchooserdialog.h
new file mode 100644 (file)
index 0000000..80e9269
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * gtkappchooserdialog.h: an app-chooser dialog
+ *
+ * Copyright (C) 2004 Novell, Inc.
+ * Copyright (C) 2007, 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Dave Camp <dave@novell.com>
+ *          Alexander Larsson <alexl@redhat.com>
+ *          Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+#ifndef __GTK_APP_CHOOSER_DIALOG_H__
+#define __GTK_APP_CHOOSER_DIALOG_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkdialog.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_APP_CHOOSER_DIALOG            (gtk_app_chooser_dialog_get_type ())
+#define GTK_APP_CHOOSER_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_DIALOG, GtkAppChooserDialog))
+#define GTK_IS_APP_CHOOSER_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_DIALOG))
+
+typedef struct _GtkAppChooserDialog        GtkAppChooserDialog;
+
+GDK_AVAILABLE_IN_ALL
+GType         gtk_app_chooser_dialog_get_type             (void) G_GNUC_CONST;
+
+GDK_DEPRECATED_IN_4_10
+GtkWidget *   gtk_app_chooser_dialog_new                  (GtkWindow           *parent,
+                                                           GtkDialogFlags       flags,
+                                                           GFile               *file);
+GDK_DEPRECATED_IN_4_10
+GtkWidget *   gtk_app_chooser_dialog_new_for_content_type (GtkWindow           *parent,
+                                                           GtkDialogFlags       flags,
+                                                           const char          *content_type);
+
+GDK_DEPRECATED_IN_4_10
+GtkWidget *   gtk_app_chooser_dialog_get_widget           (GtkAppChooserDialog *self);
+GDK_DEPRECATED_IN_4_10
+void          gtk_app_chooser_dialog_set_heading          (GtkAppChooserDialog *self,
+                                                           const char          *heading);
+GDK_DEPRECATED_IN_4_10
+const char * gtk_app_chooser_dialog_get_heading          (GtkAppChooserDialog *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserDialog, g_object_unref)
+
+G_END_DECLS
+
+#endif /* __GTK_APP_CHOOSER_DIALOG_H__ */
diff --git a/gtk/deprecated/gtkappchooserprivate.h b/gtk/deprecated/gtkappchooserprivate.h
new file mode 100644 (file)
index 0000000..754619a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * gtkappchooserprivate.h: app-chooser interface
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+#ifndef __GTK_APP_CHOOSER_PRIVATE_H__
+#define __GTK_APP_CHOOSER_PRIVATE_H__
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "gtkappchooser.h"
+#include "gtkappchooserwidget.h"
+#include "gtkentry.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkAppChooserIface GtkAppChooserIface;
+typedef GtkAppChooserIface GtkAppChooserInterface;
+
+#define GTK_APP_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_APP_CHOOSER, GtkAppChooserIface))
+
+struct _GtkAppChooserIface {
+  GTypeInterface base_iface;
+
+  GAppInfo * (* get_app_info) (GtkAppChooser *object);
+  void       (* refresh)      (GtkAppChooser *object);
+};
+
+void
+_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self,
+                                          GtkEditable         *editable);
+
+
+G_END_DECLS
+
+#endif /* __GTK_APP_CHOOSER_PRIVATE_H__ */
diff --git a/gtk/deprecated/gtkappchooserwidget.c b/gtk/deprecated/gtkappchooserwidget.c
new file mode 100644 (file)
index 0000000..fc662b2
--- /dev/null
@@ -0,0 +1,1408 @@
+/*
+ * gtkappchooserwidget.c: an app-chooser widget
+ *
+ * Copyright (C) 2004 Novell, Inc.
+ * Copyright (C) 2007, 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Dave Camp <dave@novell.com>
+ *          Alexander Larsson <alexl@redhat.com>
+ *          Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+#include "config.h"
+
+#include "gtkappchooserwidget.h"
+
+#include "gtkmarshalers.h"
+#include "gtkappchooserwidget.h"
+#include "gtkappchooserprivate.h"
+#include "gtkliststore.h"
+#include "gtktreeview.h"
+#include "gtktreeselection.h"
+#include "gtktreemodelsort.h"
+#include "gtkorientable.h"
+#include "gtkscrolledwindow.h"
+#include "gtklabel.h"
+#include "gtkgestureclick.h"
+#include "gtkwidgetprivate.h"
+#include "gtkprivate.h"
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+/**
+ * GtkAppChooserWidget:
+ *
+ * `GtkAppChooserWidget` is a widget for selecting applications.
+ *
+ * It is the main building block for [class@Gtk.AppChooserDialog].
+ * Most applications only need to use the latter; but you can use
+ * this widget as part of a larger widget if you have special needs.
+ *
+ * `GtkAppChooserWidget` offers detailed control over what applications
+ * are shown, using the
+ * [property@Gtk.AppChooserWidget:show-default],
+ * [property@Gtk.AppChooserWidget:show-recommended],
+ * [property@Gtk.AppChooserWidget:show-fallback],
+ * [property@Gtk.AppChooserWidget:show-other] and
+ * [property@Gtk.AppChooserWidget:show-all] properties. See the
+ * [iface@Gtk.AppChooser] documentation for more information about these
+ * groups of applications.
+ *
+ * To keep track of the selected application, use the
+ * [signal@Gtk.AppChooserWidget::application-selected] and
+ * [signal@Gtk.AppChooserWidget::application-activated] signals.
+ *
+ * # CSS nodes
+ *
+ * `GtkAppChooserWidget` has a single CSS node with name appchooser.
+ */
+
+typedef struct _GtkAppChooserWidgetClass   GtkAppChooserWidgetClass;
+
+struct _GtkAppChooserWidget {
+  GtkWidget parent_instance;
+
+  GAppInfo *selected_app_info;
+
+  GtkWidget *overlay;
+
+  char *content_type;
+  char *default_text;
+
+  guint show_default     : 1;
+  guint show_recommended : 1;
+  guint show_fallback    : 1;
+  guint show_other       : 1;
+  guint show_all         : 1;
+
+  GtkWidget *program_list;
+  GtkListStore *program_list_store;
+  GtkWidget *no_apps_label;
+  GtkWidget *no_apps;
+
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *padding_renderer;
+  GtkCellRenderer *secondary_padding;
+
+  GAppInfoMonitor *monitor;
+
+  GtkWidget *popup_menu;
+};
+
+struct _GtkAppChooserWidgetClass {
+  GtkWidgetClass parent_class;
+
+  void (* application_selected)  (GtkAppChooserWidget *self,
+                                  GAppInfo            *app_info);
+
+  void (* application_activated) (GtkAppChooserWidget *self,
+                                  GAppInfo            *app_info);
+};
+
+enum {
+  COLUMN_APP_INFO,
+  COLUMN_GICON,
+  COLUMN_NAME,
+  COLUMN_DESC,
+  COLUMN_EXEC,
+  COLUMN_DEFAULT,
+  COLUMN_HEADING,
+  COLUMN_HEADING_TEXT,
+  COLUMN_RECOMMENDED,
+  COLUMN_FALLBACK,
+  NUM_COLUMNS
+};
+
+
+enum {
+  PROP_CONTENT_TYPE = 1,
+  PROP_GFILE,
+  PROP_SHOW_DEFAULT,
+  PROP_SHOW_RECOMMENDED,
+  PROP_SHOW_FALLBACK,
+  PROP_SHOW_OTHER,
+  PROP_SHOW_ALL,
+  PROP_DEFAULT_TEXT,
+  N_PROPERTIES
+};
+
+enum {
+  SIGNAL_APPLICATION_SELECTED,
+  SIGNAL_APPLICATION_ACTIVATED,
+  N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0, };
+
+static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_WIDGET,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
+                                                gtk_app_chooser_widget_iface_init));
+
+static void
+refresh_and_emit_app_selected (GtkAppChooserWidget *self,
+                               GtkTreeSelection    *selection)
+{
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GAppInfo *info = NULL;
+  gboolean should_emit = FALSE;
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1);
+
+  if (info == NULL)
+    return;
+
+  if (self->selected_app_info)
+    {
+      if (!g_app_info_equal (self->selected_app_info, info))
+        {
+          should_emit = TRUE;
+          g_set_object (&self->selected_app_info, info);
+        }
+    }
+  else
+    {
+      should_emit = TRUE;
+      g_set_object (&self->selected_app_info, info);
+    }
+
+  g_object_unref (info);
+
+  if (should_emit)
+    g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0,
+                   self->selected_app_info);
+}
+
+static gboolean
+path_is_heading (GtkTreeView *view,
+                 GtkTreePath *path)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  gboolean res;
+
+  model = gtk_tree_view_get_model (view);
+  gtk_tree_model_get_iter (model, &iter, path);
+  gtk_tree_model_get (model, &iter,
+                      COLUMN_HEADING, &res,
+                      -1);
+
+  return res;
+}
+
+static void
+program_list_selection_activated (GtkTreeView       *view,
+                                  GtkTreePath       *path,
+                                  GtkTreeViewColumn *column,
+                                  gpointer           user_data)
+{
+  GtkAppChooserWidget *self = user_data;
+  GtkTreeSelection *selection;
+
+  if (path_is_heading (view, path))
+    return;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
+
+  refresh_and_emit_app_selected (self, selection);
+
+  g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0,
+                 self->selected_app_info);
+}
+
+static gboolean
+gtk_app_chooser_search_equal_func (GtkTreeModel *model,
+                                   int           column,
+                                   const char   *key,
+                                   GtkTreeIter  *iter,
+                                   gpointer      user_data)
+{
+  char *name;
+  char *exec_name;
+  gboolean ret;
+
+  if (key != NULL)
+    {
+      ret = TRUE;
+
+      gtk_tree_model_get (model, iter,
+                          COLUMN_NAME, &name,
+                          COLUMN_EXEC, &exec_name,
+                          -1);
+
+      if ((name != NULL && g_str_match_string (key, name, TRUE)) ||
+          (exec_name != NULL && g_str_match_string (key, exec_name, FALSE)))
+        ret = FALSE;
+
+      g_free (name);
+      g_free (exec_name);
+
+      return ret;
+    }
+  else
+    {
+      return TRUE;
+    }
+}
+
+static int
+gtk_app_chooser_sort_func (GtkTreeModel *model,
+                           GtkTreeIter  *a,
+                           GtkTreeIter  *b,
+                           gpointer      user_data)
+{
+  gboolean a_recommended, b_recommended;
+  gboolean a_fallback, b_fallback;
+  gboolean a_heading, b_heading;
+  gboolean a_default, b_default;
+  char *a_name, *b_name, *a_casefold, *b_casefold;
+  int retval = 0;
+
+  /* this returns:
+   * - <0 if a should show before b
+   * - =0 if a is the same as b
+   * - >0 if a should show after b
+   */
+
+  gtk_tree_model_get (model, a,
+                      COLUMN_NAME, &a_name,
+                      COLUMN_RECOMMENDED, &a_recommended,
+                      COLUMN_FALLBACK, &a_fallback,
+                      COLUMN_HEADING, &a_heading,
+                      COLUMN_DEFAULT, &a_default,
+                      -1);
+
+  gtk_tree_model_get (model, b,
+                      COLUMN_NAME, &b_name,
+                      COLUMN_RECOMMENDED, &b_recommended,
+                      COLUMN_FALLBACK, &b_fallback,
+                      COLUMN_HEADING, &b_heading,
+                      COLUMN_DEFAULT, &b_default,
+                      -1);
+
+  /* the default one always wins */
+  if (a_default && !b_default)
+    {
+      retval = -1;
+      goto out;
+    }
+
+  if (b_default && !a_default)
+    {
+      retval = 1;
+      goto out;
+    }
+  
+  /* the recommended one always wins */
+  if (a_recommended && !b_recommended)
+    {
+      retval = -1;
+      goto out;
+    }
+
+  if (b_recommended && !a_recommended)
+    {
+      retval = 1;
+      goto out;
+    }
+
+  /* the recommended one always wins */
+  if (a_fallback && !b_fallback)
+    {
+      retval = -1;
+      goto out;
+    }
+
+  if (b_fallback && !a_fallback)
+    {
+      retval = 1;
+      goto out;
+    }
+
+  /* they're both recommended/fallback or not, so if one is a heading, wins */
+  if (a_heading)
+    {
+      retval = -1;
+      goto out;
+    }
+
+  if (b_heading)
+    {
+      retval = 1;
+      goto out;
+    }
+
+  /* don't order by name recommended applications, but use GLib's ordering */
+  if (!a_recommended)
+    {
+      a_casefold = a_name != NULL ?
+        g_utf8_casefold (a_name, -1) : NULL;
+      b_casefold = b_name != NULL ?
+        g_utf8_casefold (b_name, -1) : NULL;
+
+      retval = g_strcmp0 (a_casefold, b_casefold);
+
+      g_free (a_casefold);
+      g_free (b_casefold);
+    }
+
+ out:
+  g_free (a_name);
+  g_free (b_name);
+
+  return retval;
+}
+
+static void
+padding_cell_renderer_func (GtkTreeViewColumn *column,
+                            GtkCellRenderer   *cell,
+                            GtkTreeModel      *model,
+                            GtkTreeIter       *iter,
+                            gpointer           user_data)
+{
+  gboolean heading;
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_HEADING, &heading,
+                      -1);
+  if (heading)
+    g_object_set (cell,
+                  "visible", FALSE,
+                  "xpad", 0,
+                  "ypad", 0,
+                  NULL);
+  else
+    g_object_set (cell,
+                  "visible", TRUE,
+                  "xpad", 3,
+                  "ypad", 3,
+                  NULL);
+}
+
+static gboolean
+gtk_app_chooser_selection_func (GtkTreeSelection *selection,
+                                GtkTreeModel     *model,
+                                GtkTreePath      *path,
+                                gboolean          path_currently_selected,
+                                gpointer          user_data)
+{
+  GtkTreeIter iter;
+  gboolean heading;
+
+  gtk_tree_model_get_iter (model, &iter, path);
+  gtk_tree_model_get (model, &iter,
+                      COLUMN_HEADING, &heading,
+                      -1);
+
+  return !heading;
+}
+
+static int
+compare_apps_func (gconstpointer a,
+                   gconstpointer b)
+{
+  return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
+}
+
+static gboolean
+gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self,
+                                    const char          *heading_title,
+                                    gboolean             show_headings,
+                                    gboolean             recommended,
+                                    gboolean             fallback,
+                                    GList               *applications,
+                                    GList               *exclude_apps)
+{
+  gboolean heading_added, unref_icon;
+  GtkTreeIter iter;
+  GAppInfo *app;
+  char *app_string, *bold_string;
+  GIcon *icon;
+  GList *l;
+  gboolean retval;
+
+  retval = FALSE;
+  heading_added = FALSE;
+  bold_string = g_strdup_printf ("<b>%s</b>", heading_title);
+  
+  for (l = applications; l != NULL; l = l->next)
+    {
+      app = l->data;
+
+      if (self->content_type != NULL &&
+          !g_app_info_supports_uris (app) &&
+          !g_app_info_supports_files (app))
+        continue;
+
+      if (g_list_find_custom (exclude_apps, app,
+                              (GCompareFunc) compare_apps_func))
+        continue;
+
+      if (!heading_added && show_headings)
+        {
+          gtk_list_store_append (self->program_list_store, &iter);
+          gtk_list_store_set (self->program_list_store, &iter,
+                              COLUMN_HEADING_TEXT, bold_string,
+                              COLUMN_HEADING, TRUE,
+                              COLUMN_RECOMMENDED, recommended,
+                              COLUMN_FALLBACK, fallback,
+                              -1);
+
+          heading_added = TRUE;
+        }
+
+      app_string = g_markup_printf_escaped ("%s",
+                                            g_app_info_get_name (app) != NULL ?
+                                            g_app_info_get_name (app) : "");
+
+      icon = g_app_info_get_icon (app);
+      unref_icon = FALSE;
+      if (icon == NULL)
+        {
+          icon = g_themed_icon_new ("application-x-executable");
+          unref_icon = TRUE;
+        }
+
+      gtk_list_store_append (self->program_list_store, &iter);
+      gtk_list_store_set (self->program_list_store, &iter,
+                          COLUMN_APP_INFO, app,
+                          COLUMN_GICON, icon,
+                          COLUMN_NAME, g_app_info_get_name (app),
+                          COLUMN_DESC, app_string,
+                          COLUMN_EXEC, g_app_info_get_executable (app),
+                          COLUMN_HEADING, FALSE,
+                          COLUMN_RECOMMENDED, recommended,
+                          COLUMN_FALLBACK, fallback,
+                          -1);
+
+      retval = TRUE;
+
+      g_free (app_string);
+      if (unref_icon)
+        g_object_unref (icon);
+    }
+
+  g_free (bold_string);
+
+  return retval;
+}
+
+
+static void
+gtk_app_chooser_add_default (GtkAppChooserWidget *self,
+                             GAppInfo            *app)
+{
+  GtkTreeIter iter;
+  GIcon *icon;
+  char *string;
+  gboolean unref_icon;
+
+  unref_icon = FALSE;
+  string = g_strdup_printf ("<b>%s</b>", _("Default Application"));
+
+  gtk_list_store_append (self->program_list_store, &iter);
+  gtk_list_store_set (self->program_list_store, &iter,
+                      COLUMN_HEADING_TEXT, string,
+                      COLUMN_HEADING, TRUE,
+                      COLUMN_DEFAULT, TRUE,
+                      -1);
+
+  g_free (string);
+
+  string = g_markup_printf_escaped ("%s",
+                                    g_app_info_get_name (app) != NULL ?
+                                    g_app_info_get_name (app) : "");
+
+  icon = g_app_info_get_icon (app);
+  if (icon == NULL)
+    {
+      icon = g_themed_icon_new ("application-x-executable");
+      unref_icon = TRUE;
+    }
+
+  gtk_list_store_append (self->program_list_store, &iter);
+  gtk_list_store_set (self->program_list_store, &iter,
+                      COLUMN_APP_INFO, app,
+                      COLUMN_GICON, icon,
+                      COLUMN_NAME, g_app_info_get_name (app),
+                      COLUMN_DESC, string,
+                      COLUMN_EXEC, g_app_info_get_executable (app),
+                      COLUMN_HEADING, FALSE,
+                      COLUMN_DEFAULT, TRUE,
+                      -1);
+
+  g_free (string);
+
+  if (unref_icon)
+    g_object_unref (icon);
+}
+
+static void
+update_no_applications_label (GtkAppChooserWidget *self)
+{
+  char *text = NULL, *desc = NULL;
+  const char *string;
+
+  if (self->default_text == NULL)
+    {
+      if (self->content_type)
+       desc = g_content_type_get_description (self->content_type);
+
+      string = text = g_strdup_printf (_("No applications found for “%s”."), desc);
+      g_free (desc);
+    }
+  else
+    {
+      string = self->default_text;
+    }
+
+  gtk_label_set_text (GTK_LABEL (self->no_apps_label), string);
+
+  g_free (text);
+}
+
+static void
+gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
+{
+  GtkTreeIter iter;
+  GAppInfo *info = NULL;
+  GtkTreeModel *model;
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list));
+  if (!gtk_tree_model_get_iter_first (model, &iter))
+    return;
+
+  while (info == NULL)
+    {
+      gtk_tree_model_get (model, &iter,
+                          COLUMN_APP_INFO, &info,
+                          -1);
+
+      if (info != NULL)
+        break;
+
+      if (!gtk_tree_model_iter_next (model, &iter))
+        break;
+    }
+
+  if (info != NULL)
+    {
+      GtkTreeSelection *selection;
+
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
+      gtk_tree_selection_select_iter (selection, &iter);
+
+      g_object_unref (info);
+    }
+}
+
+static void
+gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
+{
+  GList *all_applications = NULL;
+  GList *recommended_apps = NULL;
+  GList *fallback_apps = NULL;
+  GList *exclude_apps = NULL;
+  GAppInfo *default_app = NULL;
+  gboolean show_headings;
+  gboolean apps_added;
+
+  show_headings = TRUE;
+  apps_added = FALSE;
+
+  if (self->show_all)
+    show_headings = FALSE;
+
+  if (self->show_default && self->content_type)
+    {
+      default_app = g_app_info_get_default_for_type (self->content_type, FALSE);
+
+      if (default_app != NULL)
+        {
+          gtk_app_chooser_add_default (self, default_app);
+          apps_added = TRUE;
+          exclude_apps = g_list_prepend (exclude_apps, default_app);
+        }
+    }
+
+#ifndef G_OS_WIN32
+  if ((self->content_type && self->show_recommended) || self->show_all)
+    {
+      if (self->content_type)
+       recommended_apps = g_app_info_get_recommended_for_type (self->content_type);
+
+      apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
+                                                        show_headings,
+                                                        !self->show_all, /* mark as recommended */
+                                                        FALSE, /* mark as fallback */
+                                                        recommended_apps, exclude_apps);
+
+      exclude_apps = g_list_concat (exclude_apps,
+                                    g_list_copy (recommended_apps));
+    }
+
+  if ((self->content_type && self->show_fallback) || self->show_all)
+    {
+      if (self->content_type)
+       fallback_apps = g_app_info_get_fallback_for_type (self->content_type);
+
+      apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
+                                                        show_headings,
+                                                        FALSE, /* mark as recommended */
+                                                        !self->show_all, /* mark as fallback */
+                                                        fallback_apps, exclude_apps);
+      exclude_apps = g_list_concat (exclude_apps,
+                                    g_list_copy (fallback_apps));
+    }
+#endif
+
+  if (self->show_other || self->show_all)
+    {
+      all_applications = g_app_info_get_all ();
+
+      apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
+                                                        show_headings,
+                                                        FALSE,
+                                                        FALSE,
+                                                        all_applications, exclude_apps);
+    }
+
+  if (!apps_added)
+    update_no_applications_label (self);
+
+  gtk_widget_set_visible (self->no_apps, !apps_added);
+
+  gtk_app_chooser_widget_select_first (self);
+
+  if (default_app != NULL)
+    g_object_unref (default_app);
+
+  g_list_free_full (all_applications, g_object_unref);
+  g_list_free_full (recommended_apps, g_object_unref);
+  g_list_free_full (fallback_apps, g_object_unref);
+  g_list_free (exclude_apps);
+}
+
+static void
+gtk_app_chooser_widget_initialize_items (GtkAppChooserWidget *self)
+{
+  /* initial padding */
+  g_object_set (self->padding_renderer,
+                "xpad", self->show_all ? 0 : 6,
+                NULL);
+
+  /* populate the widget */
+  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+}
+
+static void
+app_info_changed (GAppInfoMonitor     *monitor,
+                  GtkAppChooserWidget *self)
+{
+  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+}
+
+static void
+gtk_app_chooser_widget_set_property (GObject      *object,
+                                     guint         property_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTENT_TYPE:
+      self->content_type = g_value_dup_string (value);
+      break;
+    case PROP_SHOW_DEFAULT:
+      gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value));
+      break;
+    case PROP_SHOW_RECOMMENDED:
+      gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value));
+      break;
+    case PROP_SHOW_FALLBACK:
+      gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value));
+      break;
+    case PROP_SHOW_OTHER:
+      gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value));
+      break;
+    case PROP_SHOW_ALL:
+      gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value));
+      break;
+    case PROP_DEFAULT_TEXT:
+      gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_app_chooser_widget_get_property (GObject    *object,
+                                     guint       property_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
+
+  switch (property_id)
+    {
+    case PROP_CONTENT_TYPE:
+      g_value_set_string (value, self->content_type);
+      break;
+    case PROP_SHOW_DEFAULT:
+      g_value_set_boolean (value, self->show_default);
+      break;
+    case PROP_SHOW_RECOMMENDED:
+      g_value_set_boolean (value, self->show_recommended);
+      break;
+    case PROP_SHOW_FALLBACK:
+      g_value_set_boolean (value, self->show_fallback);
+      break;
+    case PROP_SHOW_OTHER:
+      g_value_set_boolean (value, self->show_other);
+      break;
+    case PROP_SHOW_ALL:
+      g_value_set_boolean (value, self->show_all);
+      break;
+    case PROP_DEFAULT_TEXT:
+      g_value_set_string (value, self->default_text);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_app_chooser_widget_constructed (GObject *object)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
+
+  if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object);
+
+  gtk_app_chooser_widget_initialize_items (self);
+}
+
+static void
+gtk_app_chooser_widget_finalize (GObject *object)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
+
+  g_free (self->content_type);
+  g_free (self->default_text);
+  g_signal_handlers_disconnect_by_func (self->monitor, app_info_changed, self);
+  g_object_unref (self->monitor);
+
+  G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
+}
+
+static void
+gtk_app_chooser_widget_dispose (GObject *object)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
+
+  g_clear_object (&self->selected_app_info);
+
+  if (self->overlay)
+    {
+      gtk_widget_unparent (self->overlay);
+      self->overlay = NULL;
+    }
+
+  G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
+}
+
+static void
+gtk_app_chooser_widget_measure (GtkWidget       *widget,
+                                GtkOrientation  orientation,
+                                int             for_size,
+                                int            *minimum,
+                                int            *natural,
+                                int            *minimum_baseline,
+                                int            *natural_baseline)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
+
+  gtk_widget_measure (self->overlay, orientation, for_size,
+                      minimum, natural,
+                      minimum_baseline, natural_baseline);
+}
+
+static void
+gtk_app_chooser_widget_snapshot (GtkWidget   *widget,
+                                 GtkSnapshot *snapshot)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
+
+  gtk_widget_snapshot_child (widget, self->overlay, snapshot);
+}
+
+static void
+gtk_app_chooser_widget_size_allocate (GtkWidget *widget,
+                                      int        width,
+                                      int        height,
+                                      int        baseline)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
+
+  GTK_WIDGET_CLASS (gtk_app_chooser_widget_parent_class)->size_allocate (widget, width, height, baseline);
+
+  gtk_widget_size_allocate (self->overlay,
+                            &(GtkAllocation) {
+                              0, 0,
+                              width, height
+                            },baseline);
+}
+
+static void
+gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
+{
+  GtkWidgetClass *widget_class;
+  GObjectClass *gobject_class;
+  GParamSpec *pspec;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->dispose = gtk_app_chooser_widget_dispose;
+  gobject_class->finalize = gtk_app_chooser_widget_finalize;
+  gobject_class->set_property = gtk_app_chooser_widget_set_property;
+  gobject_class->get_property = gtk_app_chooser_widget_get_property;
+  gobject_class->constructed = gtk_app_chooser_widget_constructed;
+
+  widget_class = GTK_WIDGET_CLASS (klass);
+  widget_class->measure = gtk_app_chooser_widget_measure;
+  widget_class->size_allocate = gtk_app_chooser_widget_size_allocate;
+  widget_class->snapshot = gtk_app_chooser_widget_snapshot;
+
+  g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
+
+  /**
+   * 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)
+   *
+   * Determines whether the app chooser should show the default
+   * handler for the content type in a separate section.
+   *
+   * If %FALSE, the default handler is listed among the recommended
+   * applications.
+   */
+  pspec = g_param_spec_boolean ("show-default", NULL, NULL,
+                                FALSE,
+                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec);
+
+  /**
+   * 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)
+   *
+   * Determines whether the app chooser should show a section
+   * for recommended applications.
+   *
+   * If %FALSE, the recommended applications are listed
+   * among the other applications.
+   */
+  pspec = g_param_spec_boolean ("show-recommended", NULL, NULL,
+                                TRUE,
+                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec);
+
+  /**
+   * 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)
+   *
+   * Determines whether the app chooser should show a section
+   * for fallback applications.
+   *
+   * If %FALSE, the fallback applications are listed among the
+   * other applications.
+   */
+  pspec = g_param_spec_boolean ("show-fallback", NULL, NULL,
+                                FALSE,
+                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec);
+
+  /**
+   * 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)
+   *
+   * Determines whether the app chooser should show a section
+   * for other applications.
+   */
+  pspec = g_param_spec_boolean ("show-other", NULL, NULL,
+                                FALSE,
+                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec);
+
+  /**
+   * 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)
+   *
+   * If %TRUE, the app chooser presents all applications
+   * in a single list, without subsections for default,
+   * recommended or related applications.
+   */
+  pspec = g_param_spec_boolean ("show-all", NULL, NULL,
+                                FALSE,
+                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec);
+
+  /**
+   * 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)
+   *
+   * The text that appears in the widget when there are no applications
+   * for the given content type.
+   */
+  pspec = g_param_spec_string ("default-text", NULL, NULL,
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+  g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec);
+
+  /**
+   * GtkAppChooserWidget::application-selected:
+   * @self: the object which received the signal
+   * @application: the selected `GAppInfo`
+   *
+   * Emitted when an application item is selected from the widget's list.
+   */
+  signals[SIGNAL_APPLICATION_SELECTED] =
+    g_signal_new (I_("application-selected"),
+                  GTK_TYPE_APP_CHOOSER_WIDGET,
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  1, G_TYPE_APP_INFO);
+
+  /**
+   * GtkAppChooserWidget::application-activated:
+   * @self: the object which received the signal
+   * @application: the activated `GAppInfo`
+   *
+   * Emitted when an application item is activated from the widget's list.
+   *
+   * This usually happens when the user double clicks an item, or an item
+   * is selected and the user presses one of the keys Space, Shift+Space,
+   * Return or Enter.
+   */
+  signals[SIGNAL_APPLICATION_ACTIVATED] =
+    g_signal_new (I_("application-activated"),
+                  GTK_TYPE_APP_CHOOSER_WIDGET,
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  1, G_TYPE_APP_INFO);
+
+  /* Bind class to template
+   */
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                              "/org/gtk/libgtk/ui/gtkappchooserwidget.ui");
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list_store);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, column);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, padding_renderer);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, secondary_padding);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps_label);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps);
+  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, overlay);
+  gtk_widget_class_bind_template_callback (widget_class, refresh_and_emit_app_selected);
+  gtk_widget_class_bind_template_callback (widget_class, program_list_selection_activated);
+
+  gtk_widget_class_set_css_name (widget_class, I_("appchooser"));
+}
+
+static void
+gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel *sort;
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  /* Various parts of the GtkTreeView code need custom code to setup, mostly
+   * because we lack signals to connect to, or properties to set.
+   */
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
+  gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func,
+                                          self, NULL);
+
+  sort = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list));
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort),
+                                        COLUMN_NAME,
+                                        GTK_SORT_ASCENDING);
+  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
+                                   COLUMN_NAME,
+                                   gtk_app_chooser_sort_func,
+                                   self, NULL);
+
+  gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->program_list), COLUMN_NAME);
+  gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->program_list),
+                                       gtk_app_chooser_search_equal_func,
+                                       NULL, NULL);
+
+  gtk_tree_view_column_set_cell_data_func (self->column,
+                                          self->secondary_padding,
+                                           padding_cell_renderer_func,
+                                           NULL, NULL);
+
+  self->monitor = g_app_info_monitor_get ();
+  g_signal_connect (self->monitor, "changed",
+                   G_CALLBACK (app_info_changed), self);
+}
+
+static GAppInfo *
+gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
+
+  if (self->selected_app_info == NULL)
+    return NULL;
+
+  return g_object_ref (self->selected_app_info);
+}
+
+static void
+gtk_app_chooser_widget_refresh (GtkAppChooser *object)
+{
+  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
+
+  if (self->program_list_store != NULL)
+    {
+      gtk_list_store_clear (self->program_list_store);
+
+      /* don't add additional xpad if we don't have headings */
+      g_object_set (self->padding_renderer,
+                    "visible", !self->show_all,
+                    NULL);
+
+      gtk_app_chooser_widget_real_add_items (self);
+    }
+}
+
+static void
+gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
+{
+  iface->get_app_info = gtk_app_chooser_widget_get_app_info;
+  iface->refresh = gtk_app_chooser_widget_refresh;
+}
+
+/**
+ * gtk_app_chooser_widget_new:
+ * @content_type: the content type to show applications for
+ *
+ * Creates a new `GtkAppChooserWidget` for applications
+ * that can handle content of the given type.
+ *
+ * Returns: a newly created `GtkAppChooserWidget`
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+GtkWidget *
+gtk_app_chooser_widget_new (const char *content_type)
+{
+  return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
+                       "content-type", content_type,
+                       NULL);
+}
+
+/**
+ * gtk_app_chooser_widget_set_show_default: (attributes org.gtk.Method.set_property=show-default)
+ * @self: a `GtkAppChooserWidget`
+ * @setting: the new value for [property@Gtk.AppChooserWidget:show-default]
+ *
+ * Sets whether the app chooser should show the default handler
+ * for the content type in a separate section.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
+                                         gboolean             setting)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
+
+  if (self->show_default != setting)
+    {
+      self->show_default = setting;
+
+      g_object_notify (G_OBJECT (self), "show-default");
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_widget_get_show_default: (attributes org.gtk.Method.get_property=show-default)
+ * @self: a `GtkAppChooserWidget`
+ *
+ * Gets whether the app chooser should show the default handler
+ * for the content type in a separate section.
+ *
+ * Returns: the value of [property@Gtk.AppChooserWidget:show-default]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
+
+  return self->show_default;
+}
+
+/**
+ * gtk_app_chooser_widget_set_show_recommended: (attributes org.gtk.Method.set_property=show-recommended)
+ * @self: a `GtkAppChooserWidget`
+ * @setting: the new value for [property@Gtk.AppChooserWidget:show-recommended]
+ *
+ * Sets whether the app chooser should show recommended applications
+ * for the content type in a separate section.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
+                                             gboolean             setting)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
+
+  if (self->show_recommended != setting)
+    {
+      self->show_recommended = setting;
+
+      g_object_notify (G_OBJECT (self), "show-recommended");
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_widget_get_show_recommended: (attributes org.gtk.Method.get_property=show-recommended)
+ * @self: a `GtkAppChooserWidget`
+ *
+ * Gets whether the app chooser should show recommended applications
+ * for the content type in a separate section.
+ *
+ * Returns: the value of [property@Gtk.AppChooserWidget:show-recommended]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
+
+  return self->show_recommended;
+}
+
+/**
+ * gtk_app_chooser_widget_set_show_fallback: (attributes org.gtk.Method.set_property=show-fallback)
+ * @self: a `GtkAppChooserWidget`
+ * @setting: the new value for [property@Gtk.AppChooserWidget:show-fallback]
+ *
+ * Sets whether the app chooser should show related applications
+ * for the content type in a separate section.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
+                                          gboolean             setting)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
+
+  if (self->show_fallback != setting)
+    {
+      self->show_fallback = setting;
+
+      g_object_notify (G_OBJECT (self), "show-fallback");
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_widget_get_show_fallback: (attributes org.gtk.Method.get_property=show-fallback)
+ * @self: a `GtkAppChooserWidget`
+ *
+ * Gets whether the app chooser should show related applications
+ * for the content type in a separate section.
+ *
+ * Returns: the value of [property@Gtk.AppChooserWidget:show-fallback]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
+
+  return self->show_fallback;
+}
+
+/**
+ * gtk_app_chooser_widget_set_show_other: (attributes org.gtk.Method.set_property=show-other)
+ * @self: a `GtkAppChooserWidget`
+ * @setting: the new value for [property@Gtk.AppChooserWidget:show-other]
+ *
+ * Sets whether the app chooser should show applications
+ * which are unrelated to the content type.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
+                                       gboolean             setting)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
+
+  if (self->show_other != setting)
+    {
+      self->show_other = setting;
+
+      g_object_notify (G_OBJECT (self), "show-other");
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_widget_get_show_other: (attributes org.gtk.Method.get_property=show-other)
+ * @self: a `GtkAppChooserWidget`
+ *
+ * Gets whether the app chooser should show applications
+ * which are unrelated to the content type.
+ *
+ * Returns: the value of [property@Gtk.AppChooserWidget:show-other]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
+
+  return self->show_other;
+}
+
+/**
+ * gtk_app_chooser_widget_set_show_all: (attributes org.gtk.Method.set_property=show-all)
+ * @self: a `GtkAppChooserWidget`
+ * @setting: the new value for [property@Gtk.AppChooserWidget:show-all]
+ *
+ * Sets whether the app chooser should show all applications
+ * in a flat list.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
+                                     gboolean             setting)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
+
+  if (self->show_all != setting)
+    {
+      self->show_all = setting;
+
+      g_object_notify (G_OBJECT (self), "show-all");
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_widget_get_show_all: (attributes org.gtk.Method.get_property=show-all)
+ * @self: a `GtkAppChooserWidget`
+ *
+ * Gets whether the app chooser should show all applications
+ * in a flat list.
+ *
+ * Returns: the value of [property@Gtk.AppChooserWidget:show-all]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+gboolean
+gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
+
+  return self->show_all;
+}
+
+/**
+ * gtk_app_chooser_widget_set_default_text: (attributes org.gtk.Method.set_property=default-text)
+ * @self: a `GtkAppChooserWidget`
+ * @text: the new value for [property@Gtk.AppChooserWidget:default-text]
+ *
+ * Sets the text that is shown if there are not applications
+ * that can handle the content type.
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+void
+gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
+                                         const char          *text)
+{
+  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
+
+  if (g_strcmp0 (text, self->default_text) != 0)
+    {
+      g_free (self->default_text);
+      self->default_text = g_strdup (text);
+
+      g_object_notify (G_OBJECT (self), "default-text");
+
+      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
+    }
+}
+
+/**
+ * gtk_app_chooser_widget_get_default_text: (attributes org.gtk.Method.get_property=default-text)
+ * @self: a `GtkAppChooserWidget`
+ *
+ * Returns the text that is shown if there are not applications
+ * that can handle the content type.
+ *
+ * Returns: (nullable): the value of [property@Gtk.AppChooserWidget:default-text]
+ *
+ * Deprecated: 4.10: This widget will be removed in GTK 5
+ */
+const char *
+gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
+{
+  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
+
+  return self->default_text;
+}
+
+void
+_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self,
+                                          GtkEditable         *entry)
+{
+  gtk_tree_view_set_search_entry (GTK_TREE_VIEW (self->program_list), entry);
+
+  g_object_bind_property (self->no_apps, "visible",
+                          entry, "sensitive",
+                          G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+}
diff --git a/gtk/deprecated/gtkappchooserwidget.h b/gtk/deprecated/gtkappchooserwidget.h
new file mode 100644 (file)
index 0000000..75751dc
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * gtkappchooserwidget.h: an app-chooser widget
+ *
+ * Copyright (C) 2004 Novell, Inc.
+ * Copyright (C) 2007, 2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Dave Camp <dave@novell.com>
+ *          Alexander Larsson <alexl@redhat.com>
+ *          Cosimo Cecchi <ccecchi@redhat.com>
+ */
+
+#ifndef __GTK_APP_CHOOSER_WIDGET_H__
+#define __GTK_APP_CHOOSER_WIDGET_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkwidget.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_APP_CHOOSER_WIDGET            (gtk_app_chooser_widget_get_type ())
+#define GTK_APP_CHOOSER_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_WIDGET, GtkAppChooserWidget))
+#define GTK_IS_APP_CHOOSER_WIDGET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_WIDGET))
+
+typedef struct _GtkAppChooserWidget        GtkAppChooserWidget;
+
+GDK_AVAILABLE_IN_ALL
+GType         gtk_app_chooser_widget_get_type             (void) G_GNUC_CONST;
+
+GDK_DEPRECATED_IN_4_10
+GtkWidget *   gtk_app_chooser_widget_new                  (const char          *content_type);
+
+GDK_DEPRECATED_IN_4_10
+void          gtk_app_chooser_widget_set_show_default     (GtkAppChooserWidget *self,
+                                                           gboolean             setting);
+GDK_DEPRECATED_IN_4_10
+gboolean      gtk_app_chooser_widget_get_show_default     (GtkAppChooserWidget *self);
+
+GDK_DEPRECATED_IN_4_10
+void          gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
+                                                           gboolean             setting);
+GDK_DEPRECATED_IN_4_10
+gboolean      gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self);
+
+GDK_DEPRECATED_IN_4_10
+void          gtk_app_chooser_widget_set_show_fallback    (GtkAppChooserWidget *self,
+                                                           gboolean             setting);
+GDK_DEPRECATED_IN_4_10
+gboolean      gtk_app_chooser_widget_get_show_fallback    (GtkAppChooserWidget *self);
+
+GDK_DEPRECATED_IN_4_10
+void          gtk_app_chooser_widget_set_show_other       (GtkAppChooserWidget *self,
+                                                           gboolean             setting);
+GDK_DEPRECATED_IN_4_10
+gboolean      gtk_app_chooser_widget_get_show_other       (GtkAppChooserWidget *self);
+
+GDK_DEPRECATED_IN_4_10
+void          gtk_app_chooser_widget_set_show_all         (GtkAppChooserWidget *self,
+                                                           gboolean             setting);
+GDK_DEPRECATED_IN_4_10
+gboolean      gtk_app_chooser_widget_get_show_all         (GtkAppChooserWidget *self);
+
+GDK_DEPRECATED_IN_4_10
+void          gtk_app_chooser_widget_set_default_text     (GtkAppChooserWidget *self,
+                                                           const char          *text);
+GDK_DEPRECATED_IN_4_10
+const char * gtk_app_chooser_widget_get_default_text     (GtkAppChooserWidget *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserWidget, g_object_unref)
+
+G_END_DECLS
+
+#endif /* __GTK_APP_CHOOSER_WIDGET_H__ */
index 7e7916bcff5fe4e0d8aacfa1e522082bd5dacd8e..98c454ef735ffd81621d173e7ba14381ab3c49cf 100644 (file)
@@ -1,5 +1,13 @@
-gtk_deprecated_sources = files([])
+gtk_deprecated_sources = [
+  'deprecated/gtkappchooser.c',
+  'deprecated/gtkappchooserbutton.c',
+  'deprecated/gtkappchooserdialog.c',
+  'deprecated/gtkappchooserwidget.c',
+]
 
-gtk_deprecated_headers = files([])
-
-install_headers(gtk_deprecated_headers, subdir: 'gtk-4.0/gtk/deprecated/')
+gtk_deprecated_headers = [
+  'deprecated/gtkappchooser.h',
+  'deprecated/gtkappchooserbutton.h',
+  'deprecated/gtkappchooserdialog.h',
+  'deprecated/gtkappchooserwidget.h',
+]
index f995ba4689a89229f8e727db645adb3f4becf07c..ff0a3eff62c0790301820a32be6a1b99c3b264d0 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
 #include <gtk/gtkactionable.h>
 #include <gtk/gtkactionbar.h>
 #include <gtk/gtkadjustment.h>
-#include <gtk/gtkappchooser.h>
-#include <gtk/gtkappchooserdialog.h>
-#include <gtk/gtkappchooserwidget.h>
-#include <gtk/gtkappchooserbutton.h>
+#include <gtk/deprecated/gtkappchooser.h>
+#include <gtk/deprecated/gtkappchooserdialog.h>
+#include <gtk/deprecated/gtkappchooserwidget.h>
+#include <gtk/deprecated/gtkappchooserbutton.h>
 #include <gtk/gtkapplication.h>
 #include <gtk/gtkapplicationwindow.h>
 #include <gtk/gtkaspectframe.h>
diff --git a/gtk/gtkappchooser.c b/gtk/gtkappchooser.c
deleted file mode 100644 (file)
index 51b50f9..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * gtkappchooser.c: app-chooser interface
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-/**
- * GtkAppChooser:
- *
- * `GtkAppChooser` is an interface for widgets which allow the user to
- * choose an application.
- *
- * The main objects that implement this interface are
- * [class@Gtk.AppChooserWidget],
- * [class@Gtk.AppChooserDialog] and [class@Gtk.AppChooserButton].
- *
- * Applications are represented by GIO `GAppInfo` objects here.
- * GIO has a concept of recommended and fallback applications for a
- * given content type. Recommended applications are those that claim
- * to handle the content type itself, while fallback also includes
- * applications that handle a more generic content type. GIO also
- * knows the default and last-used application for a given content
- * type. The `GtkAppChooserWidget` provides detailed control over
- * whether the shown list of applications should include default,
- * recommended or fallback applications.
- *
- * To obtain the application that has been selected in a `GtkAppChooser`,
- * use [method@Gtk.AppChooser.get_app_info].
- */
-
-#include "config.h"
-
-#include "gtkappchooser.h"
-
-#include "gtkappchooserprivate.h"
-#include "gtkwidget.h"
-
-#include <glib.h>
-
-G_DEFINE_INTERFACE (GtkAppChooser, gtk_app_chooser, GTK_TYPE_WIDGET);
-
-static void
-gtk_app_chooser_default_init (GtkAppChooserIface *iface)
-{
-  GParamSpec *pspec;
-
-  /**
-   * GtkAppChooser:content-type: (attributes org.gtk.Property.get=gtk_app_chooser_get_content_type)
-   *
-   * The content type of the `GtkAppChooser` object.
-   *
-   * See `GContentType` for more information about content types.
-   */
-  pspec = g_param_spec_string ("content-type", NULL, NULL,
-                               NULL,
-                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-                               G_PARAM_STATIC_STRINGS);
-  g_object_interface_install_property (iface, pspec);
-}
-
-
-/**
- * gtk_app_chooser_get_content_type: (attributes org.gtk.Method.get_property=content-type)
- * @self: a `GtkAppChooser`
- *
- * Returns the content type for which the `GtkAppChooser`
- * shows applications.
- *
- * Returns: the content type of @self. Free with g_free()
- */
-char *
-gtk_app_chooser_get_content_type (GtkAppChooser *self)
-{
-  char *retval = NULL;
-
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER (self), NULL);
-
-  g_object_get (self,
-                "content-type", &retval,
-                NULL);
-
-  return retval;
-}
-
-/**
- * gtk_app_chooser_get_app_info:
- * @self: a `GtkAppChooser`
- *
- * Returns the currently selected application.
- *
- * Returns: (nullable) (transfer full): a `GAppInfo` for the
- *   currently selected application
- */
-GAppInfo *
-gtk_app_chooser_get_app_info (GtkAppChooser *self)
-{
-  return GTK_APP_CHOOSER_GET_IFACE (self)->get_app_info (self);
-}
-
-/**
- * gtk_app_chooser_refresh:
- * @self: a `GtkAppChooser`
- *
- * Reloads the list of applications.
- */
-void
-gtk_app_chooser_refresh (GtkAppChooser *self)
-{
-  GTK_APP_CHOOSER_GET_IFACE (self)->refresh (self);
-}
diff --git a/gtk/gtkappchooser.h b/gtk/gtkappchooser.h
deleted file mode 100644 (file)
index 6777297..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * gtkappchooser.h: app-chooser interface
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-#ifndef __GTK_APP_CHOOSER_H__
-#define __GTK_APP_CHOOSER_H__
-
-#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
-
-#include <glib.h>
-#include <gio/gio.h>
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_APP_CHOOSER    (gtk_app_chooser_get_type ())
-#define GTK_APP_CHOOSER(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER, GtkAppChooser))
-#define GTK_IS_APP_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER))
-
-typedef struct _GtkAppChooser GtkAppChooser;
-
-GDK_AVAILABLE_IN_ALL
-GType      gtk_app_chooser_get_type         (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GAppInfo * gtk_app_chooser_get_app_info     (GtkAppChooser *self);
-GDK_AVAILABLE_IN_ALL
-char *    gtk_app_chooser_get_content_type (GtkAppChooser *self);
-GDK_AVAILABLE_IN_ALL
-void       gtk_app_chooser_refresh          (GtkAppChooser *self);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooser, g_object_unref)
-
-G_END_DECLS
-
-#endif /* __GTK_APP_CHOOSER_H__ */
-
diff --git a/gtk/gtkappchooserbutton.c b/gtk/gtkappchooserbutton.c
deleted file mode 100644 (file)
index fb82051..0000000
+++ /dev/null
@@ -1,1132 +0,0 @@
-/* gtkappchooserbutton.c: an app-chooser button
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-/**
- * GtkAppChooserButton:
- *
- * The `GtkAppChooserButton` lets the user select an application.
- *
- * ![An example GtkAppChooserButton](appchooserbutton.png)
- *
- * Initially, a `GtkAppChooserButton` selects the first application
- * in its list, which will either be the most-recently used application
- * or, if [property@Gtk.AppChooserButton:show-default-item] is %TRUE, the
- * default application.
- *
- * The list of applications shown in a `GtkAppChooserButton` includes
- * the recommended applications for the given content type. When
- * [property@Gtk.AppChooserButton:show-default-item] is set, the default
- * application is also included. To let the user chooser other applications,
- * you can set the [property@Gtk.AppChooserButton:show-dialog-item] property,
- * which allows to open a full [class@Gtk.AppChooserDialog].
- *
- * It is possible to add custom items to the list, using
- * [method@Gtk.AppChooserButton.append_custom_item]. These items cause
- * the [signal@Gtk.AppChooserButton::custom-item-activated] signal to be
- * emitted when they are selected.
- *
- * To track changes in the selected application, use the
- * [signal@Gtk.AppChooserButton::changed] signal.
- *
- * # CSS nodes
- *
- * `GtkAppChooserButton` has a single CSS node with the name “appchooserbutton”.
- */
-#include "config.h"
-
-#include "gtkappchooserbutton.h"
-
-#include "gtkappchooser.h"
-#include "gtkappchooserdialog.h"
-#include "gtkappchooserprivate.h"
-#include "gtkcelllayout.h"
-#include "gtkcellrendererpixbuf.h"
-#include "gtkcellrenderertext.h"
-#include "gtkcombobox.h"
-#include "gtkwidgetprivate.h"
-#include "gtkdialog.h"
-#include <glib/gi18n-lib.h>
-#include "gtkmarshalers.h"
-#include "gtkliststore.h"
-#include "gtkprivate.h"
-
-enum {
-  PROP_SHOW_DIALOG_ITEM = 1,
-  PROP_SHOW_DEFAULT_ITEM,
-  PROP_HEADING,
-  PROP_MODAL,
-  NUM_PROPERTIES,
-
-  PROP_CONTENT_TYPE = NUM_PROPERTIES
-};
-
-enum {
-  SIGNAL_CHANGED,
-  SIGNAL_CUSTOM_ITEM_ACTIVATED,
-  ACTIVATE,
-  NUM_SIGNALS
-};
-
-enum {
-  COLUMN_APP_INFO,
-  COLUMN_NAME,
-  COLUMN_LABEL,
-  COLUMN_ICON,
-  COLUMN_CUSTOM,
-  COLUMN_SEPARATOR,
-  NUM_COLUMNS,
-};
-
-#define CUSTOM_ITEM_OTHER_APP "gtk-internal-item-other-app"
-
-static void app_chooser_iface_init  (GtkAppChooserIface *iface);
-
-static void real_insert_custom_item (GtkAppChooserButton *self,
-                                     const char          *name,
-                                     const char          *label,
-                                     GIcon               *icon,
-                                     gboolean             custom,
-                                     GtkTreeIter         *iter);
-
-static void real_insert_separator   (GtkAppChooserButton *self,
-                                     gboolean             custom,
-                                     GtkTreeIter         *iter);
-
-static guint signals[NUM_SIGNALS] = { 0, };
-static GParamSpec *properties[NUM_PROPERTIES];
-
-typedef struct _GtkAppChooserButtonClass   GtkAppChooserButtonClass;
-
-struct _GtkAppChooserButton {
-  GtkWidget parent_instance;
-
-  GtkWidget *combobox;
-  GtkListStore *store;
-
-  char *content_type;
-  char *heading;
-  int last_active;
-  gboolean show_dialog_item;
-  gboolean show_default_item;
-  gboolean modal;
-
-  GHashTable *custom_item_names;
-};
-
-struct _GtkAppChooserButtonClass {
-  GtkWidgetClass parent_class;
-
-  void (* changed)               (GtkAppChooserButton *self);
-  void (* custom_item_activated) (GtkAppChooserButton *self,
-                                  const char *item_name);
-  void (* activate)              (GtkAppChooserButton *self);
-};
-
-G_DEFINE_TYPE_WITH_CODE (GtkAppChooserButton, gtk_app_chooser_button, GTK_TYPE_WIDGET,
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
-                                                app_chooser_iface_init));
-
-static gboolean
-row_separator_func (GtkTreeModel *model,
-                    GtkTreeIter  *iter,
-                    gpointer      user_data)
-{
-  gboolean separator;
-
-  gtk_tree_model_get (model, iter,
-                      COLUMN_SEPARATOR, &separator,
-                      -1);
-
-  return separator;
-}
-
-static void
-get_first_iter (GtkListStore *store,
-                GtkTreeIter  *iter)
-{
-  GtkTreeIter iter2;
-
-  if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), iter))
-    {
-      /* the model is empty, append */
-      gtk_list_store_append (store, iter);
-    }
-  else
-    {
-      gtk_list_store_insert_before (store, &iter2, iter);
-      *iter = iter2;
-    }
-}
-
-typedef struct {
-  GtkAppChooserButton *self;
-  GAppInfo *info;
-  int active_index;
-} SelectAppData;
-
-static void
-select_app_data_free (SelectAppData *data)
-{
-  g_clear_object (&data->self);
-  g_clear_object (&data->info);
-
-  g_slice_free (SelectAppData, data);
-}
-
-static gboolean
-select_application_func_cb (GtkTreeModel *model,
-                            GtkTreePath  *path,
-                            GtkTreeIter  *iter,
-                            gpointer      user_data)
-{
-  SelectAppData *data = user_data;
-  GtkAppChooserButton *self = data->self;
-  GAppInfo *app_to_match = data->info;
-  GAppInfo *app = NULL;
-  gboolean custom;
-  gboolean result;
-
-  gtk_tree_model_get (model, iter,
-                      COLUMN_APP_INFO, &app,
-                      COLUMN_CUSTOM, &custom,
-                      -1);
-
-  /* custom items are always after GAppInfos, so iterating further here
-   * is just useless.
-   */
-  if (custom)
-    result = TRUE;
-  else if (g_app_info_equal (app, app_to_match))
-    {
-      gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), iter);
-      result = TRUE;
-    }
-  else
-    result = FALSE;
-
-  g_object_unref (app);
-
-  return result;
-}
-
-static void
-gtk_app_chooser_button_select_application (GtkAppChooserButton *self,
-                                           GAppInfo            *info)
-{
-  SelectAppData *data;
-
-  data = g_slice_new0 (SelectAppData);
-  data->self = g_object_ref (self);
-  data->info = g_object_ref (info);
-
-  gtk_tree_model_foreach (GTK_TREE_MODEL (self->store),
-                          select_application_func_cb, data);
-
-  select_app_data_free (data);
-}
-
-static void
-other_application_dialog_response_cb (GtkDialog *dialog,
-                                      int        response_id,
-                                      gpointer   user_data)
-{
-  GtkAppChooserButton *self = user_data;
-  GAppInfo *info;
-
-  if (response_id != GTK_RESPONSE_OK)
-    {
-      /* reset the active item, otherwise we are stuck on
-       * 'Other application…'
-       */
-      gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), self->last_active);
-      gtk_window_destroy (GTK_WINDOW (dialog));
-      return;
-    }
-
-  info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog));
-
-  gtk_window_destroy (GTK_WINDOW (dialog));
-
-  /* refresh the combobox to get the new application */
-  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-  gtk_app_chooser_button_select_application (self, info);
-
-  g_object_unref (info);
-}
-
-static void
-other_application_item_activated_cb (GtkAppChooserButton *self)
-{
-  GtkWidget *dialog, *widget;
-  GtkRoot *root;
-
-  root = gtk_widget_get_root (GTK_WIDGET (self));
-  dialog = gtk_app_chooser_dialog_new_for_content_type (GTK_WINDOW (root),
-                                                        GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                        self->content_type);
-  gtk_window_set_modal (GTK_WINDOW (dialog), self->modal | gtk_window_get_modal (GTK_WINDOW (root)));
-  gtk_app_chooser_dialog_set_heading (GTK_APP_CHOOSER_DIALOG (dialog), self->heading);
-
-  widget = gtk_app_chooser_dialog_get_widget (GTK_APP_CHOOSER_DIALOG (dialog));
-  g_object_set (widget,
-                "show-fallback", TRUE,
-                "show-other", TRUE,
-                NULL);
-  gtk_widget_show (dialog);
-
-  g_signal_connect (dialog, "response",
-                    G_CALLBACK (other_application_dialog_response_cb), self);
-}
-
-static void
-gtk_app_chooser_button_ensure_dialog_item (GtkAppChooserButton *self,
-                                           GtkTreeIter         *prev_iter)
-{
-  GtkTreeIter iter, iter2;
-
-  if (!self->show_dialog_item || !self->content_type)
-    return;
-
-  if (prev_iter == NULL)
-    gtk_list_store_append (self->store, &iter);
-  else
-    gtk_list_store_insert_after (self->store, &iter, prev_iter);
-
-  real_insert_separator (self, FALSE, &iter);
-  iter2 = iter;
-
-  gtk_list_store_insert_after (self->store, &iter, &iter2);
-  real_insert_custom_item (self, CUSTOM_ITEM_OTHER_APP,
-                           _("Other application…"), NULL,
-                           FALSE, &iter);
-}
-
-static void
-insert_one_application (GtkAppChooserButton *self,
-                        GAppInfo            *app,
-                        GtkTreeIter         *iter)
-{
-  GIcon *icon;
-
-  icon = g_app_info_get_icon (app);
-
-  if (icon == NULL)
-    icon = g_themed_icon_new ("application-x-executable");
-  else
-    g_object_ref (icon);
-
-  gtk_list_store_set (self->store, iter,
-                      COLUMN_APP_INFO, app,
-                      COLUMN_LABEL, g_app_info_get_name (app),
-                      COLUMN_ICON, icon,
-                      COLUMN_CUSTOM, FALSE,
-                      -1);
-
-  g_object_unref (icon);
-}
-
-static void
-gtk_app_chooser_button_populate (GtkAppChooserButton *self)
-{
-  GList *recommended_apps = NULL, *l;
-  GAppInfo *app, *default_app = NULL;
-  GtkTreeIter iter, iter2;
-  gboolean cycled_recommended;
-
-#ifndef G_OS_WIN32
-  if (self->content_type)
-    recommended_apps = g_app_info_get_recommended_for_type (self->content_type);
-#endif
-  cycled_recommended = FALSE;
-
-  if (self->show_default_item)
-    {
-      if (self->content_type)
-        default_app = g_app_info_get_default_for_type (self->content_type, FALSE);
-
-      if (default_app != NULL)
-        {
-          get_first_iter (self->store, &iter);
-          cycled_recommended = TRUE;
-
-          insert_one_application (self, default_app, &iter);
-
-          g_object_unref (default_app);
-        }
-    }
-
-  for (l = recommended_apps; l != NULL; l = l->next)
-    {
-      app = l->data;
-
-      if (default_app != NULL && g_app_info_equal (app, default_app))
-        continue;
-
-      if (cycled_recommended)
-        {
-          gtk_list_store_insert_after (self->store, &iter2, &iter);
-          iter = iter2;
-        }
-      else
-        {
-          get_first_iter (self->store, &iter);
-          cycled_recommended = TRUE;
-        }
-
-      insert_one_application (self, app, &iter);
-    }
-
-  if (recommended_apps != NULL)
-    g_list_free_full (recommended_apps, g_object_unref);
-
-  if (!cycled_recommended)
-    gtk_app_chooser_button_ensure_dialog_item (self, NULL);
-  else
-    gtk_app_chooser_button_ensure_dialog_item (self, &iter);
-
-  gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), 0);
-}
-
-static void
-gtk_app_chooser_button_build_ui (GtkAppChooserButton *self)
-{
-  GtkCellRenderer *cell;
-  GtkCellArea *area;
-
-  gtk_combo_box_set_model (GTK_COMBO_BOX (self->combobox),
-                           GTK_TREE_MODEL (self->store));
-
-  area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (self->combobox));
-
-  gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (self->combobox),
-                                        row_separator_func, NULL, NULL);
-
-  cell = gtk_cell_renderer_pixbuf_new ();
-  gtk_cell_area_add_with_properties (area, cell,
-                                     "align", FALSE,
-                                     "expand", FALSE,
-                                     "fixed-size", FALSE,
-                                     NULL);
-  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell,
-                                  "gicon", COLUMN_ICON,
-                                  NULL);
-
-  cell = gtk_cell_renderer_text_new ();
-  gtk_cell_area_add_with_properties (area, cell,
-                                     "align", FALSE,
-                                     "expand", TRUE,
-                                     NULL);
-  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell,
-                                  "text", COLUMN_LABEL,
-                                  NULL);
-
-  gtk_app_chooser_button_populate (self);
-}
-
-static void
-gtk_app_chooser_button_remove_non_custom (GtkAppChooserButton *self)
-{
-  GtkTreeModel *model;
-  GtkTreeIter iter;
-  gboolean custom, res;
-
-  model = GTK_TREE_MODEL (self->store);
-
-  if (!gtk_tree_model_get_iter_first (model, &iter))
-    return;
-
-  do {
-    gtk_tree_model_get (model, &iter,
-                        COLUMN_CUSTOM, &custom,
-                        -1);
-    if (custom)
-      res = gtk_tree_model_iter_next (model, &iter);
-    else
-      res = gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
-  } while (res);
-}
-
-static void
-gtk_app_chooser_button_changed (GtkComboBox *object,
-                                gpointer     user_data)
-{
-  GtkAppChooserButton *self = user_data;
-  GtkTreeIter iter;
-  char *name = NULL;
-  gboolean custom;
-  GQuark name_quark;
-
-  if (!gtk_combo_box_get_active_iter (object, &iter))
-    return;
-
-  gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
-                      COLUMN_NAME, &name,
-                      COLUMN_CUSTOM, &custom,
-                      -1);
-
-  if (name != NULL)
-    {
-      if (custom)
-        {
-          name_quark = g_quark_from_string (name);
-          g_signal_emit (self, signals[SIGNAL_CUSTOM_ITEM_ACTIVATED], name_quark, name);
-          self->last_active = gtk_combo_box_get_active (object);
-        }
-      else
-        {
-          /* trigger the dialog internally */
-          other_application_item_activated_cb (self);
-        }
-
-      g_free (name);
-    }
-  else
-    self->last_active = gtk_combo_box_get_active (object);
-
-  g_signal_emit (self, signals[SIGNAL_CHANGED], 0);
-}
-
-static void
-gtk_app_chooser_button_refresh (GtkAppChooser *object)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object);
-
-  gtk_app_chooser_button_remove_non_custom (self);
-  gtk_app_chooser_button_populate (self);
-}
-
-static GAppInfo *
-gtk_app_chooser_button_get_app_info (GtkAppChooser *object)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object);
-  GtkTreeIter iter;
-  GAppInfo *info;
-
-  if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->combobox), &iter))
-    return NULL;
-
-  gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
-                      COLUMN_APP_INFO, &info,
-                      -1);
-
-  return info;
-}
-
-static void
-gtk_app_chooser_button_constructed (GObject *obj)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
-
-  if (G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed != NULL)
-    G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed (obj);
-
-  gtk_app_chooser_button_build_ui (self);
-}
-
-static void
-gtk_app_chooser_button_set_property (GObject      *obj,
-                                     guint         property_id,
-                                     const GValue *value,
-                                     GParamSpec   *pspec)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
-
-  switch (property_id)
-    {
-    case PROP_CONTENT_TYPE:
-      self->content_type = g_value_dup_string (value);
-      break;
-    case PROP_SHOW_DIALOG_ITEM:
-      gtk_app_chooser_button_set_show_dialog_item (self, g_value_get_boolean (value));
-      break;
-    case PROP_SHOW_DEFAULT_ITEM:
-      gtk_app_chooser_button_set_show_default_item (self, g_value_get_boolean (value));
-      break;
-    case PROP_HEADING:
-      gtk_app_chooser_button_set_heading (self, g_value_get_string (value));
-      break;
-    case PROP_MODAL:
-      gtk_app_chooser_button_set_modal (self, g_value_get_boolean (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_app_chooser_button_get_property (GObject    *obj,
-                                     guint       property_id,
-                                     GValue     *value,
-                                     GParamSpec *pspec)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
-
-  switch (property_id)
-    {
-    case PROP_CONTENT_TYPE:
-      g_value_set_string (value, self->content_type);
-      break;
-    case PROP_SHOW_DIALOG_ITEM:
-      g_value_set_boolean (value, self->show_dialog_item);
-      break;
-    case PROP_SHOW_DEFAULT_ITEM:
-      g_value_set_boolean (value, self->show_default_item);
-      break;
-    case PROP_HEADING:
-      g_value_set_string (value, self->heading);
-      break;
-    case PROP_MODAL:
-      g_value_set_boolean (value, self->modal);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_app_chooser_button_finalize (GObject *obj)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj);
-
-  g_hash_table_destroy (self->custom_item_names);
-  g_free (self->content_type);
-  g_free (self->heading);
-  g_object_unref (self->store);
-  gtk_widget_unparent (self->combobox);
-
-  G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->finalize (obj);
-}
-
-static void
-gtk_app_chooser_button_measure (GtkWidget       *widget,
-                                GtkOrientation  orientation,
-                                int             for_size,
-                                int            *minimum,
-                                int            *natural,
-                                int            *minimum_baseline,
-                                int            *natural_baseline)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget);
-
-  gtk_widget_measure (self->combobox, orientation, for_size,
-                      minimum, natural,
-                      minimum_baseline, natural_baseline);
-}
-
-static void
-gtk_app_chooser_button_size_allocate (GtkWidget *widget,
-                                      int        width,
-                                      int        height,
-                                      int        baseline)
-{
-  GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget);
-
-  gtk_widget_size_allocate (self->combobox, &(GtkAllocation){0, 0, width, height}, baseline);
-}
-
-static void
-app_chooser_iface_init (GtkAppChooserIface *iface)
-{
-  iface->get_app_info = gtk_app_chooser_button_get_app_info;
-  iface->refresh = gtk_app_chooser_button_refresh;
-}
-
-static void
-gtk_app_chooser_button_activate (GtkAppChooserButton *self)
-{
-  gtk_widget_activate (self->combobox);
-}
-
-static void
-gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass)
-{
-  GObjectClass *oclass = G_OBJECT_CLASS (klass);
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
-  oclass->set_property = gtk_app_chooser_button_set_property;
-  oclass->get_property = gtk_app_chooser_button_get_property;
-  oclass->finalize = gtk_app_chooser_button_finalize;
-  oclass->constructed = gtk_app_chooser_button_constructed;
-
-  widget_class->measure = gtk_app_chooser_button_measure;
-  widget_class->size_allocate = gtk_app_chooser_button_size_allocate;
-  widget_class->grab_focus = gtk_widget_grab_focus_child;
-  widget_class->focus = gtk_widget_focus_child;
-
-  klass->activate = gtk_app_chooser_button_activate;
-
-  g_object_class_override_property (oclass, PROP_CONTENT_TYPE, "content-type");
-
-  /**
-   * GtkAppChooserButton:show-dialog-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_dialog_item org.gtk.Property.set=gtk_app_chooser_button_set_show_dialog_item)
-   *
-   * Determines whether the dropdown menu shows an item to open
-   * a `GtkAppChooserDialog`.
-   */
-  properties[PROP_SHOW_DIALOG_ITEM] =
-    g_param_spec_boolean ("show-dialog-item", NULL, NULL,
-                          FALSE,
-                          G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
-
-  /**
-   * GtkAppChooserButton:show-default-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_default_item org.gtk.Property.set=gtk_app_chooser_button_set_show_default_item)
-   *
-   * Determines whether the dropdown menu shows the default application
-   * on top for the provided content type.
-   */
-  properties[PROP_SHOW_DEFAULT_ITEM] =
-    g_param_spec_boolean ("show-default-item", NULL, NULL,
-                          FALSE,
-                          G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
-
-  /**
-   * GtkAppChooserButton:heading: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_heading org.gtk.Property.set=gtk_app_chooser_button_set_heading)
-   *
-   * The text to show at the top of the dialog that can be
-   * opened from the button.
-   *
-   * The string may contain Pango markup.
-   */
-  properties[PROP_HEADING] =
-    g_param_spec_string ("heading", NULL, NULL,
-                         NULL,
-                         G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
-
-  /**
-   * GtkAppChooserButton:modal: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_modal org.gtk.Property.set=gtk_app_chooser_button_set_modal)
-   *
-   * Whether the app chooser dialog should be modal.
-   */
-  properties[PROP_MODAL] =
-    g_param_spec_boolean ("modal", NULL, NULL,
-                          TRUE,
-                          G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
-
-  /**
-   * GtkAppChooserButton::changed:
-   * @self: the object which received the signal
-   *
-   * Emitted when the active application changes.
-   */
-  signals[SIGNAL_CHANGED] =
-    g_signal_new (I_("changed"),
-                  G_OBJECT_CLASS_TYPE (klass),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (GtkAppChooserButtonClass, changed),
-                  NULL, NULL,
-                  NULL,
-                  G_TYPE_NONE, 0);
-
-
-  /**
-   * GtkAppChooserButton::custom-item-activated:
-   * @self: the object which received the signal
-   * @item_name: the name of the activated item
-   *
-   * Emitted when a custom item is activated.
-   *
-   * Use [method@Gtk.AppChooserButton.append_custom_item],
-   * to add custom items.
-   */
-  signals[SIGNAL_CUSTOM_ITEM_ACTIVATED] =
-    g_signal_new (I_("custom-item-activated"),
-                  GTK_TYPE_APP_CHOOSER_BUTTON,
-                  G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
-                  G_STRUCT_OFFSET (GtkAppChooserButtonClass, custom_item_activated),
-                  NULL, NULL,
-                  NULL,
-                  G_TYPE_NONE,
-                  1, G_TYPE_STRING);
-
-  /**
-   * GtkAppChooserButton::activate:
-   * @widget: the object which received the signal.
-   *
-   * Emitted to when the button is activated.
-   *
-   * The `::activate` signal on `GtkAppChooserButton` is an action signal and
-   * emitting it causes the button to pop up its dialog.
-   *
-   * Since: 4.4
-   */
-  signals[ACTIVATE] =
-      g_signal_new (I_ ("activate"),
-                    G_OBJECT_CLASS_TYPE (oclass),
-                    G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-                    G_STRUCT_OFFSET (GtkAppChooserButtonClass, activate),
-                    NULL, NULL,
-                    NULL,
-                    G_TYPE_NONE, 0);
-
-  gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE]);
-
-
-  gtk_widget_class_set_css_name (widget_class, I_("appchooserbutton"));
-}
-
-static void
-gtk_app_chooser_button_init (GtkAppChooserButton *self)
-{
-  self->modal = TRUE;
-
-  self->custom_item_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-  self->store = gtk_list_store_new (NUM_COLUMNS,
-                                    G_TYPE_APP_INFO,
-                                    G_TYPE_STRING, /* name */
-                                    G_TYPE_STRING, /* label */
-                                    G_TYPE_ICON,
-                                    G_TYPE_BOOLEAN, /* separator */
-                                    G_TYPE_BOOLEAN); /* custom */
-  self->combobox = gtk_combo_box_new_with_model (GTK_TREE_MODEL (self->store));
-  gtk_widget_set_parent (self->combobox, GTK_WIDGET (self));
-
-  g_signal_connect (self->combobox, "changed",
-                    G_CALLBACK (gtk_app_chooser_button_changed), self);
-}
-
-static gboolean
-app_chooser_button_iter_from_custom_name (GtkAppChooserButton *self,
-                                          const char          *name,
-                                          GtkTreeIter         *set_me)
-{
-  GtkTreeIter iter;
-  char *custom_name = NULL;
-
-  if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter))
-    return FALSE;
-
-  do {
-    gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter,
-                        COLUMN_NAME, &custom_name,
-                        -1);
-
-    if (g_strcmp0 (custom_name, name) == 0)
-      {
-        g_free (custom_name);
-        *set_me = iter;
-
-        return TRUE;
-      }
-
-    g_free (custom_name);
-  } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter));
-
-  return FALSE;
-}
-
-static void
-real_insert_custom_item (GtkAppChooserButton *self,
-                         const char          *name,
-                         const char          *label,
-                         GIcon               *icon,
-                         gboolean             custom,
-                         GtkTreeIter         *iter)
-{
-  if (custom)
-    {
-      if (g_hash_table_lookup (self->custom_item_names, name) != NULL)
-        {
-          g_warning ("Attempting to add custom item %s to GtkAppChooserButton, "
-                     "when there's already an item with the same name", name);
-          return;
-        }
-
-      g_hash_table_insert (self->custom_item_names,
-                           g_strdup (name), GINT_TO_POINTER (1));
-    }
-
-  gtk_list_store_set (self->store, iter,
-                      COLUMN_NAME, name,
-                      COLUMN_LABEL, label,
-                      COLUMN_ICON, icon,
-                      COLUMN_CUSTOM, custom,
-                      COLUMN_SEPARATOR, FALSE,
-                      -1);
-}
-
-static void
-real_insert_separator (GtkAppChooserButton *self,
-                       gboolean             custom,
-                       GtkTreeIter         *iter)
-{
-  gtk_list_store_set (self->store, iter,
-                      COLUMN_CUSTOM, custom,
-                      COLUMN_SEPARATOR, TRUE,
-                      -1);
-}
-
-/**
- * gtk_app_chooser_button_new:
- * @content_type: the content type to show applications for
- *
- * Creates a new `GtkAppChooserButton` for applications
- * that can handle content of the given type.
- *
- * Returns: a newly created `GtkAppChooserButton`
- */
-GtkWidget *
-gtk_app_chooser_button_new (const char *content_type)
-{
-  g_return_val_if_fail (content_type != NULL, NULL);
-
-  return g_object_new (GTK_TYPE_APP_CHOOSER_BUTTON,
-                       "content-type", content_type,
-                       NULL);
-}
-
-/**
- * gtk_app_chooser_button_append_separator:
- * @self: a `GtkAppChooserButton`
- *
- * Appends a separator to the list of applications that is shown
- * in the popup.
- */
-void
-gtk_app_chooser_button_append_separator (GtkAppChooserButton *self)
-{
-  GtkTreeIter iter;
-
-  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
-
-  gtk_list_store_append (self->store, &iter);
-  real_insert_separator (self, TRUE, &iter);
-}
-
-/**
- * gtk_app_chooser_button_append_custom_item:
- * @self: a `GtkAppChooserButton`
- * @name: the name of the custom item
- * @label: the label for the custom item
- * @icon: the icon for the custom item
- *
- * Appends a custom item to the list of applications that is shown
- * in the popup.
- *
- * The item name must be unique per-widget. Clients can use the
- * provided name as a detail for the
- * [signal@Gtk.AppChooserButton::custom-item-activated] signal, to add a
- * callback for the activation of a particular custom item in the list.
- *
- * See also [method@Gtk.AppChooserButton.append_separator].
- */
-void
-gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self,
-                                           const char          *name,
-                                           const char          *label,
-                                           GIcon               *icon)
-{
-  GtkTreeIter iter;
-
-  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
-  g_return_if_fail (name != NULL);
-
-  gtk_list_store_append (self->store, &iter);
-  real_insert_custom_item (self, name, label, icon, TRUE, &iter);
-}
-
-/**
- * gtk_app_chooser_button_set_active_custom_item:
- * @self: a `GtkAppChooserButton`
- * @name: the name of the custom item
- *
- * Selects a custom item.
- *
- * See [method@Gtk.AppChooserButton.append_custom_item].
- *
- * Use [method@Gtk.AppChooser.refresh] to bring the selection
- * to its initial state.
- */
-void
-gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self,
-                                               const char          *name)
-{
-  GtkTreeIter iter;
-
-  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
-  g_return_if_fail (name != NULL);
-
-  if (!g_hash_table_contains (self->custom_item_names, name) ||
-      !app_chooser_button_iter_from_custom_name (self, name, &iter))
-    {
-      g_warning ("Can't find the item named %s in the app chooser.", name);
-      return;
-    }
-
-  gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), &iter);
-}
-
-/**
- * gtk_app_chooser_button_get_show_dialog_item: (attributes org.gtk.Method.get_property=show-dialog-item)
- * @self: a `GtkAppChooserButton`
- *
- * Returns whether the dropdown menu shows an item
- * for a `GtkAppChooserDialog`.
- *
- * Returns: the value of [property@Gtk.AppChooserButton:show-dialog-item]
- */
-gboolean
-gtk_app_chooser_button_get_show_dialog_item (GtkAppChooserButton *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE);
-
-  return self->show_dialog_item;
-}
-
-/**
- * gtk_app_chooser_button_set_show_dialog_item: (attributes org.gtk.Method.set_property=show-dialog-item)
- * @self: a `GtkAppChooserButton`
- * @setting: the new value for [property@Gtk.AppChooserButton:show-dialog-item]
- *
- * Sets whether the dropdown menu of this button should show an
- * entry to trigger a `GtkAppChooserDialog`.
- */
-void
-gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self,
-                                             gboolean             setting)
-{
-  if (self->show_dialog_item != setting)
-    {
-      self->show_dialog_item = setting;
-
-      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DIALOG_ITEM]);
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_button_get_show_default_item: (attributes org.gtk.Method.get_property=show-default-item)
- * @self: a `GtkAppChooserButton`
- *
- * Returns whether the dropdown menu should show the default
- * application at the top.
- *
- * Returns: the value of [property@Gtk.AppChooserButton:show-default-item]
- */
-gboolean
-gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE);
-
-  return self->show_default_item;
-}
-
-/**
- * gtk_app_chooser_button_set_show_default_item: (attributes org.gtk.Method.set_property=show-default-item)
- * @self: a `GtkAppChooserButton`
- * @setting: the new value for [property@Gtk.AppChooserButton:show-default-item]
- *
- * Sets whether the dropdown menu of this button should show the
- * default application for the given content type at top.
- */
-void
-gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self,
-                                              gboolean             setting)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
-
-  if (self->show_default_item != setting)
-    {
-      self->show_default_item = setting;
-
-      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DEFAULT_ITEM]);
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_button_set_heading: (attributes org.gtk.Method.set_property=heading)
- * @self: a `GtkAppChooserButton`
- * @heading: a string containing Pango markup
- *
- * Sets the text to display at the top of the dialog.
- *
- * If the heading is not set, the dialog displays a default text.
- */
-void
-gtk_app_chooser_button_set_heading (GtkAppChooserButton *self,
-                                    const char          *heading)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
-
-  g_free (self->heading);
-  self->heading = g_strdup (heading);
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADING]);
-}
-
-/**
- * gtk_app_chooser_button_get_heading: (attributes org.gtk.Method.get_property=heading)
- * @self: a `GtkAppChooserButton`
- *
- * Returns the text to display at the top of the dialog.
- *
- * Returns: (nullable): the text to display at the top of the dialog,
- *   or %NULL, in which case a default text is displayed
- */
-const char *
-gtk_app_chooser_button_get_heading (GtkAppChooserButton *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), NULL);
-
-  return self->heading;
-}
-
-/**
- * gtk_app_chooser_button_set_modal: (attributes org.gtk.Method.set_property=modal)
- * @self: a `GtkAppChooserButton`
- * @modal: %TRUE to make the dialog modal
- *
- * Sets whether the dialog should be modal.
- */
-void
-gtk_app_chooser_button_set_modal (GtkAppChooserButton *self,
-                                  gboolean             modal)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self));
-
-  if (self->modal == modal)
-    return;
-
-  self->modal = modal;
-
-  g_object_notify (G_OBJECT (self), "modal");
-}
-
-/**
- * gtk_app_chooser_button_get_modal: (attributes org.gtk.Method.get_property=modal)
- * @self: a `GtkAppChooserButton`
- *
- * Gets whether the dialog is modal.
- *
- * Returns: %TRUE if the dialog is modal
- */
-gboolean
-gtk_app_chooser_button_get_modal (GtkAppChooserButton *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE);
-
-  return self->modal;
-}
-
diff --git a/gtk/gtkappchooserbutton.h b/gtk/gtkappchooserbutton.h
deleted file mode 100644 (file)
index 493c5e3..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * gtkappchooserbutton.h: an app-chooser button
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-#ifndef __GTK_APP_CHOOSER_BUTTON_H__
-#define __GTK_APP_CHOOSER_BUTTON_H__
-
-#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
-
-#include <gtk/gtkwidget.h>
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_APP_CHOOSER_BUTTON            (gtk_app_chooser_button_get_type ())
-#define GTK_APP_CHOOSER_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_BUTTON, GtkAppChooserButton))
-#define GTK_IS_APP_CHOOSER_BUTTON(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_BUTTON))
-
-typedef struct _GtkAppChooserButton        GtkAppChooserButton;
-
-GDK_AVAILABLE_IN_ALL
-GType       gtk_app_chooser_button_get_type           (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GtkWidget * gtk_app_chooser_button_new                (const char          *content_type);
-
-GDK_AVAILABLE_IN_ALL
-void        gtk_app_chooser_button_append_separator   (GtkAppChooserButton *self);
-GDK_AVAILABLE_IN_ALL
-void        gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self,
-                                                       const char          *name,
-                                                       const char          *label,
-                                                       GIcon               *icon);
-GDK_AVAILABLE_IN_ALL
-void     gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self,
-                                                        const char          *name);
-
-GDK_AVAILABLE_IN_ALL
-void     gtk_app_chooser_button_set_show_dialog_item  (GtkAppChooserButton *self,
-                                                       gboolean             setting);
-GDK_AVAILABLE_IN_ALL
-gboolean gtk_app_chooser_button_get_show_dialog_item  (GtkAppChooserButton *self);
-GDK_AVAILABLE_IN_ALL
-void     gtk_app_chooser_button_set_heading           (GtkAppChooserButton *self,
-                                                       const char          *heading);
-GDK_AVAILABLE_IN_ALL
-const char *
-         gtk_app_chooser_button_get_heading           (GtkAppChooserButton *self);
-GDK_AVAILABLE_IN_ALL
-void     gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self,
-                                                       gboolean             setting);
-GDK_AVAILABLE_IN_ALL
-gboolean gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self);
-
-GDK_AVAILABLE_IN_ALL
-gboolean gtk_app_chooser_button_get_modal             (GtkAppChooserButton *self);
-GDK_AVAILABLE_IN_ALL
-void     gtk_app_chooser_button_set_modal             (GtkAppChooserButton *self,
-                                                       gboolean             modal);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserButton, g_object_unref)
-
-G_END_DECLS
-
-#endif /* __GTK_APP_CHOOSER_BUTTON_H__ */
diff --git a/gtk/gtkappchooserdialog.c b/gtk/gtkappchooserdialog.c
deleted file mode 100644 (file)
index 3d1669d..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- * gtkappchooserdialog.c: an app-chooser dialog
- *
- * Copyright (C) 2004 Novell, Inc.
- * Copyright (C) 2007, 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Dave Camp <dave@novell.com>
- *          Alexander Larsson <alexl@redhat.com>
- *          Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-/**
- * GtkAppChooserDialog:
- *
- * `GtkAppChooserDialog` shows a `GtkAppChooserWidget` inside a `GtkDialog`.
- *
- * ![An example GtkAppChooserDialog](appchooserdialog.png)
- *
- * Note that `GtkAppChooserDialog` does not have any interesting methods
- * of its own. Instead, you should get the embedded `GtkAppChooserWidget`
- * using [method@Gtk.AppChooserDialog.get_widget] and call its methods if
- * the generic [iface@Gtk.AppChooser] interface is not sufficient for
- * your needs.
- *
- * To set the heading that is shown above the `GtkAppChooserWidget`,
- * use [method@Gtk.AppChooserDialog.set_heading].
- */
-#include "config.h"
-
-#include "gtkappchooserdialog.h"
-
-#include "gtkappchooser.h"
-#include "gtkappchooserprivate.h"
-
-#include "gtkmessagedialog.h"
-#include "gtksettings.h"
-#include "gtklabel.h"
-#include "gtkbox.h"
-#include "gtkbutton.h"
-#include "gtkentry.h"
-#include "gtktogglebutton.h"
-#include "gtkheaderbar.h"
-#include "gtkdialogprivate.h"
-#include "gtksearchbar.h"
-#include "gtksizegroup.h"
-
-#include <string.h>
-#include <glib/gi18n-lib.h>
-#include <gio/gio.h>
-
-typedef struct _GtkAppChooserDialogClass   GtkAppChooserDialogClass;
-
-struct _GtkAppChooserDialog {
-  GtkDialog parent;
-
-  char *content_type;
-  GFile *gfile;
-  char *heading;
-
-  GtkWidget *label;
-  GtkWidget *inner_box;
-
-  GtkWidget *open_label;
-
-  GtkWidget *search_bar;
-  GtkWidget *search_entry;
-  GtkWidget *app_chooser_widget;
-  GtkWidget *show_more_button;
-  GtkWidget *software_button;
-
-  GtkSizeGroup *buttons;
-
-  gboolean show_more_clicked;
-  gboolean dismissed;
-};
-
-struct _GtkAppChooserDialogClass {
-  GtkDialogClass parent_class;
-};
-
-enum {
-  PROP_GFILE = 1,
-  PROP_CONTENT_TYPE,
-  PROP_HEADING
-};
-
-static void gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface);
-G_DEFINE_TYPE_WITH_CODE (GtkAppChooserDialog, gtk_app_chooser_dialog, GTK_TYPE_DIALOG,
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
-                                                gtk_app_chooser_dialog_iface_init));
-
-
-static void
-add_or_find_application (GtkAppChooserDialog *self)
-{
-  GAppInfo *app;
-
-  app = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self));
-
-  if (app)
-    {
-      /* we don't care about reporting errors here */
-      if (self->content_type)
-        g_app_info_set_as_last_used_for_type (app,
-                                              self->content_type,
-                                              NULL);
-      g_object_unref (app);
-    }
-}
-
-static void
-gtk_app_chooser_dialog_response (GtkDialog *dialog,
-                                 int        response_id,
-                                 gpointer   user_data)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (dialog);
-
-  switch (response_id)
-    {
-    case GTK_RESPONSE_OK:
-      add_or_find_application (self);
-      break;
-    case GTK_RESPONSE_CANCEL:
-    case GTK_RESPONSE_DELETE_EVENT:
-      self->dismissed = TRUE;
-      break;
-    default:
-      break;
-    }
-}
-
-static void
-widget_application_selected_cb (GtkAppChooserWidget *widget,
-                                GAppInfo            *app_info,
-                                gpointer             user_data)
-{
-  gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, TRUE);
-}
-
-static void
-widget_application_activated_cb (GtkAppChooserWidget *widget,
-                                 GAppInfo            *app_info,
-                                 gpointer             user_data)
-{
-  gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK);
-}
-
-static char *
-get_extension (const char *basename)
-{
-  char *p;
-
-  p = strrchr (basename, '.');
-
-  if (p && *(p + 1) != '\0')
-    return g_strdup (p + 1);
-
-  return NULL;
-}
-
-static void
-set_dialog_properties (GtkAppChooserDialog *self)
-{
-  char *name;
-  char *extension;
-  char *description;
-  char *string;
-  gboolean unknown;
-  char *title;
-  char *subtitle;
-  gboolean use_header;
-  GtkWidget *header;
-
-  name = NULL;
-  extension = NULL;
-  description = NULL;
-  unknown = TRUE;
-
-  if (self->gfile != NULL)
-    {
-      name = g_file_get_basename (self->gfile);
-      extension = get_extension (name);
-    }
-
-  if (self->content_type)
-    {
-      description = g_content_type_get_description (self->content_type);
-      unknown = g_content_type_is_unknown (self->content_type);
-    }
-
-  title = g_strdup (_("Select Application"));
-  subtitle = NULL;
-  string = NULL;
-
-  if (name != NULL)
-    {
-      /* Translators: %s is a filename */
-      subtitle = g_strdup_printf (_("Opening “%s”."), name);
-      string = g_strdup_printf (_("No applications found for “%s”"), name);
-    }
-  else if (self->content_type)
-    {
-      /* Translators: %s is a file type description */
-      subtitle = g_strdup_printf (_("Opening “%s” files."), 
-                                  unknown ? self->content_type : description);
-      string = g_strdup_printf (_("No applications found for “%s” files"),
-                                unknown ? self->content_type : description);
-    }
-
-  g_object_get (self, "use-header-bar", &use_header, NULL); 
-  if (use_header)
-    {
-      GtkWidget *box, *label;
-
-      header = gtk_dialog_get_header_bar (GTK_DIALOG (self));
-
-      box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-      gtk_widget_set_valign (box, GTK_ALIGN_CENTER);
-
-      label = gtk_label_new (title);
-      gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
-      gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
-      gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
-      gtk_label_set_width_chars (GTK_LABEL (label), 5);
-      gtk_widget_add_css_class (label, "title");
-      gtk_widget_set_parent (label, box);
-
-      if (subtitle)
-        {
-          label = gtk_label_new (subtitle);
-          gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
-          gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
-          gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
-          gtk_widget_add_css_class (label, "subtitle");
-          gtk_widget_set_parent (label, box);
-        }
-
-      gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header), box);
-    }
-  else
-    {
-      gtk_window_set_title (GTK_WINDOW (self), _("Select Application"));
-    }
-
-  if (self->heading != NULL)
-    {
-      gtk_label_set_markup (GTK_LABEL (self->label), self->heading);
-      gtk_widget_show (self->label);
-    }
-  else
-    {
-      gtk_widget_hide (self->label);
-    }
-
-  gtk_app_chooser_widget_set_default_text (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget),
-                                           string);
-
-  g_free (title);
-  g_free (subtitle);
-  g_free (name);
-  g_free (extension);
-  g_free (description);
-  g_free (string);
-}
-
-static void
-show_more_button_clicked_cb (GtkButton *button,
-                             gpointer   user_data)
-{
-  GtkAppChooserDialog *self = user_data;
-
-  g_object_set (self->app_chooser_widget,
-                "show-recommended", TRUE,
-                "show-fallback", TRUE,
-                "show-other", TRUE,
-                NULL);
-
-  gtk_widget_hide (self->show_more_button);
-  self->show_more_clicked = TRUE;
-}
-
-static void
-widget_notify_for_button_cb (GObject    *source,
-                             GParamSpec *pspec,
-                             gpointer    user_data)
-{
-  GtkAppChooserDialog *self = user_data;
-  GtkAppChooserWidget *widget = GTK_APP_CHOOSER_WIDGET (source);
-  gboolean should_hide;
-
-  should_hide = gtk_app_chooser_widget_get_show_other (widget) ||
-    self->show_more_clicked;
-
-  if (should_hide)
-    gtk_widget_hide (self->show_more_button);
-}
-
-static void
-construct_appchooser_widget (GtkAppChooserDialog *self)
-{
-  GAppInfo *info;
-
-  /* Need to build the appchooser widget after, because of the content-type construct-only property */
-  self->app_chooser_widget = gtk_app_chooser_widget_new (self->content_type);
-  gtk_widget_set_vexpand (self->app_chooser_widget, TRUE);
-  gtk_box_append (GTK_BOX (self->inner_box), self->app_chooser_widget);
-
-  g_signal_connect (self->app_chooser_widget, "application-selected",
-                    G_CALLBACK (widget_application_selected_cb), self);
-  g_signal_connect (self->app_chooser_widget, "application-activated",
-                    G_CALLBACK (widget_application_activated_cb), self);
-  g_signal_connect (self->app_chooser_widget, "notify::show-other",
-                    G_CALLBACK (widget_notify_for_button_cb), self);
-
-  /* Add the custom button to the new appchooser */
-  gtk_box_append (GTK_BOX (self->inner_box),
-                     self->show_more_button);
-
-  gtk_box_append (GTK_BOX (self->inner_box),
-                     self->software_button);
-
-  info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget));
-  gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK, info != NULL);
-  if (info)
-    g_object_unref (info);
-
-  _gtk_app_chooser_widget_set_search_entry (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget),
-                                            GTK_EDITABLE (self->search_entry));
-
-  gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (self->search_bar),
-                                         GTK_WIDGET (self));
-}
-
-static void
-set_gfile_and_content_type (GtkAppChooserDialog *self,
-                            GFile               *file)
-{
-  GFileInfo *info;
-
-  if (file == NULL)
-    return;
-
-  self->gfile = g_object_ref (file);
-
-  info = g_file_query_info (self->gfile,
-                            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-                            0, NULL, NULL);
-  self->content_type = g_strdup (g_file_info_get_content_type (info));
-
-  g_object_unref (info);
-}
-
-static GAppInfo *
-gtk_app_chooser_dialog_get_app_info (GtkAppChooser *object)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
-
-  return gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget));
-}
-
-static void
-gtk_app_chooser_dialog_refresh (GtkAppChooser *object)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
-
-  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self->app_chooser_widget));
-}
-
-static void
-show_error_dialog (const char *primary,
-                   const char *secondary,
-                   GtkWindow   *parent)
-{
-  GtkWidget *message_dialog;
-
-  message_dialog = gtk_message_dialog_new (parent, 0,
-                                           GTK_MESSAGE_ERROR,
-                                           GTK_BUTTONS_OK,
-                                           NULL);
-  g_object_set (message_dialog,
-                "text", primary,
-                "secondary-text", secondary,
-                NULL);
-  gtk_dialog_set_default_response (GTK_DIALOG (message_dialog), GTK_RESPONSE_OK);
-
-  gtk_widget_show (message_dialog);
-
-  g_signal_connect (message_dialog, "response",
-                    G_CALLBACK (gtk_window_destroy), NULL);
-}
-
-static void
-software_button_clicked_cb (GtkButton           *button,
-                            GtkAppChooserDialog *self)
-{
-  GSubprocess *process;
-  GError *error = NULL;
-  char *option;
-
-  if (self->content_type)
-    option = g_strconcat ("--search=", self->content_type, NULL);
-  else
-    option = g_strdup ("--mode=overview");
-
-  process = g_subprocess_new (0, &error, "gnome-software", option, NULL);
-  if (!process)
-    {
-      show_error_dialog (_("Failed to start GNOME Software"),
-                         error->message, GTK_WINDOW (self));
-      g_error_free (error);
-    }
-  else
-    g_object_unref (process);
-
-  g_free (option);
-}
-
-static void
-ensure_software_button (GtkAppChooserDialog *self)
-{
-  char *path;
-
-  path = g_find_program_in_path ("gnome-software");
-  if (path != NULL)
-    gtk_widget_show (self->software_button);
-  else
-    gtk_widget_hide (self->software_button);
-
-  g_free (path);
-}
-
-static void
-setup_search (GtkAppChooserDialog *self)
-{
-  gboolean use_header;
-
-  g_object_get (self, "use-header-bar", &use_header, NULL);
-  if (use_header)
-    {
-      GtkWidget *button;
-      GtkWidget *image;
-      GtkWidget *header;
-
-      button = gtk_toggle_button_new ();
-      gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
-      image = gtk_image_new_from_icon_name ("edit-find-symbolic");
-      gtk_button_set_child (GTK_BUTTON (button), image);
-      gtk_widget_add_css_class (button, "image-button");
-      gtk_widget_remove_css_class (button, "text-button");
-
-      header = gtk_dialog_get_header_bar (GTK_DIALOG (self));
-      gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
-      gtk_size_group_add_widget (self->buttons, button);
-
-      g_object_bind_property (button, "active",
-                              self->search_bar, "search-mode-enabled",
-                              G_BINDING_BIDIRECTIONAL);
-      g_object_bind_property (self->search_entry, "sensitive",
-                              button, "sensitive",
-                              G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
-    }
-}
-
-static void
-gtk_app_chooser_dialog_constructed (GObject *object)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
-
-  if (G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed != NULL)
-    G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed (object);
-
-  construct_appchooser_widget (self);
-  set_dialog_properties (self);
-  ensure_software_button (self);
-  setup_search (self);
-}
-
-static void
-gtk_app_chooser_dialog_dispose (GObject *object)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
-  
-  g_clear_object (&self->gfile);
-
-  self->dismissed = TRUE;
-
-  G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->dispose (object);
-}
-
-static void
-gtk_app_chooser_dialog_finalize (GObject *object)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
-
-  g_free (self->content_type);
-  g_free (self->heading);
-
-  G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->finalize (object);
-}
-
-static void
-gtk_app_chooser_dialog_set_property (GObject      *object,
-                                     guint         property_id,
-                                     const GValue *value,
-                                     GParamSpec   *pspec)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
-
-  switch (property_id)
-    {
-    case PROP_GFILE:
-      set_gfile_and_content_type (self, g_value_get_object (value));
-      break;
-    case PROP_CONTENT_TYPE:
-      /* don't try to override a value previously set with the GFile */
-      if (self->content_type == NULL)
-        self->content_type = g_value_dup_string (value);
-      break;
-    case PROP_HEADING:
-      gtk_app_chooser_dialog_set_heading (self, g_value_get_string (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_app_chooser_dialog_get_property (GObject    *object,
-                                     guint       property_id,
-                                     GValue     *value,
-                                     GParamSpec *pspec)
-{
-  GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
-
-  switch (property_id)
-    {
-    case PROP_GFILE:
-      if (self->gfile != NULL)
-        g_value_set_object (value, self->gfile);
-      break;
-    case PROP_CONTENT_TYPE:
-      g_value_set_string (value, self->content_type);
-      break;
-    case PROP_HEADING:
-      g_value_set_string (value, self->heading);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface)
-{
-  iface->get_app_info = gtk_app_chooser_dialog_get_app_info;
-  iface->refresh = gtk_app_chooser_dialog_refresh;
-}
-
-static void
-gtk_app_chooser_dialog_class_init (GtkAppChooserDialogClass *klass)
-{
-  GObjectClass *gobject_class;
-  GtkWidgetClass *widget_class;
-  GParamSpec *pspec;
-
-  gobject_class = G_OBJECT_CLASS (klass);
-  widget_class = GTK_WIDGET_CLASS (klass);
-
-  gobject_class->dispose = gtk_app_chooser_dialog_dispose;
-  gobject_class->finalize = gtk_app_chooser_dialog_finalize;
-  gobject_class->set_property = gtk_app_chooser_dialog_set_property;
-  gobject_class->get_property = gtk_app_chooser_dialog_get_property;
-  gobject_class->constructed = gtk_app_chooser_dialog_constructed;
-
-  g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
-
-  /**
-   * GtkAppChooserDialog:gfile:
-   *
-   * The GFile used by the `GtkAppChooserDialog`.
-   *
-   * The dialog's `GtkAppChooserWidget` content type will
-   * be guessed from the file, if present.
-   */
-  pspec = g_param_spec_object ("gfile", NULL, NULL,
-                               G_TYPE_FILE,
-                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-                               G_PARAM_STATIC_STRINGS);
-  g_object_class_install_property (gobject_class, PROP_GFILE, pspec);
-
-  /**
-   * GtkAppChooserDialog:heading: (attributes org.gtk.Property.get=gtk_app_chooser_dialog_get_heading org.gtk.Property.set=gtk_app_chooser_dialog_set_heading)
-   *
-   * The text to show at the top of the dialog.
-   *
-   * The string may contain Pango markup.
-   */
-  pspec = g_param_spec_string ("heading", NULL, NULL,
-                               NULL,
-                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
-                               G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_property (gobject_class, PROP_HEADING, pspec);
-
-  /* Bind class to template
-   */
-  gtk_widget_class_set_template_from_resource (widget_class,
-                                              "/org/gtk/libgtk/ui/gtkappchooserdialog.ui");
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, label);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, show_more_button);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, software_button);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, inner_box);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_bar);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_entry);
-  gtk_widget_class_bind_template_child(widget_class, GtkAppChooserDialog, buttons);
-  gtk_widget_class_bind_template_callback (widget_class, show_more_button_clicked_cb);
-  gtk_widget_class_bind_template_callback (widget_class, software_button_clicked_cb);
-}
-
-static void
-gtk_app_chooser_dialog_init (GtkAppChooserDialog *self)
-{
-  gtk_widget_init_template (GTK_WIDGET (self));
-  gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (self));
-
-  /* we can't override the class signal handler here, as it's a RUN_LAST;
-   * we want our signal handler instead to be executed before any user code.
-   */
-  g_signal_connect (self, "response",
-                    G_CALLBACK (gtk_app_chooser_dialog_response), NULL);
-}
-
-static void
-set_parent_and_flags (GtkWidget      *dialog,
-                      GtkWindow      *parent,
-                      GtkDialogFlags  flags)
-{
-  if (parent != NULL)
-    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
-
-  if (flags & GTK_DIALOG_MODAL)
-    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
-
-  if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
-    gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
-}
-
-/**
- * gtk_app_chooser_dialog_new:
- * @parent: (nullable): a `GtkWindow`
- * @flags: flags for this dialog
- * @file: a `GFile`
- *
- * Creates a new `GtkAppChooserDialog` for the provided `GFile`.
- *
- * The dialog will show applications that can open the file.
- *
- * Returns: a newly created `GtkAppChooserDialog`
- */
-GtkWidget *
-gtk_app_chooser_dialog_new (GtkWindow      *parent,
-                            GtkDialogFlags  flags,
-                            GFile          *file)
-{
-  GtkWidget *retval;
-
-  g_return_val_if_fail (G_IS_FILE (file), NULL);
-
-  retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG,
-                         "gfile", file,
-                         NULL);
-
-  set_parent_and_flags (retval, parent, flags);
-
-  return retval;
-}
-
-/**
- * gtk_app_chooser_dialog_new_for_content_type:
- * @parent: (nullable): a `GtkWindow`
- * @flags: flags for this dialog
- * @content_type: a content type string
- *
- * Creates a new `GtkAppChooserDialog` for the provided content type.
- *
- * The dialog will show applications that can open the content type.
- *
- * Returns: a newly created `GtkAppChooserDialog`
- */
-GtkWidget *
-gtk_app_chooser_dialog_new_for_content_type (GtkWindow      *parent,
-                                             GtkDialogFlags  flags,
-                                             const char     *content_type)
-{
-  GtkWidget *retval;
-
-  g_return_val_if_fail (content_type != NULL, NULL);
-
-  retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG,
-                         "content-type", content_type,
-                         NULL);
-
-  set_parent_and_flags (retval, parent, flags);
-
-  return retval;
-}
-
-/**
- * gtk_app_chooser_dialog_get_widget:
- * @self: a `GtkAppChooserDialog`
- *
- * Returns the `GtkAppChooserWidget` of this dialog.
- *
- * Returns: (transfer none): the `GtkAppChooserWidget` of @self
- */
-GtkWidget *
-gtk_app_chooser_dialog_get_widget (GtkAppChooserDialog *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL);
-
-  return self->app_chooser_widget;
-}
-
-/**
- * gtk_app_chooser_dialog_set_heading: (attributes org.gtk.Method.set_property=heading)
- * @self: a `GtkAppChooserDialog`
- * @heading: a string containing Pango markup
- *
- * Sets the text to display at the top of the dialog.
- *
- * If the heading is not set, the dialog displays a default text.
- */
-void
-gtk_app_chooser_dialog_set_heading (GtkAppChooserDialog *self,
-                                    const char          *heading)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self));
-
-  g_free (self->heading);
-  self->heading = g_strdup (heading);
-
-  if (self->label)
-    {
-      if (self->heading)
-        {
-          gtk_label_set_markup (GTK_LABEL (self->label), self->heading);
-          gtk_widget_show (self->label);
-        }
-      else
-        {
-          gtk_widget_hide (self->label);
-        }
-    }
-
-  g_object_notify (G_OBJECT (self), "heading");
-}
-
-/**
- * gtk_app_chooser_dialog_get_heading: (attributes org.gtk.Method.get_property=heading)
- * @self: a `GtkAppChooserDialog`
- *
- * Returns the text to display at the top of the dialog.
- *
- * Returns: (nullable): the text to display at the top of the dialog,
- *   or %NULL, in which case a default text is displayed
- */
-const char *
-gtk_app_chooser_dialog_get_heading (GtkAppChooserDialog *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL);
-
-  return self->heading;
-}
diff --git a/gtk/gtkappchooserdialog.h b/gtk/gtkappchooserdialog.h
deleted file mode 100644 (file)
index 9f3f8c5..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * gtkappchooserdialog.h: an app-chooser dialog
- *
- * Copyright (C) 2004 Novell, Inc.
- * Copyright (C) 2007, 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Dave Camp <dave@novell.com>
- *          Alexander Larsson <alexl@redhat.com>
- *          Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-#ifndef __GTK_APP_CHOOSER_DIALOG_H__
-#define __GTK_APP_CHOOSER_DIALOG_H__
-
-#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
-
-#include <gtk/gtkdialog.h>
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_APP_CHOOSER_DIALOG            (gtk_app_chooser_dialog_get_type ())
-#define GTK_APP_CHOOSER_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_DIALOG, GtkAppChooserDialog))
-#define GTK_IS_APP_CHOOSER_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_DIALOG))
-
-typedef struct _GtkAppChooserDialog        GtkAppChooserDialog;
-
-GDK_AVAILABLE_IN_ALL
-GType         gtk_app_chooser_dialog_get_type             (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GtkWidget *   gtk_app_chooser_dialog_new                  (GtkWindow           *parent,
-                                                           GtkDialogFlags       flags,
-                                                           GFile               *file);
-GDK_AVAILABLE_IN_ALL
-GtkWidget *   gtk_app_chooser_dialog_new_for_content_type (GtkWindow           *parent,
-                                                           GtkDialogFlags       flags,
-                                                           const char          *content_type);
-
-GDK_AVAILABLE_IN_ALL
-GtkWidget *   gtk_app_chooser_dialog_get_widget           (GtkAppChooserDialog *self);
-GDK_AVAILABLE_IN_ALL
-void          gtk_app_chooser_dialog_set_heading          (GtkAppChooserDialog *self,
-                                                           const char          *heading);
-GDK_AVAILABLE_IN_ALL
-const char * gtk_app_chooser_dialog_get_heading          (GtkAppChooserDialog *self);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserDialog, g_object_unref)
-
-G_END_DECLS
-
-#endif /* __GTK_APP_CHOOSER_DIALOG_H__ */
diff --git a/gtk/gtkappchooserprivate.h b/gtk/gtkappchooserprivate.h
deleted file mode 100644 (file)
index 754619a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * gtkappchooserprivate.h: app-chooser interface
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-#ifndef __GTK_APP_CHOOSER_PRIVATE_H__
-#define __GTK_APP_CHOOSER_PRIVATE_H__
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#include "gtkappchooser.h"
-#include "gtkappchooserwidget.h"
-#include "gtkentry.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GtkAppChooserIface GtkAppChooserIface;
-typedef GtkAppChooserIface GtkAppChooserInterface;
-
-#define GTK_APP_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_APP_CHOOSER, GtkAppChooserIface))
-
-struct _GtkAppChooserIface {
-  GTypeInterface base_iface;
-
-  GAppInfo * (* get_app_info) (GtkAppChooser *object);
-  void       (* refresh)      (GtkAppChooser *object);
-};
-
-void
-_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self,
-                                          GtkEditable         *editable);
-
-
-G_END_DECLS
-
-#endif /* __GTK_APP_CHOOSER_PRIVATE_H__ */
diff --git a/gtk/gtkappchooserwidget.c b/gtk/gtkappchooserwidget.c
deleted file mode 100644 (file)
index 90915f0..0000000
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*
- * gtkappchooserwidget.c: an app-chooser widget
- *
- * Copyright (C) 2004 Novell, Inc.
- * Copyright (C) 2007, 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Dave Camp <dave@novell.com>
- *          Alexander Larsson <alexl@redhat.com>
- *          Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-#include "config.h"
-
-#include "gtkappchooserwidget.h"
-
-#include "gtkmarshalers.h"
-#include "gtkappchooserwidget.h"
-#include "gtkappchooserprivate.h"
-#include "gtkliststore.h"
-#include "gtktreeview.h"
-#include "gtktreeselection.h"
-#include "gtktreemodelsort.h"
-#include "gtkorientable.h"
-#include "gtkscrolledwindow.h"
-#include "gtklabel.h"
-#include "gtkgestureclick.h"
-#include "gtkwidgetprivate.h"
-#include "gtkprivate.h"
-
-#include <string.h>
-#include <glib/gi18n-lib.h>
-#include <gio/gio.h>
-
-/**
- * GtkAppChooserWidget:
- *
- * `GtkAppChooserWidget` is a widget for selecting applications.
- *
- * It is the main building block for [class@Gtk.AppChooserDialog].
- * Most applications only need to use the latter; but you can use
- * this widget as part of a larger widget if you have special needs.
- *
- * `GtkAppChooserWidget` offers detailed control over what applications
- * are shown, using the
- * [property@Gtk.AppChooserWidget:show-default],
- * [property@Gtk.AppChooserWidget:show-recommended],
- * [property@Gtk.AppChooserWidget:show-fallback],
- * [property@Gtk.AppChooserWidget:show-other] and
- * [property@Gtk.AppChooserWidget:show-all] properties. See the
- * [iface@Gtk.AppChooser] documentation for more information about these
- * groups of applications.
- *
- * To keep track of the selected application, use the
- * [signal@Gtk.AppChooserWidget::application-selected] and
- * [signal@Gtk.AppChooserWidget::application-activated] signals.
- *
- * # CSS nodes
- *
- * `GtkAppChooserWidget` has a single CSS node with name appchooser.
- */
-
-typedef struct _GtkAppChooserWidgetClass   GtkAppChooserWidgetClass;
-
-struct _GtkAppChooserWidget {
-  GtkWidget parent_instance;
-
-  GAppInfo *selected_app_info;
-
-  GtkWidget *overlay;
-
-  char *content_type;
-  char *default_text;
-
-  guint show_default     : 1;
-  guint show_recommended : 1;
-  guint show_fallback    : 1;
-  guint show_other       : 1;
-  guint show_all         : 1;
-
-  GtkWidget *program_list;
-  GtkListStore *program_list_store;
-  GtkWidget *no_apps_label;
-  GtkWidget *no_apps;
-
-  GtkTreeViewColumn *column;
-  GtkCellRenderer *padding_renderer;
-  GtkCellRenderer *secondary_padding;
-
-  GAppInfoMonitor *monitor;
-
-  GtkWidget *popup_menu;
-};
-
-struct _GtkAppChooserWidgetClass {
-  GtkWidgetClass parent_class;
-
-  void (* application_selected)  (GtkAppChooserWidget *self,
-                                  GAppInfo            *app_info);
-
-  void (* application_activated) (GtkAppChooserWidget *self,
-                                  GAppInfo            *app_info);
-};
-
-enum {
-  COLUMN_APP_INFO,
-  COLUMN_GICON,
-  COLUMN_NAME,
-  COLUMN_DESC,
-  COLUMN_EXEC,
-  COLUMN_DEFAULT,
-  COLUMN_HEADING,
-  COLUMN_HEADING_TEXT,
-  COLUMN_RECOMMENDED,
-  COLUMN_FALLBACK,
-  NUM_COLUMNS
-};
-
-
-enum {
-  PROP_CONTENT_TYPE = 1,
-  PROP_GFILE,
-  PROP_SHOW_DEFAULT,
-  PROP_SHOW_RECOMMENDED,
-  PROP_SHOW_FALLBACK,
-  PROP_SHOW_OTHER,
-  PROP_SHOW_ALL,
-  PROP_DEFAULT_TEXT,
-  N_PROPERTIES
-};
-
-enum {
-  SIGNAL_APPLICATION_SELECTED,
-  SIGNAL_APPLICATION_ACTIVATED,
-  N_SIGNALS
-};
-
-static guint signals[N_SIGNALS] = { 0, };
-
-static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_WIDGET,
-                         G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER,
-                                                gtk_app_chooser_widget_iface_init));
-
-static void
-refresh_and_emit_app_selected (GtkAppChooserWidget *self,
-                               GtkTreeSelection    *selection)
-{
-  GtkTreeModel *model;
-  GtkTreeIter iter;
-  GAppInfo *info = NULL;
-  gboolean should_emit = FALSE;
-
-  if (gtk_tree_selection_get_selected (selection, &model, &iter))
-    gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1);
-
-  if (info == NULL)
-    return;
-
-  if (self->selected_app_info)
-    {
-      if (!g_app_info_equal (self->selected_app_info, info))
-        {
-          should_emit = TRUE;
-          g_set_object (&self->selected_app_info, info);
-        }
-    }
-  else
-    {
-      should_emit = TRUE;
-      g_set_object (&self->selected_app_info, info);
-    }
-
-  g_object_unref (info);
-
-  if (should_emit)
-    g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0,
-                   self->selected_app_info);
-}
-
-static gboolean
-path_is_heading (GtkTreeView *view,
-                 GtkTreePath *path)
-{
-  GtkTreeIter iter;
-  GtkTreeModel *model;
-  gboolean res;
-
-  model = gtk_tree_view_get_model (view);
-  gtk_tree_model_get_iter (model, &iter, path);
-  gtk_tree_model_get (model, &iter,
-                      COLUMN_HEADING, &res,
-                      -1);
-
-  return res;
-}
-
-static void
-program_list_selection_activated (GtkTreeView       *view,
-                                  GtkTreePath       *path,
-                                  GtkTreeViewColumn *column,
-                                  gpointer           user_data)
-{
-  GtkAppChooserWidget *self = user_data;
-  GtkTreeSelection *selection;
-
-  if (path_is_heading (view, path))
-    return;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
-
-  refresh_and_emit_app_selected (self, selection);
-
-  g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0,
-                 self->selected_app_info);
-}
-
-static gboolean
-gtk_app_chooser_search_equal_func (GtkTreeModel *model,
-                                   int           column,
-                                   const char   *key,
-                                   GtkTreeIter  *iter,
-                                   gpointer      user_data)
-{
-  char *name;
-  char *exec_name;
-  gboolean ret;
-
-  if (key != NULL)
-    {
-      ret = TRUE;
-
-      gtk_tree_model_get (model, iter,
-                          COLUMN_NAME, &name,
-                          COLUMN_EXEC, &exec_name,
-                          -1);
-
-      if ((name != NULL && g_str_match_string (key, name, TRUE)) ||
-          (exec_name != NULL && g_str_match_string (key, exec_name, FALSE)))
-        ret = FALSE;
-
-      g_free (name);
-      g_free (exec_name);
-
-      return ret;
-    }
-  else
-    {
-      return TRUE;
-    }
-}
-
-static int
-gtk_app_chooser_sort_func (GtkTreeModel *model,
-                           GtkTreeIter  *a,
-                           GtkTreeIter  *b,
-                           gpointer      user_data)
-{
-  gboolean a_recommended, b_recommended;
-  gboolean a_fallback, b_fallback;
-  gboolean a_heading, b_heading;
-  gboolean a_default, b_default;
-  char *a_name, *b_name, *a_casefold, *b_casefold;
-  int retval = 0;
-
-  /* this returns:
-   * - <0 if a should show before b
-   * - =0 if a is the same as b
-   * - >0 if a should show after b
-   */
-
-  gtk_tree_model_get (model, a,
-                      COLUMN_NAME, &a_name,
-                      COLUMN_RECOMMENDED, &a_recommended,
-                      COLUMN_FALLBACK, &a_fallback,
-                      COLUMN_HEADING, &a_heading,
-                      COLUMN_DEFAULT, &a_default,
-                      -1);
-
-  gtk_tree_model_get (model, b,
-                      COLUMN_NAME, &b_name,
-                      COLUMN_RECOMMENDED, &b_recommended,
-                      COLUMN_FALLBACK, &b_fallback,
-                      COLUMN_HEADING, &b_heading,
-                      COLUMN_DEFAULT, &b_default,
-                      -1);
-
-  /* the default one always wins */
-  if (a_default && !b_default)
-    {
-      retval = -1;
-      goto out;
-    }
-
-  if (b_default && !a_default)
-    {
-      retval = 1;
-      goto out;
-    }
-  
-  /* the recommended one always wins */
-  if (a_recommended && !b_recommended)
-    {
-      retval = -1;
-      goto out;
-    }
-
-  if (b_recommended && !a_recommended)
-    {
-      retval = 1;
-      goto out;
-    }
-
-  /* the recommended one always wins */
-  if (a_fallback && !b_fallback)
-    {
-      retval = -1;
-      goto out;
-    }
-
-  if (b_fallback && !a_fallback)
-    {
-      retval = 1;
-      goto out;
-    }
-
-  /* they're both recommended/fallback or not, so if one is a heading, wins */
-  if (a_heading)
-    {
-      retval = -1;
-      goto out;
-    }
-
-  if (b_heading)
-    {
-      retval = 1;
-      goto out;
-    }
-
-  /* don't order by name recommended applications, but use GLib's ordering */
-  if (!a_recommended)
-    {
-      a_casefold = a_name != NULL ?
-        g_utf8_casefold (a_name, -1) : NULL;
-      b_casefold = b_name != NULL ?
-        g_utf8_casefold (b_name, -1) : NULL;
-
-      retval = g_strcmp0 (a_casefold, b_casefold);
-
-      g_free (a_casefold);
-      g_free (b_casefold);
-    }
-
- out:
-  g_free (a_name);
-  g_free (b_name);
-
-  return retval;
-}
-
-static void
-padding_cell_renderer_func (GtkTreeViewColumn *column,
-                            GtkCellRenderer   *cell,
-                            GtkTreeModel      *model,
-                            GtkTreeIter       *iter,
-                            gpointer           user_data)
-{
-  gboolean heading;
-
-  gtk_tree_model_get (model, iter,
-                      COLUMN_HEADING, &heading,
-                      -1);
-  if (heading)
-    g_object_set (cell,
-                  "visible", FALSE,
-                  "xpad", 0,
-                  "ypad", 0,
-                  NULL);
-  else
-    g_object_set (cell,
-                  "visible", TRUE,
-                  "xpad", 3,
-                  "ypad", 3,
-                  NULL);
-}
-
-static gboolean
-gtk_app_chooser_selection_func (GtkTreeSelection *selection,
-                                GtkTreeModel     *model,
-                                GtkTreePath      *path,
-                                gboolean          path_currently_selected,
-                                gpointer          user_data)
-{
-  GtkTreeIter iter;
-  gboolean heading;
-
-  gtk_tree_model_get_iter (model, &iter, path);
-  gtk_tree_model_get (model, &iter,
-                      COLUMN_HEADING, &heading,
-                      -1);
-
-  return !heading;
-}
-
-static int
-compare_apps_func (gconstpointer a,
-                   gconstpointer b)
-{
-  return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b));
-}
-
-static gboolean
-gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self,
-                                    const char          *heading_title,
-                                    gboolean             show_headings,
-                                    gboolean             recommended,
-                                    gboolean             fallback,
-                                    GList               *applications,
-                                    GList               *exclude_apps)
-{
-  gboolean heading_added, unref_icon;
-  GtkTreeIter iter;
-  GAppInfo *app;
-  char *app_string, *bold_string;
-  GIcon *icon;
-  GList *l;
-  gboolean retval;
-
-  retval = FALSE;
-  heading_added = FALSE;
-  bold_string = g_strdup_printf ("<b>%s</b>", heading_title);
-  
-  for (l = applications; l != NULL; l = l->next)
-    {
-      app = l->data;
-
-      if (self->content_type != NULL &&
-          !g_app_info_supports_uris (app) &&
-          !g_app_info_supports_files (app))
-        continue;
-
-      if (g_list_find_custom (exclude_apps, app,
-                              (GCompareFunc) compare_apps_func))
-        continue;
-
-      if (!heading_added && show_headings)
-        {
-          gtk_list_store_append (self->program_list_store, &iter);
-          gtk_list_store_set (self->program_list_store, &iter,
-                              COLUMN_HEADING_TEXT, bold_string,
-                              COLUMN_HEADING, TRUE,
-                              COLUMN_RECOMMENDED, recommended,
-                              COLUMN_FALLBACK, fallback,
-                              -1);
-
-          heading_added = TRUE;
-        }
-
-      app_string = g_markup_printf_escaped ("%s",
-                                            g_app_info_get_name (app) != NULL ?
-                                            g_app_info_get_name (app) : "");
-
-      icon = g_app_info_get_icon (app);
-      unref_icon = FALSE;
-      if (icon == NULL)
-        {
-          icon = g_themed_icon_new ("application-x-executable");
-          unref_icon = TRUE;
-        }
-
-      gtk_list_store_append (self->program_list_store, &iter);
-      gtk_list_store_set (self->program_list_store, &iter,
-                          COLUMN_APP_INFO, app,
-                          COLUMN_GICON, icon,
-                          COLUMN_NAME, g_app_info_get_name (app),
-                          COLUMN_DESC, app_string,
-                          COLUMN_EXEC, g_app_info_get_executable (app),
-                          COLUMN_HEADING, FALSE,
-                          COLUMN_RECOMMENDED, recommended,
-                          COLUMN_FALLBACK, fallback,
-                          -1);
-
-      retval = TRUE;
-
-      g_free (app_string);
-      if (unref_icon)
-        g_object_unref (icon);
-    }
-
-  g_free (bold_string);
-
-  return retval;
-}
-
-
-static void
-gtk_app_chooser_add_default (GtkAppChooserWidget *self,
-                             GAppInfo            *app)
-{
-  GtkTreeIter iter;
-  GIcon *icon;
-  char *string;
-  gboolean unref_icon;
-
-  unref_icon = FALSE;
-  string = g_strdup_printf ("<b>%s</b>", _("Default Application"));
-
-  gtk_list_store_append (self->program_list_store, &iter);
-  gtk_list_store_set (self->program_list_store, &iter,
-                      COLUMN_HEADING_TEXT, string,
-                      COLUMN_HEADING, TRUE,
-                      COLUMN_DEFAULT, TRUE,
-                      -1);
-
-  g_free (string);
-
-  string = g_markup_printf_escaped ("%s",
-                                    g_app_info_get_name (app) != NULL ?
-                                    g_app_info_get_name (app) : "");
-
-  icon = g_app_info_get_icon (app);
-  if (icon == NULL)
-    {
-      icon = g_themed_icon_new ("application-x-executable");
-      unref_icon = TRUE;
-    }
-
-  gtk_list_store_append (self->program_list_store, &iter);
-  gtk_list_store_set (self->program_list_store, &iter,
-                      COLUMN_APP_INFO, app,
-                      COLUMN_GICON, icon,
-                      COLUMN_NAME, g_app_info_get_name (app),
-                      COLUMN_DESC, string,
-                      COLUMN_EXEC, g_app_info_get_executable (app),
-                      COLUMN_HEADING, FALSE,
-                      COLUMN_DEFAULT, TRUE,
-                      -1);
-
-  g_free (string);
-
-  if (unref_icon)
-    g_object_unref (icon);
-}
-
-static void
-update_no_applications_label (GtkAppChooserWidget *self)
-{
-  char *text = NULL, *desc = NULL;
-  const char *string;
-
-  if (self->default_text == NULL)
-    {
-      if (self->content_type)
-       desc = g_content_type_get_description (self->content_type);
-
-      string = text = g_strdup_printf (_("No applications found for “%s”."), desc);
-      g_free (desc);
-    }
-  else
-    {
-      string = self->default_text;
-    }
-
-  gtk_label_set_text (GTK_LABEL (self->no_apps_label), string);
-
-  g_free (text);
-}
-
-static void
-gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self)
-{
-  GtkTreeIter iter;
-  GAppInfo *info = NULL;
-  GtkTreeModel *model;
-
-  model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list));
-  if (!gtk_tree_model_get_iter_first (model, &iter))
-    return;
-
-  while (info == NULL)
-    {
-      gtk_tree_model_get (model, &iter,
-                          COLUMN_APP_INFO, &info,
-                          -1);
-
-      if (info != NULL)
-        break;
-
-      if (!gtk_tree_model_iter_next (model, &iter))
-        break;
-    }
-
-  if (info != NULL)
-    {
-      GtkTreeSelection *selection;
-
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
-      gtk_tree_selection_select_iter (selection, &iter);
-
-      g_object_unref (info);
-    }
-}
-
-static void
-gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self)
-{
-  GList *all_applications = NULL;
-  GList *recommended_apps = NULL;
-  GList *fallback_apps = NULL;
-  GList *exclude_apps = NULL;
-  GAppInfo *default_app = NULL;
-  gboolean show_headings;
-  gboolean apps_added;
-
-  show_headings = TRUE;
-  apps_added = FALSE;
-
-  if (self->show_all)
-    show_headings = FALSE;
-
-  if (self->show_default && self->content_type)
-    {
-      default_app = g_app_info_get_default_for_type (self->content_type, FALSE);
-
-      if (default_app != NULL)
-        {
-          gtk_app_chooser_add_default (self, default_app);
-          apps_added = TRUE;
-          exclude_apps = g_list_prepend (exclude_apps, default_app);
-        }
-    }
-
-#ifndef G_OS_WIN32
-  if ((self->content_type && self->show_recommended) || self->show_all)
-    {
-      if (self->content_type)
-       recommended_apps = g_app_info_get_recommended_for_type (self->content_type);
-
-      apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"),
-                                                        show_headings,
-                                                        !self->show_all, /* mark as recommended */
-                                                        FALSE, /* mark as fallback */
-                                                        recommended_apps, exclude_apps);
-
-      exclude_apps = g_list_concat (exclude_apps,
-                                    g_list_copy (recommended_apps));
-    }
-
-  if ((self->content_type && self->show_fallback) || self->show_all)
-    {
-      if (self->content_type)
-       fallback_apps = g_app_info_get_fallback_for_type (self->content_type);
-
-      apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"),
-                                                        show_headings,
-                                                        FALSE, /* mark as recommended */
-                                                        !self->show_all, /* mark as fallback */
-                                                        fallback_apps, exclude_apps);
-      exclude_apps = g_list_concat (exclude_apps,
-                                    g_list_copy (fallback_apps));
-    }
-#endif
-
-  if (self->show_other || self->show_all)
-    {
-      all_applications = g_app_info_get_all ();
-
-      apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"),
-                                                        show_headings,
-                                                        FALSE,
-                                                        FALSE,
-                                                        all_applications, exclude_apps);
-    }
-
-  if (!apps_added)
-    update_no_applications_label (self);
-
-  gtk_widget_set_visible (self->no_apps, !apps_added);
-
-  gtk_app_chooser_widget_select_first (self);
-
-  if (default_app != NULL)
-    g_object_unref (default_app);
-
-  g_list_free_full (all_applications, g_object_unref);
-  g_list_free_full (recommended_apps, g_object_unref);
-  g_list_free_full (fallback_apps, g_object_unref);
-  g_list_free (exclude_apps);
-}
-
-static void
-gtk_app_chooser_widget_initialize_items (GtkAppChooserWidget *self)
-{
-  /* initial padding */
-  g_object_set (self->padding_renderer,
-                "xpad", self->show_all ? 0 : 6,
-                NULL);
-
-  /* populate the widget */
-  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-}
-
-static void
-app_info_changed (GAppInfoMonitor     *monitor,
-                  GtkAppChooserWidget *self)
-{
-  gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-}
-
-static void
-gtk_app_chooser_widget_set_property (GObject      *object,
-                                     guint         property_id,
-                                     const GValue *value,
-                                     GParamSpec   *pspec)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
-
-  switch (property_id)
-    {
-    case PROP_CONTENT_TYPE:
-      self->content_type = g_value_dup_string (value);
-      break;
-    case PROP_SHOW_DEFAULT:
-      gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value));
-      break;
-    case PROP_SHOW_RECOMMENDED:
-      gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value));
-      break;
-    case PROP_SHOW_FALLBACK:
-      gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value));
-      break;
-    case PROP_SHOW_OTHER:
-      gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value));
-      break;
-    case PROP_SHOW_ALL:
-      gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value));
-      break;
-    case PROP_DEFAULT_TEXT:
-      gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_app_chooser_widget_get_property (GObject    *object,
-                                     guint       property_id,
-                                     GValue     *value,
-                                     GParamSpec *pspec)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
-
-  switch (property_id)
-    {
-    case PROP_CONTENT_TYPE:
-      g_value_set_string (value, self->content_type);
-      break;
-    case PROP_SHOW_DEFAULT:
-      g_value_set_boolean (value, self->show_default);
-      break;
-    case PROP_SHOW_RECOMMENDED:
-      g_value_set_boolean (value, self->show_recommended);
-      break;
-    case PROP_SHOW_FALLBACK:
-      g_value_set_boolean (value, self->show_fallback);
-      break;
-    case PROP_SHOW_OTHER:
-      g_value_set_boolean (value, self->show_other);
-      break;
-    case PROP_SHOW_ALL:
-      g_value_set_boolean (value, self->show_all);
-      break;
-    case PROP_DEFAULT_TEXT:
-      g_value_set_string (value, self->default_text);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_app_chooser_widget_constructed (GObject *object)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
-
-  if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL)
-    G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object);
-
-  gtk_app_chooser_widget_initialize_items (self);
-}
-
-static void
-gtk_app_chooser_widget_finalize (GObject *object)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
-
-  g_free (self->content_type);
-  g_free (self->default_text);
-  g_signal_handlers_disconnect_by_func (self->monitor, app_info_changed, self);
-  g_object_unref (self->monitor);
-
-  G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object);
-}
-
-static void
-gtk_app_chooser_widget_dispose (GObject *object)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
-
-  g_clear_object (&self->selected_app_info);
-
-  if (self->overlay)
-    {
-      gtk_widget_unparent (self->overlay);
-      self->overlay = NULL;
-    }
-
-  G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object);
-}
-
-static void
-gtk_app_chooser_widget_measure (GtkWidget       *widget,
-                                GtkOrientation  orientation,
-                                int             for_size,
-                                int            *minimum,
-                                int            *natural,
-                                int            *minimum_baseline,
-                                int            *natural_baseline)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
-
-  gtk_widget_measure (self->overlay, orientation, for_size,
-                      minimum, natural,
-                      minimum_baseline, natural_baseline);
-}
-
-static void
-gtk_app_chooser_widget_snapshot (GtkWidget   *widget,
-                                 GtkSnapshot *snapshot)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
-
-  gtk_widget_snapshot_child (widget, self->overlay, snapshot);
-}
-
-static void
-gtk_app_chooser_widget_size_allocate (GtkWidget *widget,
-                                      int        width,
-                                      int        height,
-                                      int        baseline)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget);
-
-  GTK_WIDGET_CLASS (gtk_app_chooser_widget_parent_class)->size_allocate (widget, width, height, baseline);
-
-  gtk_widget_size_allocate (self->overlay,
-                            &(GtkAllocation) {
-                              0, 0,
-                              width, height
-                            },baseline);
-}
-
-static void
-gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
-{
-  GtkWidgetClass *widget_class;
-  GObjectClass *gobject_class;
-  GParamSpec *pspec;
-
-  gobject_class = G_OBJECT_CLASS (klass);
-  gobject_class->dispose = gtk_app_chooser_widget_dispose;
-  gobject_class->finalize = gtk_app_chooser_widget_finalize;
-  gobject_class->set_property = gtk_app_chooser_widget_set_property;
-  gobject_class->get_property = gtk_app_chooser_widget_get_property;
-  gobject_class->constructed = gtk_app_chooser_widget_constructed;
-
-  widget_class = GTK_WIDGET_CLASS (klass);
-  widget_class->measure = gtk_app_chooser_widget_measure;
-  widget_class->size_allocate = gtk_app_chooser_widget_size_allocate;
-  widget_class->snapshot = gtk_app_chooser_widget_snapshot;
-
-  g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
-
-  /**
-   * 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)
-   *
-   * Determines whether the app chooser should show the default
-   * handler for the content type in a separate section.
-   *
-   * If %FALSE, the default handler is listed among the recommended
-   * applications.
-   */
-  pspec = g_param_spec_boolean ("show-default", NULL, NULL,
-                                FALSE,
-                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec);
-
-  /**
-   * 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)
-   *
-   * Determines whether the app chooser should show a section
-   * for recommended applications.
-   *
-   * If %FALSE, the recommended applications are listed
-   * among the other applications.
-   */
-  pspec = g_param_spec_boolean ("show-recommended", NULL, NULL,
-                                TRUE,
-                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec);
-
-  /**
-   * 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)
-   *
-   * Determines whether the app chooser should show a section
-   * for fallback applications.
-   *
-   * If %FALSE, the fallback applications are listed among the
-   * other applications.
-   */
-  pspec = g_param_spec_boolean ("show-fallback", NULL, NULL,
-                                FALSE,
-                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec);
-
-  /**
-   * 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)
-   *
-   * Determines whether the app chooser should show a section
-   * for other applications.
-   */
-  pspec = g_param_spec_boolean ("show-other", NULL, NULL,
-                                FALSE,
-                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec);
-
-  /**
-   * 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)
-   *
-   * If %TRUE, the app chooser presents all applications
-   * in a single list, without subsections for default,
-   * recommended or related applications.
-   */
-  pspec = g_param_spec_boolean ("show-all", NULL, NULL,
-                                FALSE,
-                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec);
-
-  /**
-   * 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)
-   *
-   * The text that appears in the widget when there are no applications
-   * for the given content type.
-   */
-  pspec = g_param_spec_string ("default-text", NULL, NULL,
-                               NULL,
-                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
-  g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec);
-
-  /**
-   * GtkAppChooserWidget::application-selected:
-   * @self: the object which received the signal
-   * @application: the selected `GAppInfo`
-   *
-   * Emitted when an application item is selected from the widget's list.
-   */
-  signals[SIGNAL_APPLICATION_SELECTED] =
-    g_signal_new (I_("application-selected"),
-                  GTK_TYPE_APP_CHOOSER_WIDGET,
-                  G_SIGNAL_RUN_FIRST,
-                  G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected),
-                  NULL, NULL,
-                  NULL,
-                  G_TYPE_NONE,
-                  1, G_TYPE_APP_INFO);
-
-  /**
-   * GtkAppChooserWidget::application-activated:
-   * @self: the object which received the signal
-   * @application: the activated `GAppInfo`
-   *
-   * Emitted when an application item is activated from the widget's list.
-   *
-   * This usually happens when the user double clicks an item, or an item
-   * is selected and the user presses one of the keys Space, Shift+Space,
-   * Return or Enter.
-   */
-  signals[SIGNAL_APPLICATION_ACTIVATED] =
-    g_signal_new (I_("application-activated"),
-                  GTK_TYPE_APP_CHOOSER_WIDGET,
-                  G_SIGNAL_RUN_FIRST,
-                  G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated),
-                  NULL, NULL,
-                  NULL,
-                  G_TYPE_NONE,
-                  1, G_TYPE_APP_INFO);
-
-  /* Bind class to template
-   */
-  gtk_widget_class_set_template_from_resource (widget_class,
-                                              "/org/gtk/libgtk/ui/gtkappchooserwidget.ui");
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list_store);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, column);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, padding_renderer);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, secondary_padding);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps_label);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps);
-  gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, overlay);
-  gtk_widget_class_bind_template_callback (widget_class, refresh_and_emit_app_selected);
-  gtk_widget_class_bind_template_callback (widget_class, program_list_selection_activated);
-
-  gtk_widget_class_set_css_name (widget_class, I_("appchooser"));
-}
-
-static void
-gtk_app_chooser_widget_init (GtkAppChooserWidget *self)
-{
-  GtkTreeSelection *selection;
-  GtkTreeModel *sort;
-
-  gtk_widget_init_template (GTK_WIDGET (self));
-
-  /* Various parts of the GtkTreeView code need custom code to setup, mostly
-   * because we lack signals to connect to, or properties to set.
-   */
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list));
-  gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func,
-                                          self, NULL);
-
-  sort = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list));
-  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort),
-                                        COLUMN_NAME,
-                                        GTK_SORT_ASCENDING);
-  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort),
-                                   COLUMN_NAME,
-                                   gtk_app_chooser_sort_func,
-                                   self, NULL);
-
-  gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->program_list), COLUMN_NAME);
-  gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->program_list),
-                                       gtk_app_chooser_search_equal_func,
-                                       NULL, NULL);
-
-  gtk_tree_view_column_set_cell_data_func (self->column,
-                                          self->secondary_padding,
-                                           padding_cell_renderer_func,
-                                           NULL, NULL);
-
-  self->monitor = g_app_info_monitor_get ();
-  g_signal_connect (self->monitor, "changed",
-                   G_CALLBACK (app_info_changed), self);
-}
-
-static GAppInfo *
-gtk_app_chooser_widget_get_app_info (GtkAppChooser *object)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
-
-  if (self->selected_app_info == NULL)
-    return NULL;
-
-  return g_object_ref (self->selected_app_info);
-}
-
-static void
-gtk_app_chooser_widget_refresh (GtkAppChooser *object)
-{
-  GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object);
-
-  if (self->program_list_store != NULL)
-    {
-      gtk_list_store_clear (self->program_list_store);
-
-      /* don't add additional xpad if we don't have headings */
-      g_object_set (self->padding_renderer,
-                    "visible", !self->show_all,
-                    NULL);
-
-      gtk_app_chooser_widget_real_add_items (self);
-    }
-}
-
-static void
-gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface)
-{
-  iface->get_app_info = gtk_app_chooser_widget_get_app_info;
-  iface->refresh = gtk_app_chooser_widget_refresh;
-}
-
-/**
- * gtk_app_chooser_widget_new:
- * @content_type: the content type to show applications for
- *
- * Creates a new `GtkAppChooserWidget` for applications
- * that can handle content of the given type.
- *
- * Returns: a newly created `GtkAppChooserWidget`
- */
-GtkWidget *
-gtk_app_chooser_widget_new (const char *content_type)
-{
-  return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET,
-                       "content-type", content_type,
-                       NULL);
-}
-
-/**
- * gtk_app_chooser_widget_set_show_default: (attributes org.gtk.Method.set_property=show-default)
- * @self: a `GtkAppChooserWidget`
- * @setting: the new value for [property@Gtk.AppChooserWidget:show-default]
- *
- * Sets whether the app chooser should show the default handler
- * for the content type in a separate section.
- */
-void
-gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self,
-                                         gboolean             setting)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
-
-  if (self->show_default != setting)
-    {
-      self->show_default = setting;
-
-      g_object_notify (G_OBJECT (self), "show-default");
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_widget_get_show_default: (attributes org.gtk.Method.get_property=show-default)
- * @self: a `GtkAppChooserWidget`
- *
- * Gets whether the app chooser should show the default handler
- * for the content type in a separate section.
- *
- * Returns: the value of [property@Gtk.AppChooserWidget:show-default]
- */
-gboolean
-gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
-
-  return self->show_default;
-}
-
-/**
- * gtk_app_chooser_widget_set_show_recommended: (attributes org.gtk.Method.set_property=show-recommended)
- * @self: a `GtkAppChooserWidget`
- * @setting: the new value for [property@Gtk.AppChooserWidget:show-recommended]
- *
- * Sets whether the app chooser should show recommended applications
- * for the content type in a separate section.
- */
-void
-gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
-                                             gboolean             setting)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
-
-  if (self->show_recommended != setting)
-    {
-      self->show_recommended = setting;
-
-      g_object_notify (G_OBJECT (self), "show-recommended");
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_widget_get_show_recommended: (attributes org.gtk.Method.get_property=show-recommended)
- * @self: a `GtkAppChooserWidget`
- *
- * Gets whether the app chooser should show recommended applications
- * for the content type in a separate section.
- *
- * Returns: the value of [property@Gtk.AppChooserWidget:show-recommended]
- */
-gboolean
-gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
-
-  return self->show_recommended;
-}
-
-/**
- * gtk_app_chooser_widget_set_show_fallback: (attributes org.gtk.Method.set_property=show-fallback)
- * @self: a `GtkAppChooserWidget`
- * @setting: the new value for [property@Gtk.AppChooserWidget:show-fallback]
- *
- * Sets whether the app chooser should show related applications
- * for the content type in a separate section.
- */
-void
-gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self,
-                                          gboolean             setting)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
-
-  if (self->show_fallback != setting)
-    {
-      self->show_fallback = setting;
-
-      g_object_notify (G_OBJECT (self), "show-fallback");
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_widget_get_show_fallback: (attributes org.gtk.Method.get_property=show-fallback)
- * @self: a `GtkAppChooserWidget`
- *
- * Gets whether the app chooser should show related applications
- * for the content type in a separate section.
- *
- * Returns: the value of [property@Gtk.AppChooserWidget:show-fallback]
- */
-gboolean
-gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
-
-  return self->show_fallback;
-}
-
-/**
- * gtk_app_chooser_widget_set_show_other: (attributes org.gtk.Method.set_property=show-other)
- * @self: a `GtkAppChooserWidget`
- * @setting: the new value for [property@Gtk.AppChooserWidget:show-other]
- *
- * Sets whether the app chooser should show applications
- * which are unrelated to the content type.
- */
-void
-gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self,
-                                       gboolean             setting)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
-
-  if (self->show_other != setting)
-    {
-      self->show_other = setting;
-
-      g_object_notify (G_OBJECT (self), "show-other");
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_widget_get_show_other: (attributes org.gtk.Method.get_property=show-other)
- * @self: a `GtkAppChooserWidget`
- *
- * Gets whether the app chooser should show applications
- * which are unrelated to the content type.
- *
- * Returns: the value of [property@Gtk.AppChooserWidget:show-other]
- */
-gboolean
-gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
-
-  return self->show_other;
-}
-
-/**
- * gtk_app_chooser_widget_set_show_all: (attributes org.gtk.Method.set_property=show-all)
- * @self: a `GtkAppChooserWidget`
- * @setting: the new value for [property@Gtk.AppChooserWidget:show-all]
- *
- * Sets whether the app chooser should show all applications
- * in a flat list.
- */
-void
-gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self,
-                                     gboolean             setting)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
-
-  if (self->show_all != setting)
-    {
-      self->show_all = setting;
-
-      g_object_notify (G_OBJECT (self), "show-all");
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_widget_get_show_all: (attributes org.gtk.Method.get_property=show-all)
- * @self: a `GtkAppChooserWidget`
- *
- * Gets whether the app chooser should show all applications
- * in a flat list.
- *
- * Returns: the value of [property@Gtk.AppChooserWidget:show-all]
- */
-gboolean
-gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE);
-
-  return self->show_all;
-}
-
-/**
- * gtk_app_chooser_widget_set_default_text: (attributes org.gtk.Method.set_property=default-text)
- * @self: a `GtkAppChooserWidget`
- * @text: the new value for [property@Gtk.AppChooserWidget:default-text]
- *
- * Sets the text that is shown if there are not applications
- * that can handle the content type.
- */
-void
-gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self,
-                                         const char          *text)
-{
-  g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self));
-
-  if (g_strcmp0 (text, self->default_text) != 0)
-    {
-      g_free (self->default_text);
-      self->default_text = g_strdup (text);
-
-      g_object_notify (G_OBJECT (self), "default-text");
-
-      gtk_app_chooser_refresh (GTK_APP_CHOOSER (self));
-    }
-}
-
-/**
- * gtk_app_chooser_widget_get_default_text: (attributes org.gtk.Method.get_property=default-text)
- * @self: a `GtkAppChooserWidget`
- *
- * Returns the text that is shown if there are not applications
- * that can handle the content type.
- *
- * Returns: (nullable): the value of [property@Gtk.AppChooserWidget:default-text]
- */
-const char *
-gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self)
-{
-  g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL);
-
-  return self->default_text;
-}
-
-void
-_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self,
-                                          GtkEditable         *entry)
-{
-  gtk_tree_view_set_search_entry (GTK_TREE_VIEW (self->program_list), entry);
-
-  g_object_bind_property (self->no_apps, "visible",
-                          entry, "sensitive",
-                          G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
-}
diff --git a/gtk/gtkappchooserwidget.h b/gtk/gtkappchooserwidget.h
deleted file mode 100644 (file)
index 6167e05..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * gtkappchooserwidget.h: an app-chooser widget
- *
- * Copyright (C) 2004 Novell, Inc.
- * Copyright (C) 2007, 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors: Dave Camp <dave@novell.com>
- *          Alexander Larsson <alexl@redhat.com>
- *          Cosimo Cecchi <ccecchi@redhat.com>
- */
-
-#ifndef __GTK_APP_CHOOSER_WIDGET_H__
-#define __GTK_APP_CHOOSER_WIDGET_H__
-
-#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
-
-#include <gtk/gtkwidget.h>
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_APP_CHOOSER_WIDGET            (gtk_app_chooser_widget_get_type ())
-#define GTK_APP_CHOOSER_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_WIDGET, GtkAppChooserWidget))
-#define GTK_IS_APP_CHOOSER_WIDGET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_WIDGET))
-
-typedef struct _GtkAppChooserWidget        GtkAppChooserWidget;
-
-GDK_AVAILABLE_IN_ALL
-GType         gtk_app_chooser_widget_get_type             (void) G_GNUC_CONST;
-
-GDK_AVAILABLE_IN_ALL
-GtkWidget *   gtk_app_chooser_widget_new                  (const char          *content_type);
-
-GDK_AVAILABLE_IN_ALL
-void          gtk_app_chooser_widget_set_show_default     (GtkAppChooserWidget *self,
-                                                           gboolean             setting);
-GDK_AVAILABLE_IN_ALL
-gboolean      gtk_app_chooser_widget_get_show_default     (GtkAppChooserWidget *self);
-
-GDK_AVAILABLE_IN_ALL
-void          gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self,
-                                                           gboolean             setting);
-GDK_AVAILABLE_IN_ALL
-gboolean      gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self);
-
-GDK_AVAILABLE_IN_ALL
-void          gtk_app_chooser_widget_set_show_fallback    (GtkAppChooserWidget *self,
-                                                           gboolean             setting);
-GDK_AVAILABLE_IN_ALL
-gboolean      gtk_app_chooser_widget_get_show_fallback    (GtkAppChooserWidget *self);
-
-GDK_AVAILABLE_IN_ALL
-void          gtk_app_chooser_widget_set_show_other       (GtkAppChooserWidget *self,
-                                                           gboolean             setting);
-GDK_AVAILABLE_IN_ALL
-gboolean      gtk_app_chooser_widget_get_show_other       (GtkAppChooserWidget *self);
-
-GDK_AVAILABLE_IN_ALL
-void          gtk_app_chooser_widget_set_show_all         (GtkAppChooserWidget *self,
-                                                           gboolean             setting);
-GDK_AVAILABLE_IN_ALL
-gboolean      gtk_app_chooser_widget_get_show_all         (GtkAppChooserWidget *self);
-
-GDK_AVAILABLE_IN_ALL
-void          gtk_app_chooser_widget_set_default_text     (GtkAppChooserWidget *self,
-                                                           const char          *text);
-GDK_AVAILABLE_IN_ALL
-const char * gtk_app_chooser_widget_get_default_text     (GtkAppChooserWidget *self);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserWidget, g_object_unref)
-
-G_END_DECLS
-
-#endif /* __GTK_APP_CHOOSER_WIDGET_H__ */
index 9982cc1678684f49a67d0933460fca4378776549..46a50717bfe68c3a625376159992c12981d06137 100644 (file)
@@ -159,10 +159,6 @@ gtk_public_sources = files([
   'gtkactionable.c',
   'gtkactionbar.c',
   'gtkadjustment.c',
-  'gtkappchooser.c',
-  'gtkappchooserbutton.c',
-  'gtkappchooserdialog.c',
-  'gtkappchooserwidget.c',
   'gtkapplication.c',
   'gtkapplicationwindow.c',
   'gtkaspectframe.c',
@@ -451,10 +447,6 @@ gtk_public_headers = files([
   'gtkactionable.h',
   'gtkactionbar.h',
   'gtkadjustment.h',
-  'gtkappchooser.h',
-  'gtkappchooserbutton.h',
-  'gtkappchooserdialog.h',
-  'gtkappchooserwidget.h',
   'gtkapplication.h',
   'gtkapplicationwindow.h',
   'gtkaspectframe.h',
@@ -704,6 +696,7 @@ gtk_public_headers = files([
 ])
 
 install_headers(gtk_public_headers, subdir: 'gtk-4.0/gtk/')
+install_headers(gtk_deprecated_headers, subdir: 'gtk-4.0/gtk/deprecated')
 
 gtk_sources = gtk_public_sources + gtk_private_sources
 
index a3418dd34b2de130085e1c711f15346039fffafd..09a856d56103ec1b7429327f257fb684b6c7073d 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <gtk/gtk.h>
 
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
 static GtkWidget *toplevel;
 static GFile *file;
 static GtkWidget *grid, *file_l, *open;
index 9024b51dfa6677c37d4eb03be5193d9539b3126d..1ffc062d4a7ac06b86e146661c70e1f578429785 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <gtk/gtk.h>
 
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
 #define CUSTOM_ITEM "custom-item"
 
 static GtkWidget *toplevel, *button, *box;
index 5911882198998dd1b73e0259eccebc252e14075c..b2a549942de33ff5fac27bf13f949fee09bdf756 100644 (file)
@@ -198,6 +198,8 @@ test_action_bar_basic (void)
   g_object_unref (g_object_ref_sink (widget));
 }
 
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
 static void
 test_app_chooser_widget_basic (void)
 {
@@ -227,6 +229,8 @@ test_app_chooser_dialog_basic (void)
   gtk_window_destroy (GTK_WINDOW (widget));
 }
 
+G_GNUC_END_IGNORE_DEPRECATIONS
+
 static void
 test_color_chooser_dialog_basic (void)
 {