From 9f93dd73c5ed57bb2fb1b572c9282d499d1c7fd7 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 24 Aug 2023 19:58:17 -0400 Subject: [PATCH 4/4] languages: Add functions for getting default input sources The code to get the default input sources would otherwise need to be duplicated across control-center, gnome-shell and gnome-initial-setup. This commit avoids some of that redundancy by consolidating the logic into two new functions: gnome_get_default_input_sources and gnome_get_default_input_sources_finish Note, these functions don't provide change notification, so there is still some redundancy needed by callers. --- libgnome-desktop/gnome-languages.c | 256 +++++++++++++++++++++++++++++ libgnome-desktop/gnome-languages.h | 10 ++ 2 files changed, 266 insertions(+) diff --git a/libgnome-desktop/gnome-languages.c b/libgnome-desktop/gnome-languages.c index cc9bd005..072e1b07 100644 --- a/libgnome-desktop/gnome-languages.c +++ b/libgnome-desktop/gnome-languages.c @@ -17,80 +17,87 @@ * along with this program; if not, see . * * Written by : William Jon McCann * Ray Strode */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_XLOCALE #include #endif #include "gnome-gettext-portable.h" #define GNOME_DESKTOP_USE_UNSTABLE_API #include "gnome-languages.h" +#include "sd-locale1.h" + #include #ifndef __LC_LAST #define __LC_LAST 13 #endif #define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes" #define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale" #include "default-input-sources.h" #include "non-latin-input-sources.h" typedef struct _GnomeLocale { char *id; char *name; char *language_code; char *territory_code; char *codeset; char *modifier; } GnomeLocale; +typedef struct _GnomeInputSourceDefaults { + InputSource **input_sources; + char **options; +} GnomeInputSourceDefaults; + static GHashTable *gnome_languages_map; static GHashTable *gnome_territories_map; static GHashTable *gnome_available_locales_map; static GHashTable *gnome_language_count_map; static GHashTable *gnome_territory_count_map; static char * construct_language_name (const char *language, const char *territory, const char *codeset, const char *modifier); static gboolean language_name_is_valid (const char *language_name); static void gnome_locale_free (GnomeLocale *locale) { if (locale == NULL) { return; } g_free (locale->id); g_free (locale->name); g_free (locale->codeset); g_free (locale->modifier); g_free (locale->language_code); g_free (locale->territory_code); g_free (locale); } static char * @@ -1440,30 +1447,279 @@ gnome_get_input_source_from_locale (const char *locale, } /** * gnome_input_source_is_non_latin: * @type: an input source type (e.g., "xkb" or "ibus") * @id: an input source id (e.g., "us+dvorak" or "anthy") * * Returns whether or not the input source has the ability to enter latin characters. * * Return value: %TRUE if it can't enter latin characters * * Since: 46 */ gboolean gnome_input_source_is_non_latin (const char *type, const char *id) { size_t i; for (i = 0; non_latin_input_sources[i].type != NULL; i++) { if (g_strcmp0 (type, non_latin_input_sources[i].type) != 0) continue; if (g_strcmp0 (id, non_latin_input_sources[i].id) != 0) continue; return TRUE; } return FALSE; } + +static void +on_got_localed_proxy (GObject *object, + GAsyncResult *result, + GTask *sub_task) +{ + g_autoptr(SdDBusLocale1) proxy = NULL; + g_autoptr(GError) error = NULL; + + proxy = sd_dbus_locale1_proxy_new_finish (result, &error); + + if (error != NULL) { + g_task_return_error (sub_task, g_steal_pointer (&error)); + } else { + g_task_return_pointer (sub_task, g_steal_pointer (&proxy), (GDestroyNotify) g_object_unref); + } +} + +static void +get_localed_proxy (GCancellable *cancellable, + GAsyncReadyCallback callback, + GTask *main_task) +{ + g_autoptr(GTask) sub_task = NULL; + + sub_task = g_task_new (NULL, + cancellable, + callback, + main_task); + + sd_dbus_locale1_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.locale1", + "/org/freedesktop/locale1", + cancellable, + (GAsyncReadyCallback) + on_got_localed_proxy, + sub_task); + + g_object_set_data_full (G_OBJECT (main_task), + "gnome-desktop-get-localed-proxy", + g_steal_pointer (&sub_task), + g_object_unref); +} + +static gboolean +input_source_equal (const InputSource *a, + const InputSource *b) +{ + return g_str_equal (a->type, b->type) && g_str_equal (a->id, b->id); +} + +static void +gnome_input_source_defaults_free (GnomeInputSourceDefaults *defaults) +{ + size_t i; + + for (i = 0; defaults->input_sources[i] != NULL; i++) { + g_free (defaults->input_sources[i]->type); + g_free (defaults->input_sources[i]->id); + g_free (defaults->input_sources[i]); + } + g_free (defaults->input_sources); + g_strfreev (defaults->options); + g_free (defaults); +} + +static void +on_got_localed_proxy_for_getting_default_input_sources (GObject *object, + GAsyncResult *result, + GTask *main_task) +{ + g_autoptr(SdDBusLocale1) proxy = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) input_sources = NULL; + g_autofree InputSource *locale_input_source = NULL; + + const char * const *locale_data; + g_autofree char *system_locale = NULL; + g_autofree char *layouts_string = NULL; + g_autofree char *variants_string = NULL; + g_autofree char *options_string = NULL; + g_auto(GStrv) layouts = NULL; + size_t number_of_layouts = 0; + g_auto(GStrv) variants = NULL; + size_t number_of_variants = 0; + g_auto(GStrv) options = NULL; + const char *type = NULL, *id = NULL; + size_t i; + GnomeInputSourceDefaults *defaults; + + proxy = g_task_propagate_pointer (G_TASK (result), &error); + + if (proxy == NULL) { + g_task_return_error (main_task, g_steal_pointer (&error)); + return; + } + + input_sources = g_ptr_array_new (); + + locale_data = sd_dbus_locale1_get_locale (proxy); + for (i = 0; locale_data[i] != NULL; i++) { + if (g_str_has_prefix (locale_data[i], "LANG=")) { + system_locale = g_strdup (locale_data[i] + strlen("LANG=")); + break; + } + } + + if (gnome_get_input_source_from_locale (system_locale, &type, &id)) { + locale_input_source = g_new0 (InputSource, 1); + locale_input_source->type = g_strdup (type); + locale_input_source->id = g_strdup (id); + + /* We add locale derived input source first if it's an input method + * and last if it's xkb based. + */ + if (g_strcmp0 (type, "ibus") == 0) { + g_ptr_array_add (input_sources, g_steal_pointer (&locale_input_source)); + } + } + + layouts_string = sd_dbus_locale1_dup_x11_layout (proxy); + variants_string = sd_dbus_locale1_dup_x11_variant (proxy); + options_string = sd_dbus_locale1_dup_x11_options (proxy); + + layouts = g_strsplit (layouts_string, ",", -1); + + if (variants_string[0] != '\0') { + variants = g_strsplit (variants_string, ",", -1); + } else { + variants = g_strdupv ((char *[]) { "", NULL }); + } + + options = g_strsplit (options_string, ",", -1); + + number_of_layouts = g_strv_length (layouts); + number_of_variants = g_strv_length (variants); + + if (number_of_layouts == number_of_variants) { + for (i = 0; layouts[i] != NULL; i++) { + g_autofree InputSource *input_source = g_new0 (InputSource, 1); + + input_source->type = g_strdup ("xkb"); + input_source->id = g_strdup_printf ("%s%s%s", + layouts[i], + variants[i][0] != '\0'? "+" : "", + variants[i]); + + if (!g_ptr_array_find_with_equal_func (input_sources, input_source, (GEqualFunc) input_source_equal, NULL)) { + g_ptr_array_add (input_sources, g_steal_pointer (&input_source)); + } + } + } + + if (locale_input_source != NULL) { + if (!g_ptr_array_find_with_equal_func (input_sources, locale_input_source, (GEqualFunc) input_source_equal, NULL)) { + g_ptr_array_add (input_sources, g_steal_pointer (&locale_input_source)); + } + } + + if (input_sources->len == 0) { + InputSource *input_source = g_new0 (InputSource, 1); + input_source->type = g_strdup ("xkb"); + input_source->id = g_strdup ("us"); + g_ptr_array_add (input_sources, g_steal_pointer (&input_source)); + } + g_ptr_array_add (input_sources, NULL); + + defaults = g_new0 (GnomeInputSourceDefaults, 1); + defaults->input_sources = (InputSource **) g_ptr_array_steal (input_sources, NULL); + defaults->options = g_steal_pointer (&options); + + g_task_return_pointer (main_task, defaults, (GDestroyNotify) gnome_input_source_defaults_free); +} + +/** + * gnome_get_default_input_sources: + * @cancellable: a #GCancellable + * @callback: a #GAsyncReadyCallback + * @user_data: user data for @callback + * + * Asynchronously fetches a list of of default input sources based on locale and system + * configuration. This is for when a user has no input sources configured + * in GSettings. + * + * Since: 46 + */ +void +gnome_get_default_input_sources (GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + task = g_task_new (NULL, + cancellable, + callback, + user_data); + + get_localed_proxy (cancellable, + (GAsyncReadyCallback) + on_got_localed_proxy_for_getting_default_input_sources, + task); +} + +/** + * gnome_get_default_input_sources_finish: + * @result: a #GAsyncResult + * @types: (out) (transfer full): an array of types (either "xkb" or "ibus") + * @options: (out) (transfer full): an options string to use with all input sources + * @error: a #GError + * + * Returns: (transfer full): a list of default input sources based on locale and system + * configuration. This is for when a user has no input sources configured + * in GSettings. + * + * Since: 46 + */ +char ** +gnome_get_default_input_sources_finish (GAsyncResult *result, + char ***types, + char ***options, + GError **error) +{ + GnomeInputSourceDefaults *defaults = NULL; + size_t i; + g_autoptr (GStrvBuilder) ids_builder = NULL; + g_autoptr (GStrvBuilder) types_builder = NULL; + + defaults = g_task_propagate_pointer (G_TASK (result), error); + + if (defaults == NULL) { + return NULL; + } + + ids_builder = g_strv_builder_new (); + types_builder = g_strv_builder_new (); + + for (i = 0; defaults->input_sources[i] != NULL; i++) { + g_strv_builder_add (types_builder, defaults->input_sources[i]->type); + g_strv_builder_add (ids_builder, defaults->input_sources[i]->id); + } + + if (types != NULL) + *types = g_strv_builder_end (types_builder); + + if (options != NULL) + *options = g_strdupv (defaults->options); + return g_strv_builder_end (ids_builder); +} diff --git a/libgnome-desktop/gnome-languages.h b/libgnome-desktop/gnome-languages.h index ed9242e7..e2cffa62 100644 --- a/libgnome-desktop/gnome-languages.h +++ b/libgnome-desktop/gnome-languages.h @@ -1,61 +1,71 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright 2008 Red Hat, Inc. * Copyright 2007 William Jon McCann * * 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: Ray Strode * William Jon McCann */ #ifndef __GNOME_LANGUAGES_H #define __GNOME_LANGUAGES_H #ifndef GNOME_DESKTOP_USE_UNSTABLE_API #error This is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-languages.h #endif #include +#include #include G_BEGIN_DECLS char * gnome_get_language_from_locale (const char *locale, const char *translation); char * gnome_get_country_from_locale (const char *locale, const char *translation); char ** gnome_get_all_locales (void); gboolean gnome_parse_locale (const char *locale, char **language_codep, char **country_codep, char **codesetp, char **modifierp); char * gnome_normalize_locale (const char *locale); gboolean gnome_language_has_translations (const char *code); char * gnome_get_language_from_code (const char *code, const char *translation); char * gnome_get_country_from_code (const char *code, const char *translation); char * gnome_get_translated_modifier (const char *modifier, const char *translation); gboolean gnome_get_input_source_from_locale (const char *locale, const char **type, const char **id); gboolean gnome_input_source_is_non_latin (const char *type, const char *id); + +void gnome_get_default_input_sources (GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +char ** gnome_get_default_input_sources_finish (GAsyncResult *result, + char ***types, + char ***options, + GError **error); G_END_DECLS #endif /* __GNOME_LANGUAGES_H */ -- 2.41.0.rc2