summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2020-05-13 15:59:49 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2020-09-25 14:27:15 +1000
commita980a4c83aab9d2f985d28be3e9263444a8beb41 (patch)
tree522b8c53e66db1c0ffa2c1d3b91c88a2ad61d92f
parent0b1f6d41d93eee42a751281b1b74ba74e5326031 (diff)
downloadgnome-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
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--config.h.meson3
-rw-r--r--libgnome-desktop/gnome-xkb-info.c145
-rw-r--r--libgnome-desktop/meson.build1
-rw-r--r--meson.build3
5 files changed, 153 insertions, 1 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b1a5d8e4..6fe953d9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,7 @@ image: fedora:rawhide
variables:
LAST_ABI_BREAK: 9d01763ba2a3f71b7c0aade04d2ffa6a883e308d
DEPENDENCIES: gtk3-devel gsettings-desktop-schemas-devel gettext
- gtk-doc xkeyboard-config-devel itstool
+ gtk-doc libxkbcommon-devel xkeyboard-config-devel itstool
gobject-introspection-devel systemd-devel iso-codes-devel
libseccomp-devel gcc gcc-c++ glibc-devel
meson redhat-rpm-config
diff --git a/config.h.meson b/config.h.meson
index 7a8d8d96..75b0170d 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -22,5 +22,8 @@
/* define if udev is available */
#mesondefine HAVE_UDEV
+/* define if libxkbregistry is available */
+#mesondefine HAVE_XKBREGISTRY
+
/* Define to include GNU extensions */
#mesondefine _GNU_SOURCE
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
diff --git a/meson.build b/meson.build
index 7ea72f71..2ec66471 100644
--- a/meson.build
+++ b/meson.build
@@ -47,6 +47,8 @@ gio_unix_dep = dependency('gio-unix-2.0', version: glib_req)
schemas_dep = dependency('gsettings-desktop-schemas', version: schemas_req)
fontconfig_dep = dependency('fontconfig')
xkb_config_dep = dependency('xkeyboard-config')
+xkbregistry_dep = dependency('xkbregistry', required: false)
+
iso_codes_dep = dependency('iso-codes')
libsystemd_dep = dependency('libsystemd', required: get_option('systemd'))
@@ -88,6 +90,7 @@ conf.set('_GNU_SOURCE', seccomp_dep.found())
conf.set('HAVE_SYSTEMD', libsystemd_dep.found())
conf.set('HAVE_UDEV', udev_dep.found())
+conf.set('HAVE_XKBREGISTRY', xkbregistry_dep.found())
conf.set('HAVE_TIMERFD', cc.has_function('timerfd_create'))
conf.set('HAVE_OPENAT', cc.has_function('openat'))