summaryrefslogtreecommitdiffstats
path: root/src/locale/xkbcommon-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/locale/xkbcommon-util.c')
-rw-r--r--src/locale/xkbcommon-util.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/locale/xkbcommon-util.c b/src/locale/xkbcommon-util.c
new file mode 100644
index 0000000..295ac8a
--- /dev/null
+++ b/src/locale/xkbcommon-util.c
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "dlfcn-util.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "xkbcommon-util.h"
+
+#if HAVE_XKBCOMMON
+static void *xkbcommon_dl = NULL;
+
+struct xkb_context* (*sym_xkb_context_new)(enum xkb_context_flags flags);
+void (*sym_xkb_context_unref)(struct xkb_context *context);
+void (*sym_xkb_context_set_log_fn)(
+ struct xkb_context *context,
+ void (*log_fn)(
+ struct xkb_context *context,
+ enum xkb_log_level level,
+ const char *format,
+ va_list args));
+struct xkb_keymap* (*sym_xkb_keymap_new_from_names)(
+ struct xkb_context *context,
+ const struct xkb_rule_names *names,
+ enum xkb_keymap_compile_flags flags);
+void (*sym_xkb_keymap_unref)(struct xkb_keymap *keymap);
+
+static int dlopen_xkbcommon(void) {
+ return dlopen_many_sym_or_warn(
+ &xkbcommon_dl, "libxkbcommon.so.0", LOG_DEBUG,
+ DLSYM_ARG(xkb_context_new),
+ DLSYM_ARG(xkb_context_unref),
+ DLSYM_ARG(xkb_context_set_log_fn),
+ DLSYM_ARG(xkb_keymap_new_from_names),
+ DLSYM_ARG(xkb_keymap_unref));
+}
+
+_printf_(3, 0)
+static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
+ const char *fmt;
+
+ fmt = strjoina("libxkbcommon: ", format);
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ log_internalv(LOG_DEBUG, 0, PROJECT_FILE, __LINE__, __func__, fmt, args);
+ REENABLE_WARNING;
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct xkb_context *, sym_xkb_context_unref, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct xkb_keymap *, sym_xkb_keymap_unref, NULL);
+
+int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
+ _cleanup_(sym_xkb_context_unrefp) struct xkb_context *ctx = NULL;
+ _cleanup_(sym_xkb_keymap_unrefp) struct xkb_keymap *km = NULL;
+ const struct xkb_rule_names rmlvo = {
+ .model = model,
+ .layout = layout,
+ .variant = variant,
+ .options = options,
+ };
+ int r;
+
+ /* Compile keymap from RMLVO information to check out its validity */
+
+ r = dlopen_xkbcommon();
+ if (r < 0)
+ return r;
+
+ ctx = sym_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
+ if (!ctx)
+ return -ENOMEM;
+
+ sym_xkb_context_set_log_fn(ctx, log_xkb);
+
+ km = sym_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ if (!km)
+ return -EINVAL;
+
+ return 0;
+}
+
+#endif