Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable out-of-range group action configuration using options API (take 3) #516

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changes/api/+keymap-compile-options.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Added a new keymap compile options API:
- `xkb_keymap_compile_options_new`
- `xkb_keymap_compile_options_free`
- `xkb_keymap_compile_options_set_layout_out_of_range_action`
- `xkb_keymap_new_from_names2`
- `xkb_keymap_new_from_file2`
- `xkb_keymap_new_from_buffer2`

This interface allows to configure keymap options that cannot be passed as flags.
9 changes: 9 additions & 0 deletions changes/api/+out-of-range-layout-config.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Enable the configuration of out-of-range layout handling using the new function
`xkb_keymap_compile_options_set_layout_out_of_range_action` and the corresponding
new enumeration `xkb_keymap_out_of_range_layout_action`:
- `XKB_KEYMAP_WRAP_OUT_OF_RANGE_LAYOUT`: wrap into range using integer modulus (default).
- `XKB_KEYMAP_REDIRECT_OUT_OF_RANGE_LAYOUT`: redirect to a specific layout index.
- `XKB_KEYMAP_CLAMP_OUT_OF_RANGE_LAYOUT`: clamp into range, i.e. invalid indexes are
corrected to the closest valid bound (0 or highest layout index).

When not specified, invalid groups are brought into range using integer modulus.
170 changes: 163 additions & 7 deletions include/xkbcommon/xkbcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#define _XKBCOMMON_H_

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>

Expand Down Expand Up @@ -878,6 +879,109 @@ enum xkb_keymap_compile_flags {
XKB_KEYMAP_COMPILE_NO_FLAGS = 0
};

/** The possible keymap formats. */
enum xkb_keymap_format {
/** The current/classic XKB text format, as generated by xkbcomp -xkb. */
XKB_KEYMAP_FORMAT_TEXT_V1 = 1
};

/**
* @struct xkb_keymap_compile_options
* Opaque keymap compilation options.
*
* TODO: more doc
*
* @since 1.8.0
*/
struct xkb_keymap_compile_options;

/**
* Create a keymap options object.
*
* TODO: more doc
*
* @since 1.8.0
*/
struct xkb_keymap_compile_options*
xkb_keymap_compile_options_new(enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags);

/**
* Destroy a keymap compilation options object.
*
* TODO: more doc
*
* @since 1.8.0
*/
void
xkb_keymap_compile_options_free(struct xkb_keymap_compile_options *options);

/** Out-of-range layout action
*
* [Effective layout] index may be invalid in some contexts.
* One of the following out-of-range layout action is then used to bring invalid
* layout indexes back into range:
*
* - “redirect into range” (see: ::XKB_KEYMAP_REDIRECT_OUT_OF_RANGE_LAYOUT)
* - “clamp into range” (see: ::XKB_KEYMAP_CLAMP_OUT_OF_RANGE_LAYOUT)
* - “wrap into range” using integer modulus (default)
*
* [Effective layout]: @ref ::XKB_STATE_LAYOUT_EFFECTIVE
*
* @since 1.8.0
*/
enum xkb_keymap_out_of_range_layout_action {
/**
* TODO: doc
*/
XKB_KEYMAP_WRAP_OUT_OF_RANGE_LAYOUT = 0,
/**
* Set the out-of-range layout action to “redirect into range”.
*
* - If the [effective layout] is invalid, it is set to a *target layout*.
* - If the target layout is invalid, it is set to the first one (0).
*
* A *target layout index* (range 0..15) may be provided using the 4 least
* significant bits of the corresponding #xkb_keymap_compile_flags value,
* e.g.:
*
* ```c
* // Set the target layout index to 1.
* enum xkb_keymap_compile_flags flags = XKB_KEYMAP_REDIRECT_OUT_OF_RANGE_LAYOUT | 1;
* ```
*
* @since 1.8.0
*
* [effective layout]: @ref ::XKB_STATE_LAYOUT_EFFECTIVE
*/
XKB_KEYMAP_REDIRECT_OUT_OF_RANGE_LAYOUT,
/**
* Set the out-of-range layout action to “clamp into range”: if the
* [effective layout] is invalid, it is set to nearest valid layout:
*
* - effective layout larger than the highest supported layout are mapped to
* the highest supported layout;
* - effective layout less than 0 are mapped to 0.
*
* @since 1.8.0
*
* [effective layout]: @ref ::XKB_STATE_LAYOUT_EFFECTIVE
*/
XKB_KEYMAP_CLAMP_OUT_OF_RANGE_LAYOUT
};

/**
* TODO: more doc
*
* @since 1.8.0
*/
bool
xkb_keymap_compile_options_set_layout_out_of_range_action(
struct xkb_keymap_compile_options *options,
enum xkb_keymap_out_of_range_layout_action,
xkb_layout_index_t target
);

/**
* Create a keymap from RMLVO names.
*
Expand All @@ -886,7 +990,7 @@ enum xkb_keymap_compile_flags {
*
* @param context The context in which to create the keymap.
* @param names The RMLVO names to use. See xkb_rule_names.
* @param flags Optional flags for the keymap, or 0.
* @param flags Optional flags for the keymap, or ::XKB_KEYMAP_COMPILE_NO_FLAGS.
*
* @returns A keymap compiled according to the RMLVO names, or NULL if
* the compilation failed.
Expand All @@ -899,19 +1003,36 @@ xkb_keymap_new_from_names(struct xkb_context *context,
const struct xkb_rule_names *names,
enum xkb_keymap_compile_flags flags);

/** The possible keymap formats. */
enum xkb_keymap_format {
/** The current/classic XKB text format, as generated by xkbcomp -xkb. */
XKB_KEYMAP_FORMAT_TEXT_V1 = 1
};
/**
* Create a keymap from RMLVO names.
*
* The primary keymap entry point: creates a new XKB keymap from a set of
* RMLVO (Rules + Model + Layouts + Variants + Options) names.
*
* @param context The context in which to create the keymap.
* @param names The RMLVO names to use. See xkb_rule_names.
* @param options The eymap compilation options.
*
* @returns A keymap compiled according to the RMLVO names, or NULL if
* the compilation failed.
*
* @sa xkb_rule_names, xkb_keymap_new_from_names()
* @memberof xkb_keymap
*
* @since 1.8.0
*/
struct xkb_keymap *
xkb_keymap_new_from_names2(struct xkb_context *context,
const struct xkb_rule_names *names,
const struct xkb_keymap_compile_options *options);

/**
* Create a keymap from a keymap file.
*
* @param context The context in which to create the keymap.
* @param file The keymap file to compile.
* @param format The text format of the keymap file to compile.
* @param flags Optional flags for the keymap, or 0.
* @param flags Optional flags for the keymap, or ::XKB_KEYMAP_COMPILE_NO_FLAGS.
*
* @returns A keymap compiled from the given XKB keymap file, or NULL if
* the compilation failed.
Expand All @@ -928,6 +1049,29 @@ xkb_keymap_new_from_file(struct xkb_context *context, FILE *file,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags);

/**
* Create a keymap from a keymap file.
*
* @param context The context in which to create the keymap.
* @param file The keymap file to compile.
* @param options The Keymap compilation options.
*
* @returns A keymap compiled from the given XKB keymap file, or NULL if
* the compilation failed.
*
* The file must contain a complete keymap. For example, in the
* XKB_KEYMAP_FORMAT_TEXT_V1 format, this means the file must contain one
* top level '%xkb_keymap' section, which in turn contains other required
* sections.
*
* @since 1.8.0
*
* @memberof xkb_keymap, xkb_keymap_new_from_file2()
*/
struct xkb_keymap *
xkb_keymap_new_from_file2(struct xkb_context *context, FILE *file,
const struct xkb_keymap_compile_options *options);

/**
* Create a keymap from a keymap string.
*
Expand Down Expand Up @@ -957,6 +1101,18 @@ xkb_keymap_new_from_buffer(struct xkb_context *context, const char *buffer,
size_t length, enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags);

/**
* Create a keymap from a memory buffer.
*
* @see xkb_keymap_new_from_buffer()
* @memberof xkb_keymap
* @since 1.8.0
*/
struct xkb_keymap *
xkb_keymap_new_from_buffer2(struct xkb_context *context,
const char *buffer, size_t length,
const struct xkb_keymap_compile_options *options);

/**
* Take a new reference on a keymap.
*
Expand Down
37 changes: 33 additions & 4 deletions src/keymap-priv.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,36 @@ update_builtin_keymap_fields(struct xkb_keymap *keymap)

struct xkb_keymap *
xkb_keymap_new(struct xkb_context *ctx,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
const struct xkb_keymap_compile_options *options)
{
struct xkb_keymap *keymap;
enum xkb_range_exceed_type out_of_range_group_action;
xkb_layout_index_t out_of_range_group_number = options->out_of_range_group_number;

switch (options->out_of_range_group_action) {
case XKB_KEYMAP_WRAP_OUT_OF_RANGE_LAYOUT:
out_of_range_group_action = RANGE_WRAP;
break;
case XKB_KEYMAP_REDIRECT_OUT_OF_RANGE_LAYOUT:
out_of_range_group_action = RANGE_REDIRECT;
break;
case XKB_KEYMAP_CLAMP_OUT_OF_RANGE_LAYOUT:
out_of_range_group_action = RANGE_SATURATE;
break;
default:
log_err(ctx, XKB_LOG_MESSAGE_NO_ID,
"Unsupported \"out of range layout\" action: %#x\n",
options->out_of_range_group_action);
return NULL;
}

if (out_of_range_group_number && out_of_range_group_action != RANGE_REDIRECT) {
log_err(ctx, XKB_LOG_MESSAGE_NO_ID,
"Redirect layout index can only be used in combination with "
"XKB_KEYMAP_REDIRECT_OUT_OF_RANGE_LAYOUT action, but got: %#x\n",
options->out_of_range_group_action);
return NULL;
}

keymap = calloc(1, sizeof(*keymap));
if (!keymap)
Expand All @@ -66,8 +92,11 @@ xkb_keymap_new(struct xkb_context *ctx,
keymap->refcnt = 1;
keymap->ctx = xkb_context_ref(ctx);

keymap->format = format;
keymap->flags = flags;
keymap->format = options->format;
keymap->flags = options->flags;

keymap->out_of_range_group_action = out_of_range_group_action;
keymap->out_of_range_group_number = out_of_range_group_number;

update_builtin_keymap_fields(keymap);

Expand Down
Loading
Loading