diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2020-05-13 15:59:49 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2020-09-25 14:27:15 +1000 |
commit | a980a4c83aab9d2f985d28be3e9263444a8beb41 (patch) | |
tree | 522b8c53e66db1c0ffa2c1d3b91c88a2ad61d92f /libgnome-desktop | |
parent | 0b1f6d41d93eee42a751281b1b74ba74e5326031 (diff) | |
download | gnome-desktop-a980a4c83aab9d2f985d28be3e9263444a8beb41.tar.gz |
xkbinfo: use libxkbregistry to parse the rules files for us
Version 2, this time with libxkbregistry build-time conditional, see
4f6bec60bfc781c59d5afb6f968fc94ad859e5b9 for the first commit, reverted in
a8c94b74a8182c48eb5cd5e2cc9b03d5ee52d4bd due to
https://gitlab.gnome.org/GNOME/gnome-build-meta/-/issues/329.
Available in libxkbcommon 1.0.0 and later, libxkbregistry is a library wrapper
around the evdev.xml rules file that we used to parse directly here. It
provides a basic iteration API - load the evdev ruleset, then iterate through
the layouts and options and copy the values over into our data structures as
needed. This removes the need for XML parsing and error-checking, we can now
rely on libxkbregistry to do this for us.
The side-effect of this (and motivation for libxkbregistry) is that we
automatically load user-specific XKB RMLVO as well where they are present.
Together with mutter commit f71238732508d91bdfcb581c84697a516499a1eb this
allows a user to drop up their custom XKB layouts in
$XDG_CONFIG_DIR/xkb and have them both listed in the GUIs and working.
See original MR at
https://gitlab.gnome.org/GNOME/gnome-desktop/-/merge_requests/79
https://gitlab.gnome.org/GNOME/gnome-desktop/-/merge_requests/88
Diffstat (limited to 'libgnome-desktop')
-rw-r--r-- | libgnome-desktop/gnome-xkb-info.c | 145 | ||||
-rw-r--r-- | libgnome-desktop/meson.build | 1 |
2 files changed, 146 insertions, 0 deletions
diff --git a/libgnome-desktop/gnome-xkb-info.c b/libgnome-desktop/gnome-xkb-info.c index bcee465a..61409210 100644 --- a/libgnome-desktop/gnome-xkb-info.c +++ b/libgnome-desktop/gnome-xkb-info.c @@ -21,6 +21,10 @@ #include <config.h> +#ifdef HAVE_XKBREGISTRY +#include <xkbcommon/xkbregistry.h> +#endif + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -74,6 +78,7 @@ struct _GnomeXkbInfoPrivate GHashTable *layouts_by_language; GHashTable *layouts_table; +#ifndef HAVE_XKBREGISTRY /* Only used while parsing */ XkbOptionGroup *current_parser_group; XkbOption *current_parser_option; @@ -82,6 +87,7 @@ struct _GnomeXkbInfoPrivate gchar *current_parser_iso639Id; gchar *current_parser_iso3166Id; gchar **current_parser_text; +#endif }; G_DEFINE_TYPE_WITH_CODE (GnomeXkbInfo, gnome_xkb_info, G_TYPE_OBJECT, @@ -192,6 +198,143 @@ add_layout_to_locale_tables (Layout *layout, } } +#ifdef HAVE_XKBREGISTRY +typedef enum { + ONLY_MAIN_LAYOUTS, + ONLY_VARIANTS, +} LayoutSubset; + +static void +add_layouts (GnomeXkbInfo *self, + struct rxkb_context *ctx, + LayoutSubset which) +{ + GnomeXkbInfoPrivate *priv = self->priv; + struct rxkb_layout *layout; + + for (layout = rxkb_layout_first (ctx); + layout; + layout = rxkb_layout_next (layout)) + { + struct rxkb_iso639_code *iso639; + struct rxkb_iso3166_code *iso3166; + const char *name, *variant; + Layout *l; + + name = rxkb_layout_get_name (layout); + variant = rxkb_layout_get_variant (layout); + + if ((which == ONLY_VARIANTS && variant == NULL) || + (which == ONLY_MAIN_LAYOUTS && variant != NULL)) + continue; + + l = g_slice_new0 (Layout); + if (variant) + { + /* This relies on the main layouts being added first */ + l->main_layout = g_hash_table_lookup (priv->layouts_table, name); + if (l->main_layout == NULL) + { + /* This is a bug in libxkbregistry */ + g_warning ("Ignoring variant '%s(%s)' without a main layout", + name, variant); + g_free (l); + continue; + } + + l->xkb_name = g_strdup (variant); + l->is_variant = TRUE; + l->id = g_strjoin ("+", name, variant, NULL); + } + else + { + l->xkb_name = g_strdup (name); + l->id = g_strdup (name); + } + l->description = g_strdup (rxkb_layout_get_description (layout)); + l->short_desc = g_strdup (rxkb_layout_get_brief (layout)); + for (iso639 = rxkb_layout_get_iso639_first (layout); + iso639; + iso639 = rxkb_iso639_code_next (iso639)) + { + char *id = g_strdup (rxkb_iso639_code_get_code (iso639)); + l->iso3166Ids = g_slist_prepend (l->iso3166Ids, id); + } + for (iso3166 = rxkb_layout_get_iso3166_first (layout); + iso3166; + iso3166 = rxkb_iso3166_code_next (iso3166)) + { + char *id = g_strdup (rxkb_iso3166_code_get_code (iso3166)); + l->iso3166Ids = g_slist_prepend (l->iso3166Ids, id); + } + + g_hash_table_replace (priv->layouts_table, l->id, l); + add_layout_to_locale_tables (l, + priv->layouts_by_language, + priv->layouts_by_country); + } +} + +static gboolean +parse_rules_file (GnomeXkbInfo *self, + const gchar *ruleset, + gboolean include_extras) +{ + GnomeXkbInfoPrivate *priv = self->priv; + struct rxkb_context *ctx; + struct rxkb_option_group *group; + enum rxkb_context_flags flags = RXKB_CONTEXT_NO_FLAGS; + + if (include_extras) + flags |= RXKB_CONTEXT_LOAD_EXOTIC_RULES; + + ctx = rxkb_context_new (flags); + if (!rxkb_context_parse (ctx, ruleset)) { + rxkb_context_unref (ctx); + return FALSE; + } + + /* libxkbregistry doesn't guarantee a sorting order of the layouts but we + * want to reference the main layout from the variants. So populate with + * the main layouts first, then add the variants */ + add_layouts (self, ctx, ONLY_MAIN_LAYOUTS); + add_layouts (self, ctx, ONLY_VARIANTS); + + for (group = rxkb_option_group_first (ctx); + group; + group = rxkb_option_group_next (group)) + { + XkbOptionGroup *g; + struct rxkb_option *option; + + g = g_slice_new (XkbOptionGroup); + g->id = g_strdup (rxkb_option_group_get_name (group)); + g->description = g_strdup (rxkb_option_group_get_description (group)); + g->options_table = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, free_option); + g->allow_multiple_selection = rxkb_option_group_allows_multiple (group); + g_hash_table_replace (priv->option_groups_table, g->id, g); + + for (option = rxkb_option_first (group); + option; + option = rxkb_option_next (option)) + { + XkbOption *o; + + o = g_slice_new (XkbOption); + o->id = g_strdup (rxkb_option_get_name (option)); + o->description = g_strdup(rxkb_option_get_description (option)); + g_hash_table_replace (g->options_table, o->id, o); + } + } + + rxkb_context_unref (ctx); + + return TRUE; +} + +#else /* HAVE_XKBREGISTRY */ + static gchar * get_xml_rules_file_path (const gchar *ruleset, const gchar *suffix) @@ -585,6 +728,8 @@ parse_rules_file (GnomeXkbInfo *self, return FALSE; } +#endif /* HAVE_XKBREGISTRY */ + static void parse_rules (GnomeXkbInfo *self) { diff --git a/libgnome-desktop/meson.build b/libgnome-desktop/meson.build index ca1e4b2a..b10a18df 100644 --- a/libgnome-desktop/meson.build +++ b/libgnome-desktop/meson.build @@ -80,6 +80,7 @@ gnome_desktop_deps = [ libsystemd_dep, schemas_dep, xkb_config_dep, + xkbregistry_dep, iso_codes_dep, udev_dep, seccomp_dep |