From d7b39f6ffbe9b46181c5597b0d0e7373eb2e9070 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 10 Jul 2020 08:50:02 +1000 Subject: [PATCH] Add /etc/xkb as extra lookup path for system data files This completes the usual triplet of configuration locations available for most processes: - vendor-provided data files in /usr/share/X11/xkb - system-specific data files in /etc/xkb - user-specific data files in $XDG_CONFIG_HOME/xkb The default lookup order user, system, vendor, just like everything else that uses these conventions. For include directives in rules files, the '%E' resolves to that path. Signed-off-by: Peter Hutterer --- doc/rules-format.md | 3 +++ doc/user-configuration.md | 2 ++ meson.build | 5 +++++ meson_options.txt | 5 +++++ src/context.c | 11 ++++++++++- src/context.h | 3 +++ src/registry.c | 8 +++++++- src/xkbcomp/rules.c | 7 +++++++ test/tool-option-parsing.py | 2 ++ xkbcommon/xkbcommon.h | 5 ++++- 10 files changed, 48 insertions(+), 3 deletions(-) diff --git a/doc/rules-format.md b/doc/rules-format.md index 96acbbf..f9fe0d9 100644 --- a/doc/rules-format.md +++ b/doc/rules-format.md @@ -73,6 +73,9 @@ Notes: %H: The value of the HOME environment variable. + %E: + The extra lookup path for system-wide XKB data (usually /etc/xkb/rules). + %S: The system-installed rules directory (usually /usr/share/X11/xkb/rules). ``` diff --git a/doc/user-configuration.md b/doc/user-configuration.md index 17e7179..b8c4d30 100644 --- a/doc/user-configuration.md +++ b/doc/user-configuration.md @@ -11,6 +11,8 @@ libxkbcommon searches the following paths for XKB configuration files: - `$XDG_CONFIG_HOME/xkb/`, or `$HOME/.config/xkb/` if the `$XDG_CONFIG_HOME` environment variable is not defined - `$HOME/.xkb/` +- `$XKB_CONFIG_EXTRA_PATH` if set, otherswise `/xkb` (on most + distributions this is `/etc/xkb`) - `$XKB_CONFIG_ROOT` if set, otherwise `/X11/xkb/` (path defined by the `xkeyboard-config` package, on most distributions this is `/usr/share/X11/xkb`) diff --git a/meson.build b/meson.build index e7d75aa..c08b40b 100644 --- a/meson.build +++ b/meson.build @@ -47,6 +47,10 @@ if XKBCONFIGROOT == '' endif endif +XKBCONFIGEXTRAPATH = get_option('xkb-config-extra-path') +if XKBCONFIGEXTRAPATH == '' + XKBCONFIGEXTRAPATH = join_paths(get_option('prefix'), get_option('sysconfdir'), 'xkb') +endif # The X locale directory for compose. XLOCALEDIR = get_option('x-locale-root') @@ -70,6 +74,7 @@ endif configh_data.set(system_extensions, 1) system_ext_define = '#define ' + system_extensions configh_data.set_quoted('DFLT_XKB_CONFIG_ROOT', XKBCONFIGROOT) +configh_data.set_quoted('DFLT_XKB_CONFIG_EXTRA_PATH', XKBCONFIGEXTRAPATH) configh_data.set_quoted('XLOCALEDIR', XLOCALEDIR) configh_data.set_quoted('DEFAULT_XKB_RULES', get_option('default-rules')) configh_data.set_quoted('DEFAULT_XKB_MODEL', get_option('default-model')) diff --git a/meson_options.txt b/meson_options.txt index 5eaa081..04982c6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,6 +4,11 @@ option( description: 'The XKB config root [default=xkeyboard-config install path]', ) option( + 'xkb-config-extra-path', + type: 'string', + description: 'Extra lookup path for system-wide XKB data [default=$sysconfdir/xkb]', +) +option( 'x-locale-root', type: 'string', description: 'The X locale root [default=$datadir/X11/locale]', diff --git a/src/context.c b/src/context.c index ef9b774..2abaa9b 100644 --- a/src/context.c +++ b/src/context.c @@ -84,6 +84,13 @@ err: } const char * +xkb_context_include_path_get_extra_path(struct xkb_context *ctx) +{ + const char *extra = secure_getenv("XKB_CONFIG_EXTRA_PATH"); + return extra ? extra : DFLT_XKB_CONFIG_EXTRA_PATH; +} + +const char * xkb_context_include_path_get_system_path(struct xkb_context *ctx) { const char *root = secure_getenv("XKB_CONFIG_ROOT"); @@ -96,7 +103,7 @@ xkb_context_include_path_get_system_path(struct xkb_context *ctx) XKB_EXPORT int xkb_context_include_path_append_default(struct xkb_context *ctx) { - const char *home, *xdg, *root; + const char *home, *xdg, *root, *extra; char *user_path; int ret = 0; @@ -126,6 +133,8 @@ xkb_context_include_path_append_default(struct xkb_context *ctx) } } + extra = xkb_context_include_path_get_extra_path(ctx); + ret |= xkb_context_include_path_append(ctx, extra); root = xkb_context_include_path_get_system_path(ctx); ret |= xkb_context_include_path_append(ctx, root); diff --git a/src/context.h b/src/context.h index 9584dbc..ead2508 100644 --- a/src/context.h +++ b/src/context.h @@ -60,6 +60,9 @@ xkb_context_failed_include_path_get(struct xkb_context *ctx, unsigned int idx); const char * +xkb_context_include_path_get_extra_path(struct xkb_context *ctx); + +const char * xkb_context_include_path_get_system_path(struct xkb_context *ctx); /* diff --git a/src/registry.c b/src/registry.c index 956d850..d3d95f5 100644 --- a/src/registry.c +++ b/src/registry.c @@ -583,7 +583,7 @@ err: XKB_EXPORT bool rxkb_context_include_path_append_default(struct rxkb_context *ctx) { - const char *home, *xdg, *root; + const char *home, *xdg, *root, *extra; char *user_path; bool ret = false; @@ -618,6 +618,12 @@ rxkb_context_include_path_append_default(struct rxkb_context *ctx) } } + extra = secure_getenv("XKB_CONFIG_EXTRA_PATH"); + if (extra != NULL) + ret |= rxkb_context_include_path_append(ctx, extra); + else + ret |= rxkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_EXTRA_PATH); + root = secure_getenv("XKB_CONFIG_ROOT"); if (root != NULL) ret |= rxkb_context_include_path_append(ctx, root); diff --git a/src/xkbcomp/rules.c b/src/xkbcomp/rules.c index 3359552..099500a 100644 --- a/src/xkbcomp/rules.c +++ b/src/xkbcomp/rules.c @@ -399,6 +399,13 @@ matcher_include(struct matcher *m, struct scanner *parent_scanner, return; } } + else if (chr(&s, 'E')) { + const char *default_root = xkb_context_include_path_get_extra_path(m->ctx); + if (!buf_appends(&s, default_root) || !buf_appends(&s, "/rules")) { + scanner_err(&s, "include path after expanding %%E is too long"); + return; + } + } else { scanner_err(&s, "unknown %% format (%c) in include statement", peek(&s)); return; diff --git a/test/tool-option-parsing.py b/test/tool-option-parsing.py index c503176..de638d1 100755 --- a/test/tool-option-parsing.py +++ b/test/tool-option-parsing.py @@ -306,5 +306,7 @@ if __name__ == '__main__': # to override it with a known (empty) directory. Otherwise our test # behavior depends on the system the test is run on. os.environ['XDG_CONFIG_HOME'] = tmpdir + # This needs to be separated if we do specific extra path testing + os.environ['XKB_CONFIG_EXTRA_PATH'] = tmpdir sys.exit(pytest.main(args=[__file__])) diff --git a/xkbcommon/xkbcommon.h b/xkbcommon/xkbcommon.h index c091e5d..5fabc34 100644 --- a/xkbcommon/xkbcommon.h +++ b/xkbcommon/xkbcommon.h @@ -553,7 +553,7 @@ xkb_keysym_to_lower(xkb_keysym_t ks); * * The user may set some environment variables which affect the library: * - * - `XKB_CONFIG_ROOT`, `XDG_CONFIG_DIR`, `HOME` - see @ref include-path. + * - `XKB_CONFIG_ROOT`, `XKB_EXTRA_PATH`, `XDG_CONFIG_DIR`, `HOME` - see @ref include-path. * - `XKB_LOG_LEVEL` - see xkb_context_set_log_level(). * - `XKB_LOG_VERBOSITY` - see xkb_context_set_log_verbosity(). * - `XKB_DEFAULT_RULES`, `XKB_DEFAULT_MODEL`, `XKB_DEFAULT_LAYOUT`, @@ -644,6 +644,9 @@ xkb_context_get_user_data(struct xkb_context *context); * fallback to `$HOME/.config/` if unset. * - The path `$HOME/.xkb`, where $HOME is the value of the environment * variable `HOME`. + * - The `XKB_EXTRA_PATH` environment variable, if defined, otherwise the + * system configuration directory, defined at library configuration time + * (usually `/etc/xkb`). * - The `XKB_CONFIG_ROOT` environment variable, if defined, otherwise * the system XKB root, defined at library configuration time. * -- 2.7.4