Commit a980a4c8 authored by Peter Hutterer's avatar Peter Hutterer

xkbinfo: use libxkbregistry to parse the rules files for us

Version 2, this time with libxkbregistry build-time conditional, see
4f6bec60 for the first commit, reverted in
a8c94b74 due to
gnome-build-meta#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
!79

!88
parent 0b1f6d41
Pipeline #216328 passed with stage
in 10 minutes and 16 seconds
......@@ -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
......
......@@ -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
......@@ -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)
{
......
......@@ -80,6 +80,7 @@ gnome_desktop_deps = [
libsystemd_dep,
schemas_dep,
xkb_config_dep,
xkbregistry_dep,
iso_codes_dep,
udev_dep,
seccomp_dep
......
......@@ -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'))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment