X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fxkbcomp%2Fcompat.c;h=44a444cccc9ba260ae4945b1c87e6a5cc0e8bca7;hb=f00e4d030c9dd49e40a8fa08fcae0c1a1be5cf14;hp=33315ad8ec555aec6a035b5e6139f09a0cc71e4a;hpb=8ccfee82ec7fbc36b8009bc1686783e920d7b879;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/xkbcomp/compat.c b/src/xkbcomp/compat.c index 33315ad..44a444c 100644 --- a/src/xkbcomp/compat.c +++ b/src/xkbcomp/compat.c @@ -24,99 +24,99 @@ * ********************************************************/ +/* + * Copyright © 2012 Ran Benita + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + #include "xkbcomp-priv.h" -#include "parseutils.h" +#include "text.h" +#include "expr.h" #include "action.h" #include "vmod.h" +#include "include.h" enum si_field { - SI_FIELD_VIRTUAL_MOD = (1 << 0), - SI_FIELD_ACTION = (1 << 1), - SI_FIELD_AUTO_REPEAT = (1 << 2), - SI_FIELD_LOCKING_KEY = (1 << 3), - SI_FIELD_LEVEL_ONE_ONLY = (1 << 4), + SI_FIELD_VIRTUAL_MOD = (1 << 0), + SI_FIELD_ACTION = (1 << 1), + SI_FIELD_AUTO_REPEAT = (1 << 2), + SI_FIELD_LEVEL_ONE_ONLY = (1 << 3), }; -typedef struct _SymInterpInfo { +typedef struct { enum si_field defined; - unsigned file_id; enum merge_mode merge; - struct list entry; struct xkb_sym_interpret interp; } SymInterpInfo; enum led_field { - LED_FIELD_INDEX = (1 << 0), - LED_FIELD_MODS = (1 << 1), - LED_FIELD_GROUPS = (1 << 2), - LED_FIELD_CTRLS = (1 << 3), - LED_FIELD_EXPLICIT = (1 << 4), - LED_FIELD_AUTOMATIC = (1 << 5), - LED_FIELD_DRIVES_KBD = (1 << 6), + LED_FIELD_MODS = (1 << 0), + LED_FIELD_GROUPS = (1 << 1), + LED_FIELD_CTRLS = (1 << 2), }; -typedef struct _LEDInfo { +typedef struct { enum led_field defined; - unsigned file_id; - enum merge_mode merge; - struct list entry; - - xkb_atom_t name; - xkb_led_index_t indicator; - unsigned char flags; - unsigned char which_mods; - unsigned char real_mods; - xkb_mod_mask_t vmods; - unsigned char which_groups; - uint32_t groups; - unsigned int ctrls; -} LEDInfo; - -typedef struct _GroupCompatInfo { - unsigned file_id; enum merge_mode merge; - bool defined; - unsigned char real_mods; - xkb_atom_t vmods; -} GroupCompatInfo; -typedef struct _CompatInfo { + struct xkb_led led; +} LedInfo; + +typedef struct { char *name; - unsigned file_id; int errorCount; - int nInterps; - struct list interps; - SymInterpInfo dflt; - LEDInfo ledDflt; - GroupCompatInfo groupCompat[XkbNumKbdGroups]; - struct list leds; - VModInfo vmods; - ActionInfo *act; - struct xkb_keymap *keymap; + SymInterpInfo default_interp; + darray(SymInterpInfo) interps; + LedInfo default_led; + LedInfo leds[XKB_MAX_LEDS]; + unsigned int num_leds; + ActionsInfo *actions; + struct xkb_mod_set mods; + + struct xkb_context *ctx; } CompatInfo; static const char * -siText(SymInterpInfo * si, CompatInfo * info) +siText(SymInterpInfo *si, CompatInfo *info) { - static char buf[128]; + char *buf = xkb_context_get_buffer(info->ctx, 128); + + if (si == &info->default_interp) + return "default"; + + snprintf(buf, 128, "%s+%s(%s)", + KeysymText(info->ctx, si->interp.sym), + SIMatchText(si->interp.match), + ModMaskText(info->ctx, &info->mods, si->interp.mods)); - if (si == &info->dflt) { - snprintf(buf, sizeof(buf), "default"); - } - else { - snprintf(buf, sizeof(buf), "%s+%s(%s)", - KeysymText(si->interp.sym), - SIMatchText(si->interp.match), - ModMaskText(si->interp.mods, false)); - } return buf; } static inline bool ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field) { - return ReportNotArray(info->keymap, "symbol interpretation", field, + return ReportNotArray(info->ctx, "symbol interpretation", field, siText(si, info)); } @@ -124,124 +124,54 @@ static inline bool ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field, const char *wanted) { - return ReportBadType(info->keymap, "symbol interpretation", field, + return ReportBadType(info->ctx, XKB_ERROR_WRONG_FIELD_TYPE, + "symbol interpretation", field, siText(si, info), wanted); } static inline bool -ReportIndicatorBadType(CompatInfo *info, LEDInfo *led, - const char *field, const char *wanted) +ReportLedBadType(CompatInfo *info, LedInfo *ledi, const char *field, + const char *wanted) { - return ReportBadType(info->keymap, "indicator map", field, - xkb_atom_text(info->keymap->ctx, led->name), + return ReportBadType(info->ctx, XKB_ERROR_WRONG_FIELD_TYPE, + "indicator map", field, + xkb_atom_text(info->ctx, ledi->led.name), wanted); } static inline bool -ReportIndicatorNotArray(CompatInfo *info, LEDInfo *led, - const char *field) -{ - return ReportNotArray(info->keymap, "indicator map", field, - xkb_atom_text(info->keymap->ctx, led->name)); -} - -static void -ClearIndicatorMapInfo(struct xkb_context *ctx, LEDInfo * info) +ReportLedNotArray(CompatInfo *info, LedInfo *ledi, const char *field) { - info->name = xkb_atom_intern(ctx, "default"); - info->indicator = XKB_LED_INVALID; - info->flags = info->which_mods = info->real_mods = 0; - info->vmods = 0; - info->which_groups = info->groups = 0; - info->ctrls = 0; + return ReportNotArray(info->ctx, "indicator map", field, + xkb_atom_text(info->ctx, ledi->led.name)); } static void -InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id) +InitCompatInfo(CompatInfo *info, struct xkb_context *ctx, + ActionsInfo *actions, const struct xkb_mod_set *mods) { - unsigned int i; - - info->keymap = keymap; - info->name = NULL; - info->file_id = file_id; - info->errorCount = 0; - info->nInterps = 0; - list_init(&info->interps); - info->act = NULL; - info->dflt.file_id = file_id; - info->dflt.defined = 0; - info->dflt.merge = MERGE_OVERRIDE; - info->dflt.interp.flags = 0; - info->dflt.interp.virtual_mod = XkbNoModifier; - info->dflt.interp.act.type = XkbSA_NoAction; - for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++) - info->dflt.interp.act.any.data[i] = 0; - ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt); - info->ledDflt.file_id = file_id; - info->ledDflt.defined = 0; - info->ledDflt.merge = MERGE_OVERRIDE; - memset(&info->groupCompat[0], 0, - XkbNumKbdGroups * sizeof(GroupCompatInfo)); - list_init(&info->leds); - InitVModInfo(&info->vmods, keymap); + memset(info, 0, sizeof(*info)); + info->ctx = ctx; + info->actions = actions; + info->mods = *mods; + info->default_interp.merge = MERGE_OVERRIDE; + info->default_interp.interp.virtual_mod = XKB_MOD_INVALID; + info->default_led.merge = MERGE_OVERRIDE; } static void ClearCompatInfo(CompatInfo *info) { - unsigned int i; - ActionInfo *next_act; - SymInterpInfo *si, *next_si; - LEDInfo *led, *next_led; - struct xkb_keymap *keymap = info->keymap; - free(info->name); - info->name = NULL; - info->dflt.defined = 0; - info->dflt.merge = MERGE_AUGMENT; - info->dflt.interp.flags = 0; - info->dflt.interp.virtual_mod = XkbNoModifier; - info->dflt.interp.act.type = XkbSA_NoAction; - for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++) - info->dflt.interp.act.any.data[i] = 0; - ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt); - info->nInterps = 0; - list_foreach_safe(si, next_si, &info->interps, entry) - free(si); - memset(&info->groupCompat[0], 0, - XkbNumKbdGroups * sizeof(GroupCompatInfo)); - list_foreach_safe(led, next_led, &info->leds, entry) - free(led); - while (info->act) { - next_act = info->act->next; - free(info->act); - info->act = next_act; - } - info->keymap = NULL; - ClearVModInfo(&info->vmods, keymap); + darray_free(info->interps); } static SymInterpInfo * -NextInterp(CompatInfo * info) -{ - SymInterpInfo *si; - - si = calloc(1, sizeof(*si)); - if (!si) - return NULL; - - list_append(&si->entry, &info->interps); - info->nInterps++; - - return si; -} - -static SymInterpInfo * -FindMatchingInterp(CompatInfo * info, SymInterpInfo * new) +FindMatchingInterp(CompatInfo *info, SymInterpInfo *new) { SymInterpInfo *old; - list_foreach(old, &info->interps, entry) + darray_foreach(old, info->interps) if (old->interp.sym == new->interp.sym && old->interp.mods == new->interp.mods && old->interp.match == new->interp.match) @@ -252,13 +182,13 @@ FindMatchingInterp(CompatInfo * info, SymInterpInfo * new) static bool UseNewInterpField(enum si_field field, SymInterpInfo *old, SymInterpInfo *new, - int verbosity, enum si_field *collide) + bool report, enum si_field *collide) { if (!(old->defined & field)) return true; if (new->defined & field) { - if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9) + if (report) *collide |= field; if (new->merge != MERGE_AUGMENT) @@ -269,60 +199,47 @@ UseNewInterpField(enum si_field field, SymInterpInfo *old, SymInterpInfo *new, } static bool -AddInterp(CompatInfo * info, SymInterpInfo * new) +AddInterp(CompatInfo *info, SymInterpInfo *new, bool same_file) { - enum si_field collide; - SymInterpInfo *old; - struct list entry; - int verbosity = xkb_get_log_verbosity(info->keymap->ctx); + SymInterpInfo *old = FindMatchingInterp(info, new); + if (old) { + const int verbosity = xkb_context_get_log_verbosity(info->ctx); + const bool report = (same_file && verbosity > 0) || verbosity > 9; + enum si_field collide = 0; - collide = 0; - old = FindMatchingInterp(info, new); - if (old != NULL) { if (new->merge == MERGE_REPLACE) { - entry = old->entry; - if ((old->file_id == new->file_id && verbosity > 0) || - verbosity > 9) - log_warn(info->keymap->ctx, + if (report) + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Multiple definitions for \"%s\"; " "Earlier interpretation ignored\n", siText(new, info)); *old = *new; - old->entry = entry; return true; } - if (UseNewInterpField(SI_FIELD_VIRTUAL_MOD, old, new, verbosity, + if (UseNewInterpField(SI_FIELD_VIRTUAL_MOD, old, new, report, &collide)) { old->interp.virtual_mod = new->interp.virtual_mod; old->defined |= SI_FIELD_VIRTUAL_MOD; } - if (UseNewInterpField(SI_FIELD_ACTION, old, new, verbosity, + if (UseNewInterpField(SI_FIELD_ACTION, old, new, report, &collide)) { - old->interp.act = new->interp.act; + old->interp.action = new->interp.action; old->defined |= SI_FIELD_ACTION; } - if (UseNewInterpField(SI_FIELD_AUTO_REPEAT, old, new, verbosity, + if (UseNewInterpField(SI_FIELD_AUTO_REPEAT, old, new, report, &collide)) { - old->interp.flags &= ~XkbSI_AutoRepeat; - old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat); + old->interp.repeat = new->interp.repeat; old->defined |= SI_FIELD_AUTO_REPEAT; } - if (UseNewInterpField(SI_FIELD_LOCKING_KEY, old, new, verbosity, - &collide)) { - old->interp.flags &= ~XkbSI_LockingKey; - old->interp.flags |= (new->interp.flags & XkbSI_LockingKey); - old->defined |= SI_FIELD_LOCKING_KEY; - } - if (UseNewInterpField(SI_FIELD_LEVEL_ONE_ONLY, old, new, verbosity, + if (UseNewInterpField(SI_FIELD_LEVEL_ONE_ONLY, old, new, report, &collide)) { - old->interp.match &= ~XkbSI_LevelOneOnly; - old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly); + old->interp.level_one_only = new->interp.level_one_only; old->defined |= SI_FIELD_LEVEL_ONE_ONLY; } if (collide) { - log_warn(info->keymap->ctx, + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Multiple interpretations of \"%s\"; " "Using %s definition for duplicate fields\n", siText(new, info), @@ -332,95 +249,57 @@ AddInterp(CompatInfo * info, SymInterpInfo * new) return true; } - old = new; - if ((new = NextInterp(info)) == NULL) - return false; - entry = new->entry; - *new = *old; - new->entry = entry; - return true; -} - -static bool -AddGroupCompat(CompatInfo *info, xkb_group_index_t group, GroupCompatInfo *new) -{ - GroupCompatInfo *gc; - int verbosity = xkb_get_log_verbosity(info->keymap->ctx); - - gc = &info->groupCompat[group]; - if (gc->real_mods == new->real_mods && gc->vmods == new->vmods) - return true; - - if ((gc->file_id == new->file_id && verbosity > 0) || verbosity > 9) - log_warn(info->keymap->ctx, - "Compat map for group %u redefined; " - "Using %s definition\n", - group + 1, (new->merge == MERGE_AUGMENT ? "old" : "new")); - - if (new->defined && (new->merge != MERGE_AUGMENT || !gc->defined)) - *gc = *new; - + darray_append(info->interps, *new); return true; } /***====================================================================***/ static bool -ResolveStateAndPredicate(ExprDef * expr, - unsigned *pred_rtrn, - xkb_mod_mask_t *mods_rtrn, CompatInfo * info) +ResolveStateAndPredicate(ExprDef *expr, enum xkb_match_operation *pred_rtrn, + xkb_mod_mask_t *mods_rtrn, CompatInfo *info) { if (expr == NULL) { - *pred_rtrn = XkbSI_AnyOfOrNone; - *mods_rtrn = ~0; + *pred_rtrn = MATCH_ANY_OR_NONE; + *mods_rtrn = MOD_REAL_MASK_ALL; return true; } - *pred_rtrn = XkbSI_Exactly; - if (expr->op == EXPR_ACTION_DECL) { - const char *pred_txt = xkb_atom_text(info->keymap->ctx, - expr->value.action.name); - if (istreq(pred_txt, "noneof")) - *pred_rtrn = XkbSI_NoneOf; - else if (istreq(pred_txt, "anyofornone")) - *pred_rtrn = XkbSI_AnyOfOrNone; - else if (istreq(pred_txt, "anyof")) - *pred_rtrn = XkbSI_AnyOf; - else if (istreq(pred_txt, "allof")) - *pred_rtrn = XkbSI_AllOf; - else if (istreq(pred_txt, "exactly")) - *pred_rtrn = XkbSI_Exactly; - else { - log_err(info->keymap->ctx, + *pred_rtrn = MATCH_EXACTLY; + if (expr->expr.op == EXPR_ACTION_DECL) { + const char *pred_txt = xkb_atom_text(info->ctx, expr->action.name); + if (!LookupString(symInterpretMatchMaskNames, pred_txt, pred_rtrn) || + !expr->action.args || expr->action.args->common.next) { + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Illegal modifier predicate \"%s\"; Ignored\n", pred_txt); return false; } - expr = expr->value.action.args; + expr = expr->action.args; } - else if (expr->op == EXPR_IDENT) { - const char *pred_txt = xkb_atom_text(info->keymap->ctx, - expr->value.str); + else if (expr->expr.op == EXPR_IDENT) { + const char *pred_txt = xkb_atom_text(info->ctx, expr->ident.ident); if (pred_txt && istreq(pred_txt, "any")) { - *pred_rtrn = XkbSI_AnyOf; - *mods_rtrn = 0xff; + *pred_rtrn = MATCH_ANY; + *mods_rtrn = MOD_REAL_MASK_ALL; return true; } } - return ExprResolveModMask(info->keymap->ctx, expr, mods_rtrn); + return ExprResolveModMask(info->ctx, expr, MOD_REAL, &info->mods, + mods_rtrn); } /***====================================================================***/ static bool -UseNewLEDField(enum led_field field, LEDInfo *old, LEDInfo *new, - int verbosity, enum led_field *collide) +UseNewLEDField(enum led_field field, LedInfo *old, LedInfo *new, + bool report, enum led_field *collide) { if (!(old->defined & field)) return true; if (new->defined & field) { - if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9) + if (report) *collide |= field; if (new->merge != MERGE_AUGMENT) @@ -431,146 +310,115 @@ UseNewLEDField(enum led_field field, LEDInfo *old, LEDInfo *new, } static bool -AddIndicatorMap(CompatInfo *info, LEDInfo *new) +AddLedMap(CompatInfo *info, LedInfo *new, bool same_file) { - LEDInfo *old; enum led_field collide; - struct xkb_context *ctx = info->keymap->ctx; - int verbosity = xkb_get_log_verbosity(ctx); - - list_foreach(old, &info->leds, entry) { - if (old->name == new->name) { - if ((old->real_mods == new->real_mods) && - (old->vmods == new->vmods) && - (old->groups == new->groups) && - (old->ctrls == new->ctrls) && - (old->which_mods == new->which_mods) && - (old->which_groups == new->which_groups)) { - old->defined |= new->defined; - return true; - } + const int verbosity = xkb_context_get_log_verbosity(info->ctx); + const bool report = (same_file && verbosity > 0) || verbosity > 9; - if (new->merge == MERGE_REPLACE) { - struct list entry = old->entry; - if ((old->file_id == new->file_id && verbosity > 0) || - verbosity > 9) - log_warn(info->keymap->ctx, - "Map for indicator %s redefined; " - "Earlier definition ignored\n", - xkb_atom_text(ctx, old->name)); - *old = *new; - old->entry = entry; - return true; - } + for (xkb_led_index_t i = 0; i < info->num_leds; i++) { + LedInfo *old = &info->leds[i]; - collide = 0; - if (UseNewLEDField(LED_FIELD_INDEX, old, new, verbosity, - &collide)) { - old->indicator = new->indicator; - old->defined |= LED_FIELD_INDEX; - } - if (UseNewLEDField(LED_FIELD_MODS, old, new, verbosity, - &collide)) { - old->which_mods = new->which_mods; - old->real_mods = new->real_mods; - old->vmods = new->vmods; - old->defined |= LED_FIELD_MODS; - } - if (UseNewLEDField(LED_FIELD_GROUPS, old, new, verbosity, - &collide)) { - old->which_groups = new->which_groups; - old->groups = new->groups; - old->defined |= LED_FIELD_GROUPS; - } - if (UseNewLEDField(LED_FIELD_CTRLS, old, new, verbosity, - &collide)) { - old->ctrls = new->ctrls; - old->defined |= LED_FIELD_CTRLS; - } - if (UseNewLEDField(LED_FIELD_EXPLICIT, old, new, verbosity, - &collide)) { - old->flags &= ~XkbIM_NoExplicit; - old->flags |= (new->flags & XkbIM_NoExplicit); - old->defined |= LED_FIELD_EXPLICIT; - } - if (UseNewLEDField(LED_FIELD_AUTOMATIC, old, new, verbosity, - &collide)) { - old->flags &= ~XkbIM_NoAutomatic; - old->flags |= (new->flags & XkbIM_NoAutomatic); - old->defined |= LED_FIELD_AUTOMATIC; - } - if (UseNewLEDField(LED_FIELD_DRIVES_KBD, old, new, verbosity, - &collide)) { - old->flags &= ~XkbIM_LEDDrivesKB; - old->flags |= (new->flags & XkbIM_LEDDrivesKB); - old->defined |= LED_FIELD_DRIVES_KBD; - } + if (old->led.name != new->led.name) + continue; - if (collide) { - log_warn(info->keymap->ctx, - "Map for indicator %s redefined; " - "Using %s definition for duplicate fields\n", - xkb_atom_text(ctx, old->name), - (new->merge == MERGE_AUGMENT ? "first" : "last")); - } + if (old->led.mods.mods == new->led.mods.mods && + old->led.groups == new->led.groups && + old->led.ctrls == new->led.ctrls && + old->led.which_mods == new->led.which_mods && + old->led.which_groups == new->led.which_groups) { + old->defined |= new->defined; + return true; + } + if (new->merge == MERGE_REPLACE) { + if (report) + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Map for indicator %s redefined; " + "Earlier definition ignored\n", + xkb_atom_text(info->ctx, old->led.name)); + *old = *new; return true; } + + collide = 0; + if (UseNewLEDField(LED_FIELD_MODS, old, new, report, &collide)) { + old->led.which_mods = new->led.which_mods; + old->led.mods = new->led.mods; + old->defined |= LED_FIELD_MODS; + } + if (UseNewLEDField(LED_FIELD_GROUPS, old, new, report, &collide)) { + old->led.which_groups = new->led.which_groups; + old->led.groups = new->led.groups; + old->defined |= LED_FIELD_GROUPS; + } + if (UseNewLEDField(LED_FIELD_CTRLS, old, new, report, &collide)) { + old->led.ctrls = new->led.ctrls; + old->defined |= LED_FIELD_CTRLS; + } + + if (collide) { + log_warn(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Map for indicator %s redefined; " + "Using %s definition for duplicate fields\n", + xkb_atom_text(info->ctx, old->led.name), + (new->merge == MERGE_AUGMENT ? "first" : "last")); + } + + return true; } - /* new definition */ - old = malloc(sizeof(*old)); - if (!old) { - log_wsgo(info->keymap->ctx, - "Couldn't allocate indicator map; " - "Map for indicator %s not compiled\n", - xkb_atom_text(ctx, new->name)); + if (info->num_leds >= XKB_MAX_LEDS) { + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Too many LEDs defined (maximum %d)\n", + XKB_MAX_LEDS); return false; } - - *old = *new; - list_append(&old->entry, &info->leds); - + info->leds[info->num_leds++] = *new; return true; } static void -MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from, +MergeIncludedCompatMaps(CompatInfo *into, CompatInfo *from, enum merge_mode merge) { - SymInterpInfo *si; - LEDInfo *led, *next_led; - GroupCompatInfo *gcm; - xkb_group_index_t i; - if (from->errorCount > 0) { into->errorCount += from->errorCount; return; } + + into->mods = from->mods; + if (into->name == NULL) { into->name = from->name; from->name = NULL; } - list_foreach(si, &from->interps, entry) { - if (merge != MERGE_DEFAULT) - si->merge = merge; - if (!AddInterp(into, si)) - into->errorCount++; + if (darray_empty(into->interps)) { + into->interps = from->interps; + darray_init(from->interps); } - - for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; - i++, gcm++) { - if (merge != MERGE_DEFAULT) - gcm->merge = merge; - if (!AddGroupCompat(into, i, gcm)) - into->errorCount++; + else { + SymInterpInfo *si; + darray_foreach(si, from->interps) { + si->merge = (merge == MERGE_DEFAULT ? si->merge : merge); + if (!AddInterp(into, si, false)) + into->errorCount++; + } } - list_foreach_safe(led, next_led, &from->leds, entry) { - led->merge = (merge == MERGE_DEFAULT ? led->merge : merge); - if (!AddIndicatorMap(into, led)) - into->errorCount++; + if (into->num_leds == 0) { + memcpy(into->leds, from->leds, sizeof(*from->leds) * from->num_leds); + into->num_leds = from->num_leds; + from->num_leds = 0; + } + else { + for (xkb_led_index_t i = 0; i < from->num_leds; i++) { + LedInfo *ledi = &from->leds[i]; + ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge); + if (!AddLedMap(into, ledi, false)) + into->errorCount++; + } } } @@ -578,72 +426,60 @@ static void HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge); static bool -HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *stmt) +HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *include) { - enum merge_mode merge = MERGE_DEFAULT; - XkbFile *rtrn; - CompatInfo included, next_incl; - - InitCompatInfo(&included, info->keymap, info->file_id); - if (stmt->stmt) { - free(included.name); - included.name = stmt->stmt; - stmt->stmt = NULL; - } + CompatInfo included; + + if (!include) + return false; + + InitCompatInfo(&included, info->ctx, info->actions, &info->mods); + included.name = include->stmt; + include->stmt = NULL; - for (; stmt; stmt = stmt->next_incl) { - if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT, - &rtrn, &merge)) { + for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) { + CompatInfo next_incl; + XkbFile *file; + + file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_COMPAT); + if (!file) { info->errorCount += 10; ClearCompatInfo(&included); return false; } - InitCompatInfo(&next_incl, info->keymap, rtrn->id); - next_incl.file_id = rtrn->id; - next_incl.dflt = info->dflt; - next_incl.dflt.file_id = rtrn->id; - next_incl.dflt.merge = merge; - next_incl.ledDflt.file_id = rtrn->id; - next_incl.ledDflt.merge = merge; - next_incl.act = info->act; + InitCompatInfo(&next_incl, info->ctx, info->actions, &included.mods); + next_incl.default_interp = info->default_interp; + next_incl.default_interp.merge = stmt->merge; + next_incl.default_led = info->default_led; + next_incl.default_led.merge = stmt->merge; - HandleCompatMapFile(&next_incl, rtrn, MERGE_OVERRIDE); + HandleCompatMapFile(&next_incl, file, MERGE_OVERRIDE); - MergeIncludedCompatMaps(&included, &next_incl, merge); - if (info->act) - next_incl.act = NULL; + MergeIncludedCompatMaps(&included, &next_incl, stmt->merge); ClearCompatInfo(&next_incl); - FreeXKBFile(rtrn); + FreeXkbFile(file); } - MergeIncludedCompatMaps(info, &included, merge); + MergeIncludedCompatMaps(info, &included, include->merge); ClearCompatInfo(&included); return (info->errorCount == 0); } -static const LookupEntry useModMapValues[] = { - { "levelone", 1 }, - { "level1", 1 }, - { "anylevel", 0 }, - { "any", 0 }, - { NULL, 0 } -}; - -static int +static bool SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field, ExprDef *arrayNdx, ExprDef *value) { - struct xkb_keymap *keymap = info->keymap; xkb_mod_index_t ndx; if (istreq(field, "action")) { if (arrayNdx) return ReportSINotArray(info, si, field); - if (!HandleActionDef(value, keymap, &si->interp.act.any, info->act)) + if (!HandleActionDef(info->ctx, info->actions, &info->mods, + value, &si->interp.action)) return false; si->defined |= SI_FIELD_ACTION; @@ -653,7 +489,7 @@ SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field, if (arrayNdx) return ReportSINotArray(info, si, field); - if (!ResolveVirtualModifier(value, keymap, &ndx, &info->vmods)) + if (!ExprResolveMod(info->ctx, value, MOD_VIRT, &info->mods, &ndx)) return ReportSIBadType(info, si, field, "virtual modifier"); si->interp.virtual_mod = ndx; @@ -665,31 +501,17 @@ SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field, if (arrayNdx) return ReportSINotArray(info, si, field); - if (!ExprResolveBoolean(keymap->ctx, value, &set)) + if (!ExprResolveBoolean(info->ctx, value, &set)) return ReportSIBadType(info, si, field, "boolean"); - if (set) - si->interp.flags |= XkbSI_AutoRepeat; - else - si->interp.flags &= ~XkbSI_AutoRepeat; + si->interp.repeat = set; si->defined |= SI_FIELD_AUTO_REPEAT; } else if (istreq(field, "locking")) { - bool set; - - if (arrayNdx) - return ReportSINotArray(info, si, field); - - if (!ExprResolveBoolean(keymap->ctx, value, &set)) - return ReportSIBadType(info, si, field, "boolean"); - - if (set) - si->interp.flags |= XkbSI_LockingKey; - else - si->interp.flags &= ~XkbSI_LockingKey; - - si->defined |= SI_FIELD_LOCKING_KEY; + log_dbg(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "The \"locking\" field in symbol interpretation is unsupported; " + "Ignored\n"); } else if (istreq(field, "usemodmap") || istreq(field, "usemodmapmods")) { @@ -698,143 +520,91 @@ SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field, if (arrayNdx) return ReportSINotArray(info, si, field); - if (!ExprResolveEnum(keymap->ctx, value, &val, useModMapValues)) + if (!ExprResolveEnum(info->ctx, value, &val, useModMapValueNames)) return ReportSIBadType(info, si, field, "level specification"); - if (val) - si->interp.match |= XkbSI_LevelOneOnly; - else - si->interp.match &= ~XkbSI_LevelOneOnly; - + si->interp.level_one_only = val; si->defined |= SI_FIELD_LEVEL_ONE_ONLY; } else { - return ReportBadField(keymap, "symbol interpretation", field, + return ReportBadField(info->ctx, "symbol interpretation", field, siText(si, info)); } return true; } -static const LookupEntry modComponentNames[] = { - {"base", XkbIM_UseBase}, - {"latched", XkbIM_UseLatched}, - {"locked", XkbIM_UseLocked}, - {"effective", XkbIM_UseEffective}, - {"compat", XkbIM_UseCompat}, - {"any", XkbIM_UseAnyMods}, - {"none", 0}, - {NULL, 0} -}; -static const LookupEntry groupComponentNames[] = { - {"base", XkbIM_UseBase}, - {"latched", XkbIM_UseLatched}, - {"locked", XkbIM_UseLocked}, - {"effective", XkbIM_UseEffective}, - {"any", XkbIM_UseAnyGroup}, - {"none", 0}, - {NULL, 0} -}; - -static const LookupEntry groupNames[] = { - {"group1", 0x01}, - {"group2", 0x02}, - {"group3", 0x04}, - {"group4", 0x08}, - {"group5", 0x10}, - {"group6", 0x20}, - {"group7", 0x40}, - {"group8", 0x80}, - {"none", 0x00}, - {"all", 0xff}, - {NULL, 0} -}; - -static int -SetIndicatorMapField(CompatInfo *info, LEDInfo *led, - const char *field, ExprDef *arrayNdx, ExprDef *value) +static bool +SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field, + ExprDef *arrayNdx, ExprDef *value) { bool ok = true; - struct xkb_keymap *keymap = info->keymap; if (istreq(field, "modifiers") || istreq(field, "mods")) { - xkb_mod_mask_t mask; - if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); + return ReportLedNotArray(info, ledi, field); - if (!ExprResolveVModMask(keymap, value, &mask)) - return ReportIndicatorBadType(info, led, field, "modifier mask"); + if (!ExprResolveModMask(info->ctx, value, MOD_BOTH, + &info->mods, &ledi->led.mods.mods)) + return ReportLedBadType(info, ledi, field, "modifier mask"); - led->real_mods = mask & 0xff; - led->vmods = (mask >> XkbNumModifiers) & 0xffff; - led->defined |= LED_FIELD_MODS; + ledi->defined |= LED_FIELD_MODS; } else if (istreq(field, "groups")) { unsigned int mask; if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); + return ReportLedNotArray(info, ledi, field); - if (!ExprResolveMask(keymap->ctx, value, &mask, groupNames)) - return ReportIndicatorBadType(info, led, field, "group mask"); + if (!ExprResolveMask(info->ctx, value, &mask, groupMaskNames)) + return ReportLedBadType(info, ledi, field, "group mask"); - led->groups = mask; - led->defined |= LED_FIELD_GROUPS; + ledi->led.groups = mask; + ledi->defined |= LED_FIELD_GROUPS; } else if (istreq(field, "controls") || istreq(field, "ctrls")) { unsigned int mask; if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); + return ReportLedNotArray(info, ledi, field); - if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlNames)) - return ReportIndicatorBadType(info, led, field, - "controls mask"); + if (!ExprResolveMask(info->ctx, value, &mask, ctrlMaskNames)) + return ReportLedBadType(info, ledi, field, "controls mask"); - led->ctrls = mask; - led->defined |= LED_FIELD_CTRLS; + ledi->led.ctrls = mask; + ledi->defined |= LED_FIELD_CTRLS; } else if (istreq(field, "allowexplicit")) { - bool set; - - if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); - - if (!ExprResolveBoolean(keymap->ctx, value, &set)) - return ReportIndicatorBadType(info, led, field, "boolean"); - - if (set) - led->flags &= ~XkbIM_NoExplicit; - else - led->flags |= XkbIM_NoExplicit; - - led->defined |= LED_FIELD_EXPLICIT; + log_dbg(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "The \"allowExplicit\" field in indicator statements is unsupported; " + "Ignored\n"); } else if (istreq(field, "whichmodstate") || istreq(field, "whichmodifierstate")) { unsigned int mask; if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); + return ReportLedNotArray(info, ledi, field); - if (!ExprResolveMask(keymap->ctx, value, &mask, modComponentNames)) - return ReportIndicatorBadType(info, led, field, - "mask of modifier state components"); + if (!ExprResolveMask(info->ctx, value, &mask, + modComponentMaskNames)) + return ReportLedBadType(info, ledi, field, + "mask of modifier state components"); - led->which_mods = mask; + ledi->led.which_mods = mask; } else if (istreq(field, "whichgroupstate")) { unsigned mask; if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); + return ReportLedNotArray(info, ledi, field); - if (!ExprResolveMask(keymap->ctx, value, &mask, groupComponentNames)) - return ReportIndicatorBadType(info, led, field, - "mask of group state components"); + if (!ExprResolveMask(info->ctx, value, &mask, + groupComponentMaskNames)) + return ReportLedBadType(info, ledi, field, + "mask of group state components"); - led->which_groups = mask; + ledi->led.which_groups = mask; } else if (istreq(field, "driveskbd") || istreq(field, "driveskeyboard") || @@ -842,206 +612,143 @@ SetIndicatorMapField(CompatInfo *info, LEDInfo *led, istreq(field, "leddriveskeyboard") || istreq(field, "indicatordriveskbd") || istreq(field, "indicatordriveskeyboard")) { - bool set; - - if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); - - if (!ExprResolveBoolean(keymap->ctx, value, &set)) - return ReportIndicatorBadType(info, led, field, "boolean"); - - if (set) - led->flags |= XkbIM_LEDDrivesKB; - else - led->flags &= ~XkbIM_LEDDrivesKB; - - led->defined |= LED_FIELD_DRIVES_KBD; + log_dbg(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "The \"%s\" field in indicator statements is unsupported; " + "Ignored\n", field); } else if (istreq(field, "index")) { - int ndx; - - if (arrayNdx) - return ReportIndicatorNotArray(info, led, field); - - if (!ExprResolveInteger(keymap->ctx, value, &ndx)) - return ReportIndicatorBadType(info, led, field, - "indicator index"); - - if (ndx < 1 || ndx > 32) { - log_err(info->keymap->ctx, - "Illegal indicator index %d (range 1..%d); " - "Index definition for %s indicator ignored\n", - ndx, XkbNumIndicators, - xkb_atom_text(keymap->ctx, led->name)); - return false; - } - - led->indicator = (xkb_led_index_t) ndx; - led->defined |= LED_FIELD_INDEX; + /* Users should see this, it might cause unexpected behavior. */ + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "The \"index\" field in indicator statements is unsupported; " + "Ignored\n"); } else { - log_err(info->keymap->ctx, + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Unknown field %s in map for %s indicator; " "Definition ignored\n", - field, xkb_atom_text(keymap->ctx, led->name)); + field, xkb_atom_text(info->ctx, ledi->led.name)); ok = false; } return ok; } -static int -HandleInterpVar(CompatInfo *info, VarDef *stmt) +static bool +HandleGlobalVar(CompatInfo *info, VarDef *stmt) { const char *elem, *field; ExprDef *ndx; - int ret; + bool ret; - if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &ndx)) - ret = 0; /* internal error, already reported */ + if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &ndx)) + ret = false; else if (elem && istreq(elem, "interpret")) - ret = SetInterpField(info, &info->dflt, field, ndx, stmt->value); + ret = SetInterpField(info, &info->default_interp, field, ndx, + stmt->value); else if (elem && istreq(elem, "indicator")) - ret = SetIndicatorMapField(info, &info->ledDflt, field, ndx, - stmt->value); + ret = SetLedMapField(info, &info->default_led, field, ndx, + stmt->value); else - ret = SetActionField(info->keymap, elem, field, ndx, stmt->value, - &info->act); + ret = SetActionField(info->ctx, info->actions, &info->mods, + elem, field, ndx, stmt->value); return ret; } -static int +static bool HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si) { - int ok = 1; + bool ok = true; const char *elem, *field; ExprDef *arrayNdx; - for (; def != NULL; def = (VarDef *) def->common.next) { - if (def->name && def->name->op == EXPR_FIELD_REF) { - ok = HandleInterpVar(info, def); + for (; def; def = (VarDef *) def->common.next) { + if (def->name && def->name->expr.op == EXPR_FIELD_REF) { + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Cannot set a global default value from within an interpret statement; " + "Move statements to the global file scope\n"); + ok = false; continue; } - ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field, - &arrayNdx); - if (ok) { - ok = SetInterpField(info, si, field, arrayNdx, def->value); - } + + ok = ExprResolveLhs(info->ctx, def->name, &elem, &field, &arrayNdx); + if (!ok) + continue; + + ok = SetInterpField(info, si, field, arrayNdx, def->value); } + return ok; } -static int +static bool HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge) { - unsigned pred, mods; + enum xkb_match_operation pred; + xkb_mod_mask_t mods; SymInterpInfo si; if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) { - log_err(info->keymap->ctx, + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Couldn't determine matching modifiers; " "Symbol interpretation ignored\n"); return false; } - if (def->merge != MERGE_DEFAULT) - merge = def->merge; - si = info->dflt; - si.merge = merge; - if (!LookupKeysym(def->sym, &si.interp.sym)) { - log_err(info->keymap->ctx, - "Could not resolve keysym %s; " - "Symbol interpretation ignored\n", - def->sym); - return false; - } - si.interp.match = pred & XkbSI_OpMask; + si = info->default_interp; + si.merge = (def->merge == MERGE_DEFAULT ? merge : def->merge); + si.interp.sym = def->sym; + si.interp.match = pred; si.interp.mods = mods; + if (!HandleInterpBody(info, def->def, &si)) { info->errorCount++; return false; } - if (!AddInterp(info, &si)) { + if (!AddInterp(info, &si, true)) { info->errorCount++; return false; } - return true; -} - -static int -HandleGroupCompatDef(CompatInfo *info, GroupCompatDef *def, - enum merge_mode merge) -{ - xkb_mod_mask_t mask; - GroupCompatInfo tmp; - - merge = (def->merge == MERGE_DEFAULT ? merge : def->merge); - if (def->group < 1 || def->group > XkbNumKbdGroups) { - log_err(info->keymap->ctx, - "Keyboard group must be in the range 1..%u; " - "Compatibility map for illegal group %u ignored\n", - XkbNumKbdGroups, def->group); - return false; - } - - tmp.file_id = info->file_id; - tmp.merge = merge; - - if (!ExprResolveVModMask(info->keymap, def->def, &mask)) { - log_err(info->keymap->ctx, - "Expected a modifier mask in group compatibility definition; " - "Ignoring illegal compatibility map for group %u\n", - def->group); - return false; - } - - tmp.real_mods = mask & 0xff; - tmp.vmods = (mask >> XkbNumModifiers) & 0xffff; - tmp.defined = true; - return AddGroupCompat(info, def->group - 1, &tmp); + return true; } static bool -HandleIndicatorMapDef(CompatInfo *info, IndicatorMapDef *def, - enum merge_mode merge) +HandleLedMapDef(CompatInfo *info, LedMapDef *def, enum merge_mode merge) { - LEDInfo led; + LedInfo ledi; VarDef *var; bool ok; if (def->merge != MERGE_DEFAULT) merge = def->merge; - led = info->ledDflt; - led.merge = merge; - led.name = def->name; + ledi = info->default_led; + ledi.merge = merge; + ledi.led.name = def->name; ok = true; for (var = def->body; var != NULL; var = (VarDef *) var->common.next) { const char *elem, *field; ExprDef *arrayNdx; - if (!ExprResolveLhs(info->keymap->ctx, var->name, &elem, &field, - &arrayNdx)) { + if (!ExprResolveLhs(info->ctx, var->name, &elem, &field, &arrayNdx)) { ok = false; continue; } if (elem) { - log_err(info->keymap->ctx, + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, "Cannot set defaults for \"%s\" element in indicator map; " "Assignment to %s.%s ignored\n", elem, elem, field); ok = false; } else { - ok = SetIndicatorMapField(info, &led, field, arrayNdx, - var->value) && ok; + ok = SetLedMapField(info, &ledi, field, arrayNdx, var->value) && ok; } } if (ok) - return AddIndicatorMap(info, &led); + return AddLedMap(info, &ledi, true); return false; } @@ -1050,14 +757,13 @@ static void HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge) { bool ok; - ParseCommon *stmt; merge = (merge == MERGE_DEFAULT ? MERGE_AUGMENT : merge); free(info->name); info->name = strdup_safe(file->name); - for (stmt = file->defs; stmt; stmt = stmt->next) { + for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) { switch (stmt->type) { case STMT_INCLUDE: ok = HandleIncludeCompatMap(info, (IncludeStmt *) stmt); @@ -1066,22 +772,24 @@ HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge) ok = HandleInterpDef(info, (InterpDef *) stmt, merge); break; case STMT_GROUP_COMPAT: - ok = HandleGroupCompatDef(info, (GroupCompatDef *) stmt, merge); + log_dbg(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "The \"group\" statement in compat is unsupported; " + "Ignored\n"); + ok = true; break; - case STMT_INDICATOR_MAP: - ok = HandleIndicatorMapDef(info, (IndicatorMapDef *) stmt, merge); + case STMT_LED_MAP: + ok = HandleLedMapDef(info, (LedMapDef *) stmt, merge); break; case STMT_VAR: - ok = HandleInterpVar(info, (VarDef *) stmt); + ok = HandleGlobalVar(info, (VarDef *) stmt); break; case STMT_VMOD: - ok = HandleVModDef((VModDef *) stmt, info->keymap, merge, - &info->vmods); + ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge); break; default: - log_err(info->keymap->ctx, - "Interpretation files may not include other types; " - "Ignoring %s\n", StmtTypeToString(stmt->type)); + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Compat files may not include other types; " + "Ignoring %s\n", stmt_type_to_string(stmt->type)); ok = false; break; } @@ -1090,141 +798,110 @@ HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge) info->errorCount++; if (info->errorCount > 10) { - log_err(info->keymap->ctx, - "Abandoning compatibility map \"%s\"\n", file->topName); + log_err(info->ctx, XKB_LOG_MESSAGE_NO_ID, + "Abandoning compatibility map \"%s\"\n", file->name); break; } } } +/* Temporary struct for CopyInterps. */ +struct collect { + darray(struct xkb_sym_interpret) sym_interprets; +}; + static void -CopyInterps(CompatInfo *info, bool needSymbol, unsigned pred) +CopyInterps(CompatInfo *info, bool needSymbol, enum xkb_match_operation pred, + struct collect *collect) { SymInterpInfo *si; - list_foreach(si, &info->interps, entry) { - if (((si->interp.match & XkbSI_OpMask) != pred) || - (needSymbol && si->interp.sym == XKB_KEY_NoSymbol) || - (!needSymbol && si->interp.sym != XKB_KEY_NoSymbol)) - continue; - - darray_append(info->keymap->sym_interpret, si->interp); - } + darray_foreach(si, info->interps) + if (si->interp.match == pred && + (si->interp.sym != XKB_KEY_NoSymbol) == needSymbol) + darray_append(collect->sym_interprets, si->interp); } static void -BindIndicators(CompatInfo *info, struct list *unbound_leds) -{ - xkb_led_index_t i; - LEDInfo *led, *next_led; - struct xkb_indicator_map *map; - struct xkb_keymap *keymap = info->keymap; - - list_foreach(led, unbound_leds, entry) { - if (led->indicator == XKB_LED_INVALID) { - for (i = 0; i < XkbNumIndicators; i++) { - if (keymap->indicator_names[i] && - streq(keymap->indicator_names[i], - xkb_atom_text(keymap->ctx, led->name))) { - led->indicator = i + 1; +CopyLedMapDefsToKeymap(struct xkb_keymap *keymap, CompatInfo *info) +{ + for (xkb_led_index_t idx = 0; idx < info->num_leds; idx++) { + LedInfo *ledi = &info->leds[idx]; + xkb_led_index_t i; + struct xkb_led *led; + + /* + * Find the LED with the given name, if it was already declared + * in keycodes. + */ + xkb_leds_enumerate(i, led, keymap) + if (led->name == ledi->led.name) + break; + + /* Not previously declared; create it with next free index. */ + if (i >= keymap->num_leds) { + log_dbg(keymap->ctx, XKB_LOG_MESSAGE_NO_ID, + "Indicator name \"%s\" was not declared in the keycodes section; " + "Adding new indicator\n", + xkb_atom_text(keymap->ctx, ledi->led.name)); + + xkb_leds_enumerate(i, led, keymap) + if (led->name == XKB_ATOM_NONE) break; - } - } - } - } - list_foreach(led, unbound_leds, entry) { - if (led->indicator == XKB_LED_INVALID) { - for (i = 0; i < XkbNumIndicators; i++) { - if (keymap->indicator_names[i] == NULL) { - keymap->indicator_names[i] = - xkb_atom_text(keymap->ctx, led->name); - led->indicator = i + 1; - break; + if (i >= keymap->num_leds) { + /* Not place to put it; ignore. */ + if (i >= XKB_MAX_LEDS) { + log_err(keymap->ctx, XKB_LOG_MESSAGE_NO_ID, + "Too many indicators (maximum is %d); " + "Indicator name \"%s\" ignored\n", + XKB_MAX_LEDS, + xkb_atom_text(keymap->ctx, ledi->led.name)); + continue; } - } - if (led->indicator == XKB_LED_INVALID) { - log_err(info->keymap->ctx, - "No unnamed indicators found; " - "Virtual indicator map \"%s\" not bound\n", - xkb_atom_text(keymap->ctx, led->name)); - continue; + /* Add a new LED. */ + led = &keymap->leds[keymap->num_leds++]; } } - } - - list_foreach_safe(led, next_led, unbound_leds, entry) { - if (led->indicator == XKB_LED_INVALID) { - free(led); - continue; - } - - if (!streq(keymap->indicator_names[led->indicator - 1], - xkb_atom_text(keymap->ctx, led->name))) { - const char *old = keymap->indicator_names[led->indicator - 1]; - log_err(info->keymap->ctx, - "Multiple names bound to indicator %d; " - "Using %s, ignoring %s\n", - led->indicator, old, - xkb_atom_text(keymap->ctx, led->name)); - free(led); - continue; - } - map = &keymap->indicators[led->indicator - 1]; - map->flags = led->flags; - map->which_groups = led->which_groups; - map->groups = led->groups; - map->which_mods = led->which_mods; - map->mods.mask = led->real_mods; - map->mods.real_mods = led->real_mods; - map->mods.vmods = led->vmods; - map->ctrls = led->ctrls; - free(led); + *led = ledi->led; + if (led->groups != 0 && led->which_groups == 0) + led->which_groups = XKB_STATE_LAYOUT_EFFECTIVE; + if (led->mods.mods != 0 && led->which_mods == 0) + led->which_mods = XKB_STATE_MODS_EFFECTIVE; } - - list_init(unbound_leds); } static bool -CopyIndicatorMapDefs(CompatInfo *info) +CopyCompatToKeymap(struct xkb_keymap *keymap, CompatInfo *info) { - LEDInfo *led, *next_led; - struct list unbound_leds; - struct xkb_indicator_map *im; - struct xkb_keymap *keymap = info->keymap; + keymap->compat_section_name = strdup_safe(info->name); + XkbEscapeMapName(keymap->compat_section_name); - list_init(&unbound_leds); + keymap->mods = info->mods; - list_foreach_safe(led, next_led, &info->leds, entry) { - if (led->groups != 0 && led->which_groups == 0) - led->which_groups = XkbIM_UseEffective; + if (!darray_empty(info->interps)) { + struct collect collect; + darray_init(collect.sym_interprets); - if (led->which_mods == 0 && (led->real_mods || led->vmods)) - led->which_mods = XkbIM_UseEffective; + /* Most specific to least specific. */ + CopyInterps(info, true, MATCH_EXACTLY, &collect); + CopyInterps(info, true, MATCH_ALL, &collect); + CopyInterps(info, true, MATCH_NONE, &collect); + CopyInterps(info, true, MATCH_ANY, &collect); + CopyInterps(info, true, MATCH_ANY_OR_NONE, &collect); + CopyInterps(info, false, MATCH_EXACTLY, &collect); + CopyInterps(info, false, MATCH_ALL, &collect); + CopyInterps(info, false, MATCH_NONE, &collect); + CopyInterps(info, false, MATCH_ANY, &collect); + CopyInterps(info, false, MATCH_ANY_OR_NONE, &collect); - if (led->indicator == XKB_LED_INVALID) { - list_append(&led->entry, &unbound_leds); - continue; - } - - im = &keymap->indicators[led->indicator - 1]; - im->flags = led->flags; - im->which_groups = led->which_groups; - im->groups = led->groups; - im->which_mods = led->which_mods; - im->mods.mask = led->real_mods; - im->mods.real_mods = led->real_mods; - im->mods.vmods = led->vmods; - im->ctrls = led->ctrls; - keymap->indicator_names[led->indicator - 1] = - xkb_atom_text(keymap->ctx, led->name); - free(led); + darray_steal(collect.sym_interprets, + &keymap->sym_interprets, &keymap->num_sym_interprets); } - list_init(&info->leds); - BindIndicators(info, &unbound_leds); + CopyLedMapDefsToKeymap(keymap, info); return true; } @@ -1233,312 +910,30 @@ bool CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge) { - xkb_group_index_t i; CompatInfo info; - GroupCompatInfo *gcm; + ActionsInfo *actions; - InitCompatInfo(&info, keymap, file->id); - info.dflt.merge = merge; - info.ledDflt.merge = merge; + actions = NewActionsInfo(); + if (!actions) + return false; - HandleCompatMapFile(&info, file, merge); + InitCompatInfo(&info, keymap->ctx, actions, &keymap->mods); + info.default_interp.merge = merge; + info.default_led.merge = merge; + HandleCompatMapFile(&info, file, merge); if (info.errorCount != 0) goto err_info; - darray_init(keymap->sym_interpret); - darray_growalloc(keymap->sym_interpret, info.nInterps); - - if (info.name) - keymap->compat_section_name = strdup(info.name); - - if (info.nInterps > 0) { - CopyInterps(&info, true, XkbSI_Exactly); - CopyInterps(&info, true, XkbSI_AllOf | XkbSI_NoneOf); - CopyInterps(&info, true, XkbSI_AnyOf); - CopyInterps(&info, true, XkbSI_AnyOfOrNone); - CopyInterps(&info, false, XkbSI_Exactly); - CopyInterps(&info, false, XkbSI_AllOf | XkbSI_NoneOf); - CopyInterps(&info, false, XkbSI_AnyOf); - CopyInterps(&info, false, XkbSI_AnyOfOrNone); - } - - for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups; - i++, gcm++) { - if (gcm->file_id != 0 || gcm->real_mods != 0 || gcm->vmods != 0) { - keymap->groups[i].mask = gcm->real_mods; - keymap->groups[i].real_mods = gcm->real_mods; - keymap->groups[i].vmods = gcm->vmods; - } - } - - if (!CopyIndicatorMapDefs(&info)) - info.errorCount++; + if (!CopyCompatToKeymap(keymap, &info)) + goto err_info; ClearCompatInfo(&info); + FreeActionsInfo(actions); return true; err_info: ClearCompatInfo(&info); + FreeActionsInfo(actions); return false; } - -xkb_mod_mask_t -VModsToReal(struct xkb_keymap *keymap, xkb_mod_mask_t vmodmask) -{ - xkb_mod_mask_t ret = 0; - xkb_mod_index_t i; - - if (!vmodmask) - return 0; - - for (i = 0; i < XkbNumVirtualMods; i++) { - if (!(vmodmask & (1 << i))) - continue; - ret |= keymap->vmods[i]; - } - - return ret; -} - -static void -UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act, - xkb_mod_mask_t rmodmask) -{ - switch (act->type) { - case XkbSA_SetMods: - case XkbSA_LatchMods: - case XkbSA_LockMods: - if (act->mods.flags & XkbSA_UseModMapMods) - act->mods.real_mods = rmodmask; - act->mods.mask = act->mods.real_mods; - act->mods.mask |= VModsToReal(keymap, act->mods.vmods); - break; - - case XkbSA_ISOLock: - if (act->iso.flags & XkbSA_UseModMapMods) - act->iso.real_mods = rmodmask; - act->iso.mask = act->iso.real_mods; - act->iso.mask |= VModsToReal(keymap, act->iso.vmods); - break; - - default: - break; - } -} - -/** - * Find an interpretation which applies to this particular level, either by - * finding an exact match for the symbol and modifier combination, or a - * generic XKB_KEY_NoSymbol match. - */ -static struct xkb_sym_interpret * -FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key, - xkb_group_index_t group, xkb_level_index_t level) -{ - struct xkb_sym_interpret *ret = NULL; - struct xkb_sym_interpret *interp; - const xkb_keysym_t *syms; - int num_syms; - - num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms); - if (num_syms == 0) - return NULL; - - darray_foreach(interp, keymap->sym_interpret) { - uint32_t mods; - bool found; - - if ((num_syms > 1 || interp->sym != syms[0]) && - interp->sym != XKB_KEY_NoSymbol) - continue; - - if (level == 0 || !(interp->match & XkbSI_LevelOneOnly)) - mods = key->modmap; - else - mods = 0; - - switch (interp->match & XkbSI_OpMask) { - case XkbSI_NoneOf: - found = !(interp->mods & mods); - break; - case XkbSI_AnyOfOrNone: - found = (!mods || (interp->mods & mods)); - break; - case XkbSI_AnyOf: - found = !!(interp->mods & mods); - break; - case XkbSI_AllOf: - found = ((interp->mods & mods) == interp->mods); - break; - case XkbSI_Exactly: - found = (interp->mods == mods); - break; - default: - found = false; - break; - } - - if (found && interp->sym != XKB_KEY_NoSymbol) - return interp; - else if (found && !ret) - ret = interp; - } - - return ret; -} - -/** - */ -static bool -ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key) -{ -#define INTERP_SIZE (8 * 4) - struct xkb_sym_interpret *interps[INTERP_SIZE]; - union xkb_action *acts; - xkb_mod_mask_t vmodmask = 0; - int num_acts = 0; - xkb_group_index_t group; - xkb_level_index_t level; - unsigned int i; - - /* If we've been told not to bind interps to this key, then don't. */ - if (key->explicit & XkbExplicitInterpretMask) - return true; - - for (i = 0; i < INTERP_SIZE; i++) - interps[i] = NULL; - - for (group = 0; group < key->num_groups; group++) { - for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); - level++) { - i = (group * key->width) + level; - if (i >= INTERP_SIZE) /* XXX FIXME */ - return false; - interps[i] = FindInterpForKey(keymap, key, group, level); - if (interps[i]) - num_acts++; - } - } - - if (num_acts) - num_acts = key->num_groups * key->width; - acts = ResizeKeyActions(keymap, key, num_acts); - if (num_acts && !acts) - return false; - - for (group = 0; group < key->num_groups; group++) { - for (level = 0; level < XkbKeyGroupWidth(keymap, key, group); - level++) { - struct xkb_sym_interpret *interp; - - i = (group * key->width) + level; - interp = interps[i]; - - /* Infer default key behaviours from the base level. */ - if (group == 0 && level == 0) { - if (!(key->explicit & XkbExplicitAutoRepeatMask) && - (!interp || (interp->flags & XkbSI_AutoRepeat))) - key->repeats = true; - } - - if (!interp) - continue; - - if ((group == 0 && level == 0) || - !(interp->match & XkbSI_LevelOneOnly)) { - if (interp->virtual_mod != XkbNoModifier) - vmodmask |= (1 << interp->virtual_mod); - } - acts[i] = interp->act; - } - } - - if (!(key->explicit & XkbExplicitVModMapMask)) - key->vmodmap = vmodmask; - - return true; -#undef INTERP_SIZE -} - -/** - * This collects a bunch of disparate functions which was done in the server - * at various points that really should've been done within xkbcomp. Turns out - * your actions and types are a lot more useful when any of your modifiers - * other than Shift actually do something ... - */ -bool -UpdateModifiersFromCompat(struct xkb_keymap *keymap) -{ - xkb_mod_index_t vmod; - xkb_group_index_t grp; - xkb_led_index_t led; - unsigned int i; - struct xkb_key *key; - struct xkb_key_type *type; - struct xkb_kt_map_entry *entry; - - /* Find all the interprets for the key and bind them to actions, - * which will also update the vmodmap. */ - xkb_foreach_key(key, keymap) - if (!ApplyInterpsToKey(keymap, key)) - return false; - - /* Update keymap->vmods, the virtual -> real mod mapping. */ - for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) - keymap->vmods[vmod] = 0; - - xkb_foreach_key(key, keymap) { - if (!key->vmodmap) - continue; - - for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) { - if (!(key->vmodmap & (1 << vmod))) - continue; - keymap->vmods[vmod] |= key->modmap; - } - } - - /* Now update the level masks for all the types to reflect the vmods. */ - for (i = 0; i < keymap->num_types; i++) { - xkb_mod_mask_t mask = 0; - type = &keymap->types[i]; - type->mods.mask = type->mods.real_mods; - type->mods.mask |= VModsToReal(keymap, type->mods.vmods); - - /* FIXME: We compute the mask with doing anything with it? */ - for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) { - if (!(type->mods.vmods & (1 << vmod))) - continue; - mask |= keymap->vmods[vmod]; - } - - darray_foreach(entry, type->map) - entry->mods.mask = entry->mods.real_mods | - VModsToReal(keymap, entry->mods.vmods); - } - - /* Update action modifiers. */ - xkb_foreach_key(key, keymap) { - union xkb_action *acts = XkbKeyActionsPtr(keymap, key); - for (i = 0; i < XkbKeyNumActions(key); i++) { - if (acts[i].any.type == XkbSA_NoAction) - continue; - UpdateActionMods(keymap, &acts[i], key->modmap); - } - } - - /* Update group modifiers. */ - for (grp = 0; grp < XkbNumKbdGroups; grp++) { - struct xkb_mods *group = &keymap->groups[grp]; - group->mask = group->real_mods | VModsToReal(keymap, group->vmods); - } - - /* Update vmod -> indicator maps. */ - for (led = 0; led < XkbNumIndicators; led++) { - struct xkb_mods *mods = &keymap->indicators[led].mods; - mods->mask = mods->real_mods | VModsToReal(keymap, mods->vmods); - } - - return true; -}