From e05fb7b3e36c052baf0dd607ddeb22c0a2b5cbde Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:47:04 +0200 Subject: Adding upstream version 43.2. Signed-off-by: Daniel Baumann --- .../pages/keyboard/cc-input-chooser.c | 883 +++++++++++++++++++++ 1 file changed, 883 insertions(+) create mode 100644 gnome-initial-setup/pages/keyboard/cc-input-chooser.c (limited to 'gnome-initial-setup/pages/keyboard/cc-input-chooser.c') diff --git a/gnome-initial-setup/pages/keyboard/cc-input-chooser.c b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c new file mode 100644 index 0000000..efba249 --- /dev/null +++ b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c @@ -0,0 +1,883 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Written by: + * Jasper St. Pierre + * Matthias Clasen + */ + +#include "config.h" +#include "cc-input-chooser.h" + +#include +#include +#include + +#include + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include + +#ifdef HAVE_IBUS +#include +#include "cc-ibus-utils.h" +#endif + +#include "cc-common-language.h" + +#include + +#define INPUT_SOURCE_TYPE_XKB "xkb" +#define INPUT_SOURCE_TYPE_IBUS "ibus" + +#define MIN_ROWS 5 + +struct _CcInputChooserPrivate +{ + GtkWidget *filter_entry; + GtkWidget *input_list; + GHashTable *inputs; + + GtkWidget *no_results; + GtkWidget *more_item; + + gboolean showing_extra; + gchar *locale; + gchar *id; + gchar *type; + GnomeXkbInfo *xkb_info; +#ifdef HAVE_IBUS + IBusBus *ibus; + GHashTable *ibus_engines; + GCancellable *ibus_cancellable; +#endif +}; +typedef struct _CcInputChooserPrivate CcInputChooserPrivate; +G_DEFINE_TYPE_WITH_PRIVATE (CcInputChooser, cc_input_chooser, GTK_TYPE_BOX); + +enum { + PROP_0, + PROP_SHOWING_EXTRA, + PROP_LAST +}; + +static GParamSpec *obj_props[PROP_LAST]; + +enum { + CHANGED, + CONFIRM, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + GtkWidget *box; + GtkWidget *label; + GtkWidget *checkmark; + + gchar *id; + gchar *type; + gchar *name; + gboolean is_extra; +} InputWidget; + +static InputWidget * +get_input_widget (GtkWidget *widget) +{ + return g_object_get_data (G_OBJECT (widget), "input-widget"); +} + +static GtkWidget * +padded_label_new (char *text) +{ + GtkWidget *widget; + widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + gtk_widget_set_halign (widget, GTK_ALIGN_CENTER); + gtk_widget_set_margin_top (widget, 10); + gtk_widget_set_margin_bottom (widget, 10); + gtk_box_append (GTK_BOX (widget), gtk_label_new (text)); + return widget; +} + +static void +input_widget_free (gpointer data) +{ + InputWidget *widget = data; + + g_free (widget->id); + g_free (widget->type); + g_free (widget->name); + g_free (widget); +} + +static gboolean +get_layout (CcInputChooser *chooser, + const gchar *type, + const gchar *id, + const gchar **layout, + const gchar **variant) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + + if (g_strcmp0 (type, INPUT_SOURCE_TYPE_XKB) == 0) { + gnome_xkb_info_get_layout_info (priv->xkb_info, + id, NULL, NULL, + layout, variant); + return TRUE; + } +#ifdef HAVE_IBUS + if (g_strcmp0 (type, INPUT_SOURCE_TYPE_IBUS) == 0) { + IBusEngineDesc *engine_desc = NULL; + + if (priv->ibus_engines) + engine_desc = g_hash_table_lookup (priv->ibus_engines, id); + + if (!engine_desc) + return FALSE; + + *layout = ibus_engine_desc_get_layout (engine_desc); + *variant = ""; + return TRUE; + } +#endif + return FALSE; +} + +static gboolean +preview_cb (GtkLabel *label, + const gchar *uri, + CcInputChooser *chooser) +{ + GtkWidget *row; + InputWidget *widget; + const gchar *layout; + const gchar *variant; + gchar *commandline; + + row = gtk_widget_get_parent (GTK_WIDGET (label)); + widget = get_input_widget (row); + + if (!get_layout (chooser, widget->type, widget->id, &layout, &variant)) + return TRUE; + + if (variant[0]) + commandline = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"", layout, variant); + else + commandline = g_strdup_printf ("gkbd-keyboard-display -l %s", layout); + g_spawn_command_line_async (commandline, NULL); + g_free (commandline); + + return TRUE; +} + +static GtkWidget * +input_widget_new (CcInputChooser *chooser, + const char *type, + const char *id, + gboolean is_extra) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + GtkWidget *label; + InputWidget *widget = g_new0 (InputWidget, 1); + const gchar *name; + gchar *text; + + if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) { + gnome_xkb_info_get_layout_info (priv->xkb_info, id, &name, NULL, NULL, NULL); + } +#ifdef HAVE_IBUS + else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) { + if (priv->ibus_engines) + name = engine_get_display_name (g_hash_table_lookup (priv->ibus_engines, id)); + else + name = id; + } +#endif + else { + name = "ERROR"; + } + + widget->id = g_strdup (id); + widget->type = g_strdup (type); + widget->name = g_strdup (name); + widget->is_extra = is_extra; + + widget->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + gtk_widget_set_halign (widget->box, GTK_ALIGN_FILL); + gtk_widget_set_margin_top (widget->box, 10); + gtk_widget_set_margin_bottom (widget->box, 10); + gtk_widget_set_margin_start (widget->box, 10); + gtk_widget_set_margin_end (widget->box, 10); + + widget->label = gtk_label_new (name); + gtk_label_set_xalign (GTK_LABEL (widget->label), 0); + gtk_label_set_yalign (GTK_LABEL (widget->label), 0.5); + gtk_label_set_ellipsize (GTK_LABEL (widget->label), PANGO_ELLIPSIZE_END); + gtk_label_set_max_width_chars (GTK_LABEL (widget->label), 40); + gtk_label_set_width_chars (GTK_LABEL (widget->label), 40); + gtk_box_append (GTK_BOX (widget->box), widget->label); + + + widget->checkmark = gtk_image_new_from_icon_name ("object-select-symbolic"); + gtk_box_append (GTK_BOX (widget->box), widget->checkmark); + + gtk_widget_set_margin_start (widget->checkmark, 10); + gtk_widget_set_margin_end (widget->checkmark, 10); + gtk_widget_set_halign (widget->box, GTK_ALIGN_START); + + text = g_strdup_printf ("%s", _("Preview")); + label = gtk_label_new (""); + gtk_label_set_markup (GTK_LABEL (label), text); + g_free (text); + g_signal_connect (label, "activate-link", + G_CALLBACK (preview_cb), chooser); + gtk_box_append (GTK_BOX (widget->box), label); + + g_object_set_data_full (G_OBJECT (widget->box), "input-widget", widget, + input_widget_free); + + return widget->box; +} + +static void +sync_all_checkmarks (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv; + GtkWidget *row; + + priv = cc_input_chooser_get_instance_private (chooser); + row = gtk_widget_get_first_child (priv->input_list); + while (row) { + InputWidget *widget; + GtkWidget *child; + gboolean should_be_visible; + + child = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (row)); + widget = get_input_widget (child); + + if (widget == NULL) + return; + + if (priv->id == NULL || priv->type == NULL) + should_be_visible = FALSE; + else + should_be_visible = g_strcmp0 (widget->id, priv->id) == 0 && + g_strcmp0 (widget->type, priv->type) == 0; + gtk_widget_set_opacity (widget->checkmark, should_be_visible ? 1.0 : 0.0); + + if (widget->is_extra && should_be_visible) + widget->is_extra = FALSE; + + row = gtk_widget_get_next_sibling (row); + } + + gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->input_list)); +} + +static GtkWidget * +more_widget_new (void) +{ + GtkWidget *widget; + GtkWidget *arrow; + + widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10); + gtk_widget_set_tooltip_text (widget, _("Moreā€¦")); + + arrow = gtk_image_new_from_icon_name ("view-more-symbolic"); + gtk_style_context_add_class (gtk_widget_get_style_context (arrow), "dim-label"); + gtk_widget_set_margin_top (widget, 12); + gtk_widget_set_margin_bottom (widget, 12); + gtk_widget_set_hexpand (arrow, TRUE); + gtk_widget_set_halign (arrow, GTK_ALIGN_CENTER); + gtk_widget_set_valign (arrow, GTK_ALIGN_CENTER); + gtk_box_append (GTK_BOX (widget), arrow); + + return widget; +} + +static GtkWidget * +no_results_widget_new (void) +{ + GtkWidget *widget; + + /* Translators: a search for input methods or keyboard layouts + * did not yield any results + */ + widget = padded_label_new (_("No inputs found")); + gtk_widget_set_sensitive (widget, FALSE); + return widget; +} + +static void +choose_non_extras (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv; + GtkWidget *row; + guint count = 0; + + priv = cc_input_chooser_get_instance_private (chooser); + row = gtk_widget_get_first_child (priv->input_list); + while (row) { + InputWidget *widget; + GtkWidget *child; + + if (++count > MIN_ROWS) + break; + + child = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (row)); + widget = get_input_widget (child); + if (widget == NULL) + break; + + widget->is_extra = FALSE; + + row = gtk_widget_get_next_sibling (row); + } +} + +static void +add_rows_to_list (CcInputChooser *chooser, + GList *list, + const gchar *type, + const gchar *default_id) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + const gchar *id; + GtkWidget *widget; + gchar *key; + + for (; list; list = list->next) { + id = (const gchar *) list->data; + + if (g_strcmp0 (id, default_id) == 0) + continue; + + key = g_strdup_printf ("%s::%s", type, id); + if (g_hash_table_contains (priv->inputs, key)) { + g_free (key); + continue; + } + g_hash_table_add (priv->inputs, key); + + widget = input_widget_new (chooser, type, id, TRUE); + gtk_list_box_append (GTK_LIST_BOX (priv->input_list), widget); + } +} + +static void +add_row_to_list (CcInputChooser *chooser, + const gchar *type, + const gchar *id) +{ + GList tmp = { 0 }; + tmp.data = (gpointer)id; + add_rows_to_list (chooser, &tmp, type, NULL); +} + +static void +get_locale_infos (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + const gchar *type = NULL; + const gchar *id = NULL; + gchar *lang, *country; + GList *list; + + if (gnome_get_input_source_from_locale (priv->locale, &type, &id)) { + add_row_to_list (chooser, type, id); + if (!priv->id) { + priv->id = g_strdup (id); + priv->type = g_strdup (type); + } + } + + if (!gnome_parse_locale (priv->locale, &lang, &country, NULL, NULL)) + goto out; + + list = gnome_xkb_info_get_layouts_for_language (priv->xkb_info, lang); + add_rows_to_list (chooser, list, INPUT_SOURCE_TYPE_XKB, id); + g_list_free (list); + + if (country != NULL) { + list = gnome_xkb_info_get_layouts_for_country (priv->xkb_info, country); + add_rows_to_list (chooser, list, INPUT_SOURCE_TYPE_XKB, id); + g_list_free (list); + } + + choose_non_extras (chooser); + + list = gnome_xkb_info_get_all_layouts (priv->xkb_info); + add_rows_to_list (chooser, list, INPUT_SOURCE_TYPE_XKB, id); + g_list_free (list); + +out: + g_free (lang); + g_free (country); +} + +static gboolean +input_visible (GtkListBoxRow *row, + gpointer user_data) +{ + CcInputChooser *chooser = user_data; + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + InputWidget *widget; + gboolean visible; + GtkWidget *child; + const char *search_term; + + child = gtk_list_box_row_get_child (row); + if (child == priv->more_item) + return !priv->showing_extra && g_hash_table_size (priv->inputs) > MIN_ROWS; + + widget = get_input_widget (child); + + if (!priv->showing_extra && widget->is_extra) + return FALSE; + + search_term = gtk_editable_get_text (GTK_EDITABLE (priv->filter_entry)); + if (!search_term || !*search_term) + return TRUE; + + visible = g_str_match_string (search_term, widget->name, TRUE); + return visible; +} + +static gint +sort_inputs (GtkListBoxRow *a, + GtkListBoxRow *b, + gpointer data) +{ + InputWidget *la, *lb; + + la = get_input_widget (gtk_list_box_row_get_child (a)); + lb = get_input_widget (gtk_list_box_row_get_child (b)); + + if (la == NULL) + return 1; + + if (lb == NULL) + return -1; + + if (la->is_extra && !lb->is_extra) + return 1; + + if (!la->is_extra && lb->is_extra) + return -1; + + return strcmp (la->name, lb->name); +} + +static void +filter_changed (GtkEntry *entry, + CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->input_list)); +} + +static void +show_more (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + + if (g_hash_table_size (priv->inputs) <= MIN_ROWS) + return; + + gtk_widget_grab_focus (priv->filter_entry); + + gtk_widget_set_valign (GTK_WIDGET (chooser), GTK_ALIGN_FILL); + + priv->showing_extra = TRUE; + gtk_list_box_invalidate_filter (GTK_LIST_BOX (priv->input_list)); + g_object_notify_by_pspec (G_OBJECT (chooser), obj_props[PROP_SHOWING_EXTRA]); +} + +static void +set_input (CcInputChooser *chooser, + const gchar *id, + const gchar *type) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + + if (g_strcmp0 (priv->id, id) == 0 && + g_strcmp0 (priv->type, type) == 0) + return; + + g_free (priv->id); + g_free (priv->type); + priv->id = g_strdup (id); + priv->type = g_strdup (type); + + sync_all_checkmarks (chooser); + + g_signal_emit (chooser, signals[CHANGED], 0); +} + +static gboolean +confirm_choice (gpointer data) +{ + GtkWidget *widget = data; + + g_signal_emit (widget, signals[CONFIRM], 0); + + return G_SOURCE_REMOVE; +} + +static void +row_activated (GtkListBox *box, + GtkListBoxRow *row, + CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + GtkWidget *child; + InputWidget *widget; + + if (row == NULL) + return; + + child = gtk_list_box_row_get_child (row); + if (child == priv->more_item) { + show_more (chooser); + } else { + widget = get_input_widget (child); + if (widget == NULL) + return; + if (g_strcmp0 (priv->id, widget->id) == 0 && + g_strcmp0 (priv->type, widget->type) == 0) + confirm_choice (chooser); + else + set_input (chooser, widget->id, widget->type); + } +} + +#ifdef HAVE_IBUS +static void +update_ibus_active_sources (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv; + IBusEngineDesc *engine_desc; + GtkWidget *child; + const gchar *type; + const gchar *id; + gchar *name; + + priv = cc_input_chooser_get_instance_private (chooser); + child = gtk_widget_get_first_child (priv->input_list); + while (child) { + InputWidget *row; + + row = get_input_widget (child); + child = gtk_widget_get_next_sibling (child); + + if (row == NULL) + continue; + + type = row->type; + id = row->id; + if (g_strcmp0 (type, INPUT_SOURCE_TYPE_IBUS) != 0) + continue; + + engine_desc = g_hash_table_lookup (priv->ibus_engines, id); + if (engine_desc) { + name = engine_get_display_name (engine_desc); + gtk_label_set_text (GTK_LABEL (row->label), name); + g_free (name); + } + } +} + +static void +get_ibus_locale_infos (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + GHashTableIter iter; + const gchar *engine_id; + IBusEngineDesc *engine; + + if (!priv->ibus_engines) + return; + + g_hash_table_iter_init (&iter, priv->ibus_engines); + while (g_hash_table_iter_next (&iter, (gpointer *) &engine_id, (gpointer *) &engine)) + add_row_to_list (chooser, INPUT_SOURCE_TYPE_IBUS, engine_id); +} + +static void +fetch_ibus_engines_result (GObject *object, + GAsyncResult *result, + CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv; + GList *list, *l; + GError *error; + + error = NULL; + list = ibus_bus_list_engines_async_finish (IBUS_BUS (object), result, &error); + if (!list && error) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Couldn't finish IBus request: %s", error->message); + g_error_free (error); + return; + } + + priv = cc_input_chooser_get_instance_private (chooser); + g_clear_object (&priv->ibus_cancellable); + + /* Maps engine ids to engine description objects */ + priv->ibus_engines = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + for (l = list; l; l = l->next) { + IBusEngineDesc *engine = l->data; + const gchar *engine_id; + + engine_id = ibus_engine_desc_get_name (engine); + if (g_str_has_prefix (engine_id, "xkb:")) + g_object_unref (engine); + else + g_hash_table_replace (priv->ibus_engines, (gpointer)engine_id, engine); + } + g_list_free (list); + + update_ibus_active_sources (chooser); + get_ibus_locale_infos (chooser); + + sync_all_checkmarks (chooser); +} + +static void +fetch_ibus_engines (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + + priv->ibus_cancellable = g_cancellable_new (); + + ibus_bus_list_engines_async (priv->ibus, + -1, + priv->ibus_cancellable, + (GAsyncReadyCallback)fetch_ibus_engines_result, + chooser); + + /* We've got everything we needed, don't want to be called again. */ + g_signal_handlers_disconnect_by_func (priv->ibus, fetch_ibus_engines, chooser); +} + +static void +maybe_start_ibus (void) +{ + /* IBus doesn't export API in the session bus. The only thing + * we have there is a well known name which we can use as a + * sure-fire way to activate it. + */ + g_bus_unwatch_name (g_bus_watch_name (G_BUS_TYPE_SESSION, + IBUS_SERVICE_IBUS, + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + NULL, + NULL, + NULL, + NULL)); +} +#endif + +static void +cc_input_chooser_constructed (GObject *object) +{ + CcInputChooser *chooser = CC_INPUT_CHOOSER (object); + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + + G_OBJECT_CLASS (cc_input_chooser_parent_class)->constructed (object); + + priv->xkb_info = gnome_xkb_info_new (); + +#ifdef HAVE_IBUS + ibus_init (); + if (!priv->ibus) { + priv->ibus = ibus_bus_new_async (); + if (ibus_bus_is_connected (priv->ibus)) + fetch_ibus_engines (chooser); + else + g_signal_connect_swapped (priv->ibus, "connected", + G_CALLBACK (fetch_ibus_engines), chooser); + } + maybe_start_ibus (); +#endif + + priv->inputs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + priv->more_item = more_widget_new (); + priv->no_results = no_results_widget_new (); + + gtk_list_box_set_sort_func (GTK_LIST_BOX (priv->input_list), + sort_inputs, chooser, NULL); + gtk_list_box_set_filter_func (GTK_LIST_BOX (priv->input_list), + input_visible, chooser, NULL); + gtk_list_box_set_selection_mode (GTK_LIST_BOX (priv->input_list), + GTK_SELECTION_NONE); + + if (priv->locale == NULL) { + priv->locale = cc_common_language_get_current_language (); + } + + get_locale_infos (chooser); +#ifdef HAVE_IBUS + get_ibus_locale_infos (chooser); +#endif + + gtk_list_box_append (GTK_LIST_BOX (priv->input_list), priv->more_item); + gtk_list_box_set_placeholder (GTK_LIST_BOX (priv->input_list), priv->no_results); + + g_signal_connect (priv->filter_entry, "changed", + G_CALLBACK (filter_changed), + chooser); + + g_signal_connect (priv->input_list, "row-activated", + G_CALLBACK (row_activated), chooser); + + sync_all_checkmarks (chooser); +} + +static void +cc_input_chooser_finalize (GObject *object) +{ + CcInputChooser *chooser = CC_INPUT_CHOOSER (object); + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + + g_clear_object (&priv->xkb_info); + g_hash_table_unref (priv->inputs); +#ifdef HAVE_IBUS + g_clear_object (&priv->ibus); + if (priv->ibus_cancellable) + g_cancellable_cancel (priv->ibus_cancellable); + g_clear_object (&priv->ibus_cancellable); + g_clear_pointer (&priv->ibus_engines, g_hash_table_destroy); +#endif + + G_OBJECT_CLASS (cc_input_chooser_parent_class)->finalize (object); +} + +static void +cc_input_chooser_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CcInputChooser *chooser = CC_INPUT_CHOOSER (object); + switch (prop_id) { + case PROP_SHOWING_EXTRA: + g_value_set_boolean (value, cc_input_chooser_get_showing_extra (chooser)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +cc_input_chooser_class_init (CcInputChooserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/initial-setup/input-chooser.ui"); + + gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcInputChooser, filter_entry); + gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), CcInputChooser, input_list); + + object_class->finalize = cc_input_chooser_finalize; + object_class->get_property = cc_input_chooser_get_property; + object_class->constructed = cc_input_chooser_constructed; + + obj_props[PROP_SHOWING_EXTRA] = + g_param_spec_string ("showing-extra", "", "", "", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CONFIRM] = + g_signal_new ("confirm", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_object_class_install_properties (object_class, PROP_LAST, obj_props); +} + +static void +cc_input_chooser_init (CcInputChooser *chooser) +{ + gtk_widget_init_template (GTK_WIDGET (chooser)); +} + +void +cc_input_chooser_clear_filter (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + gtk_editable_set_text (GTK_EDITABLE (priv->filter_entry), ""); +} + +const gchar * +cc_input_chooser_get_input_id (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + return priv->id; +} + +const gchar * +cc_input_chooser_get_input_type (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + return priv->type; +} + +void +cc_input_chooser_get_layout (CcInputChooser *chooser, + const gchar **layout, + const gchar **variant) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + + if (!get_layout (chooser, priv->type, priv->id, layout, variant)) { + if (layout != NULL) + *layout = NULL; + if (variant != NULL) + *variant = NULL; + } +} + +void +cc_input_chooser_set_input (CcInputChooser *chooser, + const gchar *id, + const gchar *type) +{ + set_input (chooser, id, type); +} + +gboolean +cc_input_chooser_get_showing_extra (CcInputChooser *chooser) +{ + CcInputChooserPrivate *priv = cc_input_chooser_get_instance_private (chooser); + return priv->showing_extra; +} -- cgit v1.2.3