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);
}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__ */
+
--- /dev/null
+/* 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.
+ *
+ * 
+ *
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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`.
+ *
+ * 
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__ */
-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',
+]
#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>
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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__ */
-
+++ /dev/null
-/* 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.
- *
- * 
- *
- * 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;
-}
-
+++ /dev/null
-/*
- * 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__ */
+++ /dev/null
-/*
- * 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`.
- *
- * 
- *
- * 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;
-}
+++ /dev/null
-/*
- * 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__ */
+++ /dev/null
-/*
- * 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__ */
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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__ */
'gtkactionable.c',
'gtkactionbar.c',
'gtkadjustment.c',
- 'gtkappchooser.c',
- 'gtkappchooserbutton.c',
- 'gtkappchooserdialog.c',
- 'gtkappchooserwidget.c',
'gtkapplication.c',
'gtkapplicationwindow.c',
'gtkaspectframe.c',
'gtkactionable.h',
'gtkactionbar.h',
'gtkadjustment.h',
- 'gtkappchooser.h',
- 'gtkappchooserbutton.h',
- 'gtkappchooserdialog.h',
- 'gtkappchooserwidget.h',
'gtkapplication.h',
'gtkapplicationwindow.h',
'gtkaspectframe.h',
])
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
#include <stdlib.h>
#include <gtk/gtk.h>
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
static GtkWidget *toplevel;
static GFile *file;
static GtkWidget *grid, *file_l, *open;
#include <stdlib.h>
#include <gtk/gtk.h>
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
#define CUSTOM_ITEM "custom-item"
static GtkWidget *toplevel, *button, *box;
g_object_unref (g_object_ref_sink (widget));
}
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
static void
test_app_chooser_widget_basic (void)
{
gtk_window_destroy (GTK_WINDOW (widget));
}
+G_GNUC_END_IGNORE_DEPRECATIONS
+
static void
test_color_chooser_dialog_basic (void)
{