compat: add general overview
[platform/upstream/libxkbcommon.git] / src / xkbcomp / compat.c
1 /************************************************************
2  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3  *
4  * Permission to use, copy, modify, and distribute this
5  * software and its documentation for any purpose and without
6  * fee is hereby granted, provided that the above copyright
7  * notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting
9  * documentation, and that the name of Silicon Graphics not be
10  * used in advertising or publicity pertaining to distribution
11  * of the software without specific prior written permission.
12  * Silicon Graphics makes no representation about the suitability
13  * of this software for any purpose. It is provided "as is"
14  * without any express or implied warranty.
15  *
16  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  ********************************************************/
26
27 #include "xkbcomp-priv.h"
28 #include "text.h"
29 #include "expr.h"
30 #include "action.h"
31 #include "vmod.h"
32 #include "include.h"
33
34 /*
35  * The xkb_compat section
36  * =====================
37  * This section is the third to be processesed, after xkb_keycodes and
38  * xkb_types.
39  *
40  * Interpret statements
41  * --------------------
42  * Statements of the form:
43  *      interpret Num_Lock+Any { ... }
44  *
45  * The body of the statment may include statements of the following
46  * forms:
47  *
48  * - action statement:
49  *      action = LockMods(modifiers=NumLock);
50  *
51  * - virtual modifier statement:
52  *      virtualModifier = NumLock;
53  *
54  * - repeat statement:
55  *      repeat = True;
56  *
57  * - useModMapMods statement:
58  *      useModMapMods = level1;
59  *
60  * Indicator map statements
61  * ------------------------
62  * Statements of the form:
63  *      indicator "Shift Lock" { ... }
64  *
65  *   This statement specifies the behavior and binding of the indicator
66  *   with the given name ("Shift Lock" above). The name should have been
67  *   declared previously in the xkb_keycodes section (see Indicator name
68  *   statement), and given an index there. If it wasn't, it is created
69  *   with the next free index.
70  *   The body of the statement describes the conditions of the keyboard
71  *   state which will cause the indicator to be lit. It may include the
72  *   following statements:
73  *
74  * - modifiers statment:
75  *      modifiers = ScrollLock;
76  *
77  *   If the given modifiers are in the required state (see below), the
78  *   led is lit.
79  *
80  * - whichModifierState statment:
81  *      whichModState = Latched + Locked;
82  *
83  *   Can be any combination of:
84  *      base, latched, locked, effective
85  *      any (i.e. all of the above)
86  *      none (i.e. none of the above)
87  *      compat (this is legal, but unused)
88  *   This will cause the respective portion of the modifer state (see
89  *   struct xkb_state) to be matched against the modifiers given in the
90  *   "modifiers" statement.
91  *
92  *   Here's a simple example:
93  *      indicator "Num Lock" {
94  *          modifiers = NumLock;
95  *          whichModState = Locked;
96  *      };
97  *   Whenever the NumLock modifier is locked, the Num Lock indicator
98  *   will light up.
99  *
100  * - groups statment:
101  *      groups = All - group1;
102  *
103  *   If the given groups are in the required state (see below), the led
104  *   is lit.
105  *
106  * - whichGroupState statment:
107  *      whichGroupState = Effective;
108  *
109  *   Can be any combination of:
110  *      base, latched, locked, effective
111  *      any (i.e. all of the above)
112  *      none (i.e. none of the above)
113  *   This will cause the respective portion of the group state (see
114  *   struct xkb_state) to be matched against the groups given in the
115  *   "groups" statement.
116  *
117  *   Note: the above conditions are disjunctive, i.e. if any of them are
118  *   satisfied the led is lit.
119  *
120  * Virtual modifier statements
121  * ---------------------------
122  * Statements of the form:
123  *     virtual_modifiers LControl;
124  *
125  * Can appear in the xkb_types, xkb_compat, xkb_symbols sections.
126  * TODO
127  *
128  * Effect on keymap
129  * ----------------
130  * After all of the xkb_compat sections have been compiled, the following
131  * members of struct xkb_keymap are finalized:
132  *      darray(struct xkb_sym_interpret) sym_interpret;
133  *      struct xkb_indicator_map indicators[XkbNumIndicators];
134  *      char *compat_section_name;
135  * TODO: virtual modifiers.
136  */
137
138 enum si_field {
139     SI_FIELD_VIRTUAL_MOD    = (1 << 0),
140     SI_FIELD_ACTION         = (1 << 1),
141     SI_FIELD_AUTO_REPEAT    = (1 << 2),
142     SI_FIELD_LOCKING_KEY    = (1 << 3),
143     SI_FIELD_LEVEL_ONE_ONLY = (1 << 4),
144 };
145
146 typedef struct _SymInterpInfo {
147     enum si_field defined;
148     unsigned file_id;
149     enum merge_mode merge;
150     struct list entry;
151
152     struct xkb_sym_interpret interp;
153 } SymInterpInfo;
154
155 enum led_field {
156     LED_FIELD_INDEX      = (1 << 0),
157     LED_FIELD_MODS       = (1 << 1),
158     LED_FIELD_GROUPS     = (1 << 2),
159     LED_FIELD_CTRLS      = (1 << 3),
160     LED_FIELD_EXPLICIT   = (1 << 4),
161     LED_FIELD_AUTOMATIC  = (1 << 5),
162     LED_FIELD_DRIVES_KBD = (1 << 6),
163 };
164
165 typedef struct _LEDInfo {
166     enum led_field defined;
167     unsigned file_id;
168     enum merge_mode merge;
169     struct list entry;
170
171     xkb_atom_t name;
172     xkb_led_index_t indicator;
173     unsigned char flags;
174     unsigned char which_mods;
175     xkb_mod_mask_t mods;
176     unsigned char which_groups;
177     uint32_t groups;
178     unsigned int ctrls;
179 } LEDInfo;
180
181 typedef struct _GroupCompatInfo {
182     unsigned file_id;
183     enum merge_mode merge;
184     bool defined;
185     xkb_mod_mask_t mods;
186 } GroupCompatInfo;
187
188 typedef struct _CompatInfo {
189     char *name;
190     unsigned file_id;
191     int errorCount;
192     int nInterps;
193     struct list interps;
194     SymInterpInfo dflt;
195     LEDInfo ledDflt;
196     GroupCompatInfo groupCompat[XkbNumKbdGroups];
197     struct list leds;
198     VModInfo vmods;
199     ActionInfo *act;
200     struct xkb_keymap *keymap;
201 } CompatInfo;
202
203 static const char *
204 siText(SymInterpInfo * si, CompatInfo * info)
205 {
206     static char buf[128];
207
208     if (si == &info->dflt) {
209         snprintf(buf, sizeof(buf), "default");
210     }
211     else {
212         snprintf(buf, sizeof(buf), "%s+%s(%s)",
213                  KeysymText(si->interp.sym),
214                  SIMatchText(si->interp.match),
215                  ModMaskText(si->interp.mods));
216     }
217     return buf;
218 }
219
220 static inline bool
221 ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field)
222 {
223     return ReportNotArray(info->keymap, "symbol interpretation", field,
224                           siText(si, info));
225 }
226
227 static inline bool
228 ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field,
229                 const char *wanted)
230 {
231     return ReportBadType(info->keymap->ctx, "symbol interpretation", field,
232                          siText(si, info), wanted);
233 }
234
235 static inline bool
236 ReportIndicatorBadType(CompatInfo *info, LEDInfo *led,
237                        const char *field, const char *wanted)
238 {
239     return ReportBadType(info->keymap->ctx, "indicator map", field,
240                          xkb_atom_text(info->keymap->ctx, led->name),
241                          wanted);
242 }
243
244 static inline bool
245 ReportIndicatorNotArray(CompatInfo *info, LEDInfo *led,
246                         const char *field)
247 {
248     return ReportNotArray(info->keymap, "indicator map", field,
249                           xkb_atom_text(info->keymap->ctx, led->name));
250 }
251
252 static void
253 ClearIndicatorMapInfo(struct xkb_context *ctx, LEDInfo * info)
254 {
255     info->name = xkb_atom_intern(ctx, "default");
256     info->indicator = XKB_LED_INVALID;
257     info->flags = 0;
258     info->which_mods = 0;
259     info->mods = 0;
260     info->which_groups = info->groups = 0;
261     info->ctrls = 0;
262 }
263
264 static void
265 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
266 {
267     info->keymap = keymap;
268     info->name = NULL;
269     info->file_id = file_id;
270     info->errorCount = 0;
271     info->nInterps = 0;
272     list_init(&info->interps);
273     info->act = NULL;
274     info->dflt.file_id = file_id;
275     info->dflt.defined = 0;
276     info->dflt.merge = MERGE_OVERRIDE;
277     info->dflt.interp.flags = 0;
278     info->dflt.interp.virtual_mod = XkbNoModifier;
279     memset(&info->dflt.interp.act, 0, sizeof(info->dflt.interp.act));
280     info->dflt.interp.act.type = XkbSA_NoAction;
281     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
282     info->ledDflt.file_id = file_id;
283     info->ledDflt.defined = 0;
284     info->ledDflt.merge = MERGE_OVERRIDE;
285     memset(&info->groupCompat[0], 0,
286            XkbNumKbdGroups * sizeof(GroupCompatInfo));
287     list_init(&info->leds);
288     InitVModInfo(&info->vmods, keymap);
289 }
290
291 static void
292 ClearCompatInfo(CompatInfo *info)
293 {
294     SymInterpInfo *si, *next_si;
295     LEDInfo *led, *next_led;
296     struct xkb_keymap *keymap = info->keymap;
297
298     free(info->name);
299     info->name = NULL;
300     info->dflt.defined = 0;
301     info->dflt.merge = MERGE_AUGMENT;
302     info->dflt.interp.flags = 0;
303     info->dflt.interp.virtual_mod = XkbNoModifier;
304     memset(&info->dflt.interp.act, 0, sizeof(info->dflt.interp.act));
305     info->dflt.interp.act.type = XkbSA_NoAction;
306     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
307     info->nInterps = 0;
308     list_foreach_safe(si, next_si, &info->interps, entry)
309         free(si);
310     memset(&info->groupCompat[0], 0,
311            XkbNumKbdGroups * sizeof(GroupCompatInfo));
312     list_foreach_safe(led, next_led, &info->leds, entry)
313         free(led);
314     FreeActionInfo(info->act);
315     info->act = NULL;
316     info->keymap = NULL;
317     ClearVModInfo(&info->vmods, keymap);
318 }
319
320 static SymInterpInfo *
321 NextInterp(CompatInfo * info)
322 {
323     SymInterpInfo *si;
324
325     si = calloc(1, sizeof(*si));
326     if (!si)
327         return NULL;
328
329     list_append(&si->entry, &info->interps);
330     info->nInterps++;
331
332     return si;
333 }
334
335 static SymInterpInfo *
336 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
337 {
338     SymInterpInfo *old;
339
340     list_foreach(old, &info->interps, entry)
341         if (old->interp.sym == new->interp.sym &&
342             old->interp.mods == new->interp.mods &&
343             old->interp.match == new->interp.match)
344             return old;
345
346     return NULL;
347 }
348
349 static bool
350 UseNewInterpField(enum si_field field, SymInterpInfo *old, SymInterpInfo *new,
351                   int verbosity, enum si_field *collide)
352 {
353     if (!(old->defined & field))
354         return true;
355
356     if (new->defined & field) {
357         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
358             *collide |= field;
359
360         if (new->merge != MERGE_AUGMENT)
361             return true;
362     }
363
364     return false;
365 }
366
367 static bool
368 AddInterp(CompatInfo * info, SymInterpInfo * new)
369 {
370     enum si_field collide;
371     SymInterpInfo *old;
372     struct list entry;
373     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
374
375     collide = 0;
376     old = FindMatchingInterp(info, new);
377     if (old != NULL) {
378         if (new->merge == MERGE_REPLACE) {
379             entry = old->entry;
380             if ((old->file_id == new->file_id && verbosity > 0) ||
381                 verbosity > 9)
382                 log_warn(info->keymap->ctx,
383                          "Multiple definitions for \"%s\"; "
384                          "Earlier interpretation ignored\n",
385                          siText(new, info));
386             *old = *new;
387             old->entry = entry;
388             return true;
389         }
390
391         if (UseNewInterpField(SI_FIELD_VIRTUAL_MOD, old, new, verbosity,
392                               &collide)) {
393             old->interp.virtual_mod = new->interp.virtual_mod;
394             old->defined |= SI_FIELD_VIRTUAL_MOD;
395         }
396         if (UseNewInterpField(SI_FIELD_ACTION, old, new, verbosity,
397                               &collide)) {
398             old->interp.act = new->interp.act;
399             old->defined |= SI_FIELD_ACTION;
400         }
401         if (UseNewInterpField(SI_FIELD_AUTO_REPEAT, old, new, verbosity,
402                               &collide)) {
403             old->interp.flags &= ~XkbSI_AutoRepeat;
404             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
405             old->defined |= SI_FIELD_AUTO_REPEAT;
406         }
407         if (UseNewInterpField(SI_FIELD_LOCKING_KEY, old, new, verbosity,
408                               &collide)) {
409             old->interp.flags &= ~XkbSI_LockingKey;
410             old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
411             old->defined |= SI_FIELD_LOCKING_KEY;
412         }
413         if (UseNewInterpField(SI_FIELD_LEVEL_ONE_ONLY, old, new, verbosity,
414                               &collide)) {
415             old->interp.match &= ~XkbSI_LevelOneOnly;
416             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
417             old->defined |= SI_FIELD_LEVEL_ONE_ONLY;
418         }
419
420         if (collide) {
421             log_warn(info->keymap->ctx,
422                      "Multiple interpretations of \"%s\"; "
423                      "Using %s definition for duplicate fields\n",
424                      siText(new, info),
425                      (new->merge != MERGE_AUGMENT ? "last" : "first"));
426         }
427
428         return true;
429     }
430
431     old = new;
432     if ((new = NextInterp(info)) == NULL)
433         return false;
434     entry = new->entry;
435     *new = *old;
436     new->entry = entry;
437     return true;
438 }
439
440 static bool
441 AddGroupCompat(CompatInfo *info, xkb_group_index_t group, GroupCompatInfo *new)
442 {
443     GroupCompatInfo *gc;
444     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
445
446     gc = &info->groupCompat[group];
447     if (gc->mods == new->mods)
448         return true;
449
450     if ((gc->file_id == new->file_id && verbosity > 0) || verbosity > 9)
451         log_warn(info->keymap->ctx,
452                  "Compat map for group %u redefined; "
453                  "Using %s definition\n",
454                  group + 1, (new->merge == MERGE_AUGMENT ? "old" : "new"));
455
456     if (new->defined && (new->merge != MERGE_AUGMENT || !gc->defined))
457         *gc = *new;
458
459     return true;
460 }
461
462 /***====================================================================***/
463
464 static bool
465 ResolveStateAndPredicate(ExprDef * expr,
466                          unsigned *pred_rtrn,
467                          xkb_mod_mask_t *mods_rtrn, CompatInfo * info)
468 {
469     if (expr == NULL) {
470         *pred_rtrn = XkbSI_AnyOfOrNone;
471         *mods_rtrn = ~0;
472         return true;
473     }
474
475     *pred_rtrn = XkbSI_Exactly;
476     if (expr->op == EXPR_ACTION_DECL) {
477         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
478                                              expr->value.action.name);
479         if (istreq(pred_txt, "noneof"))
480             *pred_rtrn = XkbSI_NoneOf;
481         else if (istreq(pred_txt, "anyofornone"))
482             *pred_rtrn = XkbSI_AnyOfOrNone;
483         else if (istreq(pred_txt, "anyof"))
484             *pred_rtrn = XkbSI_AnyOf;
485         else if (istreq(pred_txt, "allof"))
486             *pred_rtrn = XkbSI_AllOf;
487         else if (istreq(pred_txt, "exactly"))
488             *pred_rtrn = XkbSI_Exactly;
489         else {
490             log_err(info->keymap->ctx,
491                     "Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
492             return false;
493         }
494         expr = expr->value.action.args;
495     }
496     else if (expr->op == EXPR_IDENT) {
497         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
498                                              expr->value.str);
499         if (pred_txt && istreq(pred_txt, "any")) {
500             *pred_rtrn = XkbSI_AnyOf;
501             *mods_rtrn = 0xff;
502             return true;
503         }
504     }
505
506     return ExprResolveModMask(info->keymap->ctx, expr, mods_rtrn);
507 }
508
509 /***====================================================================***/
510
511 static bool
512 UseNewLEDField(enum led_field field, LEDInfo *old, LEDInfo *new,
513                int verbosity, enum led_field *collide)
514 {
515     if (!(old->defined & field))
516         return true;
517
518     if (new->defined & field) {
519         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
520             *collide |= field;
521
522         if (new->merge != MERGE_AUGMENT)
523             return true;
524     }
525
526     return false;
527 }
528
529 static bool
530 AddIndicatorMap(CompatInfo *info, LEDInfo *new)
531 {
532     LEDInfo *old;
533     enum led_field collide;
534     struct xkb_context *ctx = info->keymap->ctx;
535     int verbosity = xkb_get_log_verbosity(ctx);
536
537     list_foreach(old, &info->leds, entry) {
538         if (old->name == new->name) {
539             if ((old->mods == new->mods) &&
540                 (old->groups == new->groups) &&
541                 (old->ctrls == new->ctrls) &&
542                 (old->which_mods == new->which_mods) &&
543                 (old->which_groups == new->which_groups)) {
544                 old->defined |= new->defined;
545                 return true;
546             }
547
548             if (new->merge == MERGE_REPLACE) {
549                 struct list entry = old->entry;
550                 if ((old->file_id == new->file_id && verbosity > 0) ||
551                     verbosity > 9)
552                     log_warn(info->keymap->ctx,
553                              "Map for indicator %s redefined; "
554                              "Earlier definition ignored\n",
555                              xkb_atom_text(ctx, old->name));
556                 *old = *new;
557                 old->entry = entry;
558                 return true;
559             }
560
561             collide = 0;
562             if (UseNewLEDField(LED_FIELD_INDEX, old, new, verbosity,
563                                &collide)) {
564                 old->indicator = new->indicator;
565                 old->defined |= LED_FIELD_INDEX;
566             }
567             if (UseNewLEDField(LED_FIELD_MODS, old, new, verbosity,
568                                &collide)) {
569                 old->which_mods = new->which_mods;
570                 old->mods = new->mods;
571                 old->defined |= LED_FIELD_MODS;
572             }
573             if (UseNewLEDField(LED_FIELD_GROUPS, old, new, verbosity,
574                                &collide)) {
575                 old->which_groups = new->which_groups;
576                 old->groups = new->groups;
577                 old->defined |= LED_FIELD_GROUPS;
578             }
579             if (UseNewLEDField(LED_FIELD_CTRLS, old, new, verbosity,
580                                &collide)) {
581                 old->ctrls = new->ctrls;
582                 old->defined |= LED_FIELD_CTRLS;
583             }
584             if (UseNewLEDField(LED_FIELD_EXPLICIT, old, new, verbosity,
585                                &collide)) {
586                 old->flags &= ~XkbIM_NoExplicit;
587                 old->flags |= (new->flags & XkbIM_NoExplicit);
588                 old->defined |= LED_FIELD_EXPLICIT;
589             }
590             if (UseNewLEDField(LED_FIELD_AUTOMATIC, old, new, verbosity,
591                                &collide)) {
592                 old->flags &= ~XkbIM_NoAutomatic;
593                 old->flags |= (new->flags & XkbIM_NoAutomatic);
594                 old->defined |= LED_FIELD_AUTOMATIC;
595             }
596             if (UseNewLEDField(LED_FIELD_DRIVES_KBD, old, new, verbosity,
597                                &collide)) {
598                 old->flags &= ~XkbIM_LEDDrivesKB;
599                 old->flags |= (new->flags & XkbIM_LEDDrivesKB);
600                 old->defined |= LED_FIELD_DRIVES_KBD;
601             }
602
603             if (collide) {
604                 log_warn(info->keymap->ctx,
605                          "Map for indicator %s redefined; "
606                          "Using %s definition for duplicate fields\n",
607                          xkb_atom_text(ctx, old->name),
608                          (new->merge == MERGE_AUGMENT ? "first" : "last"));
609             }
610
611             return true;
612         }
613     }
614
615     /* new definition */
616     old = malloc(sizeof(*old));
617     if (!old) {
618         log_wsgo(info->keymap->ctx,
619                  "Couldn't allocate indicator map; "
620                  "Map for indicator %s not compiled\n",
621                  xkb_atom_text(ctx, new->name));
622         return false;
623     }
624
625     *old = *new;
626     list_append(&old->entry, &info->leds);
627
628     return true;
629 }
630
631 static void
632 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
633                         enum merge_mode merge)
634 {
635     SymInterpInfo *si;
636     LEDInfo *led, *next_led;
637     GroupCompatInfo *gcm;
638     xkb_group_index_t i;
639
640     if (from->errorCount > 0) {
641         into->errorCount += from->errorCount;
642         return;
643     }
644     if (into->name == NULL) {
645         into->name = from->name;
646         from->name = NULL;
647     }
648
649     list_foreach(si, &from->interps, entry) {
650         if (merge != MERGE_DEFAULT)
651             si->merge = merge;
652         if (!AddInterp(into, si))
653             into->errorCount++;
654     }
655
656     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups;
657          i++, gcm++) {
658         if (merge != MERGE_DEFAULT)
659             gcm->merge = merge;
660         if (!AddGroupCompat(into, i, gcm))
661             into->errorCount++;
662     }
663
664     list_foreach_safe(led, next_led, &from->leds, entry) {
665         led->merge = (merge == MERGE_DEFAULT ? led->merge : merge);
666         if (!AddIndicatorMap(into, led))
667             into->errorCount++;
668     }
669 }
670
671 static void
672 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge);
673
674 static bool
675 HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *stmt)
676 {
677     enum merge_mode merge = MERGE_DEFAULT;
678     XkbFile *rtrn;
679     CompatInfo included, next_incl;
680
681     InitCompatInfo(&included, info->keymap, info->file_id);
682     if (stmt->stmt) {
683         free(included.name);
684         included.name = stmt->stmt;
685         stmt->stmt = NULL;
686     }
687
688     for (; stmt; stmt = stmt->next_incl) {
689         if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT,
690                                 &rtrn, &merge)) {
691             info->errorCount += 10;
692             ClearCompatInfo(&included);
693             return false;
694         }
695
696         InitCompatInfo(&next_incl, info->keymap, rtrn->id);
697         next_incl.file_id = rtrn->id;
698         next_incl.dflt = info->dflt;
699         next_incl.dflt.file_id = rtrn->id;
700         next_incl.dflt.merge = merge;
701         next_incl.ledDflt.file_id = rtrn->id;
702         next_incl.ledDflt.merge = merge;
703         next_incl.act = info->act;
704
705         HandleCompatMapFile(&next_incl, rtrn, MERGE_OVERRIDE);
706
707         MergeIncludedCompatMaps(&included, &next_incl, merge);
708         if (info->act)
709             next_incl.act = NULL;
710
711         ClearCompatInfo(&next_incl);
712         FreeXkbFile(rtrn);
713     }
714
715     MergeIncludedCompatMaps(info, &included, merge);
716     ClearCompatInfo(&included);
717
718     return (info->errorCount == 0);
719 }
720
721 static const LookupEntry useModMapValues[] = {
722     { "levelone", 1 },
723     { "level1", 1 },
724     { "anylevel", 0 },
725     { "any", 0 },
726     { NULL, 0 }
727 };
728
729 static int
730 SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
731                ExprDef *arrayNdx, ExprDef *value)
732 {
733     struct xkb_keymap *keymap = info->keymap;
734     xkb_mod_index_t ndx;
735
736     if (istreq(field, "action")) {
737         if (arrayNdx)
738             return ReportSINotArray(info, si, field);
739
740         if (!HandleActionDef(value, keymap, &si->interp.act, info->act))
741             return false;
742
743         si->defined |= SI_FIELD_ACTION;
744     }
745     else if (istreq(field, "virtualmodifier") ||
746              istreq(field, "virtualmod")) {
747         if (arrayNdx)
748             return ReportSINotArray(info, si, field);
749
750         if (!ResolveVirtualModifier(value, keymap, &ndx, &info->vmods))
751             return ReportSIBadType(info, si, field, "virtual modifier");
752
753         si->interp.virtual_mod = ndx;
754         si->defined |= SI_FIELD_VIRTUAL_MOD;
755     }
756     else if (istreq(field, "repeat")) {
757         bool set;
758
759         if (arrayNdx)
760             return ReportSINotArray(info, si, field);
761
762         if (!ExprResolveBoolean(keymap->ctx, value, &set))
763             return ReportSIBadType(info, si, field, "boolean");
764
765         if (set)
766             si->interp.flags |= XkbSI_AutoRepeat;
767         else
768             si->interp.flags &= ~XkbSI_AutoRepeat;
769
770         si->defined |= SI_FIELD_AUTO_REPEAT;
771     }
772     else if (istreq(field, "locking")) {
773         bool set;
774
775         if (arrayNdx)
776             return ReportSINotArray(info, si, field);
777
778         if (!ExprResolveBoolean(keymap->ctx, value, &set))
779             return ReportSIBadType(info, si, field, "boolean");
780
781         if (set)
782             si->interp.flags |= XkbSI_LockingKey;
783         else
784             si->interp.flags &= ~XkbSI_LockingKey;
785
786         si->defined |= SI_FIELD_LOCKING_KEY;
787     }
788     else if (istreq(field, "usemodmap") ||
789              istreq(field, "usemodmapmods")) {
790         unsigned int val;
791
792         if (arrayNdx)
793             return ReportSINotArray(info, si, field);
794
795         if (!ExprResolveEnum(keymap->ctx, value, &val, useModMapValues))
796             return ReportSIBadType(info, si, field, "level specification");
797
798         if (val)
799             si->interp.match |= XkbSI_LevelOneOnly;
800         else
801             si->interp.match &= ~XkbSI_LevelOneOnly;
802
803         si->defined |= SI_FIELD_LEVEL_ONE_ONLY;
804     }
805     else {
806         return ReportBadField(keymap, "symbol interpretation", field,
807                               siText(si, info));
808     }
809
810     return true;
811 }
812
813 static const LookupEntry modComponentNames[] = {
814     {"base", XkbIM_UseBase},
815     {"latched", XkbIM_UseLatched},
816     {"locked", XkbIM_UseLocked},
817     {"effective", XkbIM_UseEffective},
818     {"compat", XkbIM_UseCompat},
819     {"any", XkbIM_UseAnyMods},
820     {"none", 0},
821     {NULL, 0}
822 };
823 static const LookupEntry groupComponentNames[] = {
824     {"base", XkbIM_UseBase},
825     {"latched", XkbIM_UseLatched},
826     {"locked", XkbIM_UseLocked},
827     {"effective", XkbIM_UseEffective},
828     {"any", XkbIM_UseAnyGroup},
829     {"none", 0},
830     {NULL, 0}
831 };
832
833 static const LookupEntry groupNames[] = {
834     {"group1", 0x01},
835     {"group2", 0x02},
836     {"group3", 0x04},
837     {"group4", 0x08},
838     {"group5", 0x10},
839     {"group6", 0x20},
840     {"group7", 0x40},
841     {"group8", 0x80},
842     {"none", 0x00},
843     {"all", 0xff},
844     {NULL, 0}
845 };
846
847 static int
848 SetIndicatorMapField(CompatInfo *info, LEDInfo *led,
849                      const char *field, ExprDef *arrayNdx, ExprDef *value)
850 {
851     bool ok = true;
852     struct xkb_keymap *keymap = info->keymap;
853
854     if (istreq(field, "modifiers") || istreq(field, "mods")) {
855         if (arrayNdx)
856             return ReportIndicatorNotArray(info, led, field);
857
858         if (!ExprResolveVModMask(keymap, value, &led->mods))
859             return ReportIndicatorBadType(info, led, field, "modifier mask");
860
861         led->defined |= LED_FIELD_MODS;
862     }
863     else if (istreq(field, "groups")) {
864         unsigned int mask;
865
866         if (arrayNdx)
867             return ReportIndicatorNotArray(info, led, field);
868
869         if (!ExprResolveMask(keymap->ctx, value, &mask, groupNames))
870             return ReportIndicatorBadType(info, led, field, "group mask");
871
872         led->groups = mask;
873         led->defined |= LED_FIELD_GROUPS;
874     }
875     else if (istreq(field, "controls") || istreq(field, "ctrls")) {
876         unsigned int mask;
877
878         if (arrayNdx)
879             return ReportIndicatorNotArray(info, led, field);
880
881         if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlNames))
882             return ReportIndicatorBadType(info, led, field,
883                                           "controls mask");
884
885         led->ctrls = mask;
886         led->defined |= LED_FIELD_CTRLS;
887     }
888     else if (istreq(field, "allowexplicit")) {
889         bool set;
890
891         if (arrayNdx)
892             return ReportIndicatorNotArray(info, led, field);
893
894         if (!ExprResolveBoolean(keymap->ctx, value, &set))
895             return ReportIndicatorBadType(info, led, field, "boolean");
896
897         if (set)
898             led->flags &= ~XkbIM_NoExplicit;
899         else
900             led->flags |= XkbIM_NoExplicit;
901
902         led->defined |= LED_FIELD_EXPLICIT;
903     }
904     else if (istreq(field, "whichmodstate") ||
905              istreq(field, "whichmodifierstate")) {
906         unsigned int mask;
907
908         if (arrayNdx)
909             return ReportIndicatorNotArray(info, led, field);
910
911         if (!ExprResolveMask(keymap->ctx, value, &mask, modComponentNames))
912             return ReportIndicatorBadType(info, led, field,
913                                           "mask of modifier state components");
914
915         led->which_mods = mask;
916     }
917     else if (istreq(field, "whichgroupstate")) {
918         unsigned mask;
919
920         if (arrayNdx)
921             return ReportIndicatorNotArray(info, led, field);
922
923         if (!ExprResolveMask(keymap->ctx, value, &mask, groupComponentNames))
924             return ReportIndicatorBadType(info, led, field,
925                                           "mask of group state components");
926
927         led->which_groups = mask;
928     }
929     else if (istreq(field, "driveskbd") ||
930              istreq(field, "driveskeyboard") ||
931              istreq(field, "leddriveskbd") ||
932              istreq(field, "leddriveskeyboard") ||
933              istreq(field, "indicatordriveskbd") ||
934              istreq(field, "indicatordriveskeyboard")) {
935         bool set;
936
937         if (arrayNdx)
938             return ReportIndicatorNotArray(info, led, field);
939
940         if (!ExprResolveBoolean(keymap->ctx, value, &set))
941             return ReportIndicatorBadType(info, led, field, "boolean");
942
943         if (set)
944             led->flags |= XkbIM_LEDDrivesKB;
945         else
946             led->flags &= ~XkbIM_LEDDrivesKB;
947
948         led->defined |= LED_FIELD_DRIVES_KBD;
949     }
950     else if (istreq(field, "index")) {
951         int ndx;
952
953         if (arrayNdx)
954             return ReportIndicatorNotArray(info, led, field);
955
956         if (!ExprResolveInteger(keymap->ctx, value, &ndx))
957             return ReportIndicatorBadType(info, led, field,
958                                           "indicator index");
959
960         if (ndx < 1 || ndx > 32) {
961             log_err(info->keymap->ctx,
962                     "Illegal indicator index %d (range 1..%d); "
963                     "Index definition for %s indicator ignored\n",
964                     ndx, XkbNumIndicators,
965                     xkb_atom_text(keymap->ctx, led->name));
966             return false;
967         }
968
969         led->indicator = (xkb_led_index_t) ndx;
970         led->defined |= LED_FIELD_INDEX;
971     }
972     else {
973         log_err(info->keymap->ctx,
974                 "Unknown field %s in map for %s indicator; "
975                 "Definition ignored\n",
976                 field, xkb_atom_text(keymap->ctx, led->name));
977         ok = false;
978     }
979
980     return ok;
981 }
982
983 static int
984 HandleInterpVar(CompatInfo *info, VarDef *stmt)
985 {
986     const char *elem, *field;
987     ExprDef *ndx;
988     int ret;
989
990     if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &ndx))
991         ret = 0;               /* internal error, already reported */
992     else if (elem && istreq(elem, "interpret"))
993         ret = SetInterpField(info, &info->dflt, field, ndx, stmt->value);
994     else if (elem && istreq(elem, "indicator"))
995         ret = SetIndicatorMapField(info, &info->ledDflt, field, ndx,
996                                    stmt->value);
997     else
998         ret = SetActionField(info->keymap, elem, field, ndx, stmt->value,
999                              &info->act);
1000     return ret;
1001 }
1002
1003 static int
1004 HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
1005 {
1006     int ok = 1;
1007     const char *elem, *field;
1008     ExprDef *arrayNdx;
1009
1010     for (; def != NULL; def = (VarDef *) def->common.next) {
1011         if (def->name && def->name->op == EXPR_FIELD_REF) {
1012             ok = HandleInterpVar(info, def);
1013             continue;
1014         }
1015         ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
1016                             &arrayNdx);
1017         if (ok) {
1018             ok = SetInterpField(info, si, field, arrayNdx, def->value);
1019         }
1020     }
1021     return ok;
1022 }
1023
1024 static int
1025 HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
1026 {
1027     unsigned pred, mods;
1028     SymInterpInfo si;
1029
1030     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
1031         log_err(info->keymap->ctx,
1032                 "Couldn't determine matching modifiers; "
1033                 "Symbol interpretation ignored\n");
1034         return false;
1035     }
1036     if (def->merge != MERGE_DEFAULT)
1037         merge = def->merge;
1038
1039     si = info->dflt;
1040     si.merge = merge;
1041     if (!LookupKeysym(def->sym, &si.interp.sym)) {
1042         log_err(info->keymap->ctx,
1043                 "Could not resolve keysym %s; "
1044                 "Symbol interpretation ignored\n",
1045                 def->sym);
1046         return false;
1047     }
1048     si.interp.match = pred & XkbSI_OpMask;
1049     si.interp.mods = mods;
1050     if (!HandleInterpBody(info, def->def, &si)) {
1051         info->errorCount++;
1052         return false;
1053     }
1054
1055     if (!AddInterp(info, &si)) {
1056         info->errorCount++;
1057         return false;
1058     }
1059     return true;
1060 }
1061
1062 static int
1063 HandleGroupCompatDef(CompatInfo *info, GroupCompatDef *def,
1064                      enum merge_mode merge)
1065 {
1066     GroupCompatInfo tmp;
1067
1068     merge = (def->merge == MERGE_DEFAULT ? merge : def->merge);
1069
1070     if (def->group < 1 || def->group > XkbNumKbdGroups) {
1071         log_err(info->keymap->ctx,
1072                 "Keyboard group must be in the range 1..%u; "
1073                 "Compatibility map for illegal group %u ignored\n",
1074                 XkbNumKbdGroups, def->group);
1075         return false;
1076     }
1077
1078     tmp.file_id = info->file_id;
1079     tmp.merge = merge;
1080
1081     if (!ExprResolveVModMask(info->keymap, def->def, &tmp.mods)) {
1082         log_err(info->keymap->ctx,
1083                 "Expected a modifier mask in group compatibility definition; "
1084                 "Ignoring illegal compatibility map for group %u\n",
1085                 def->group);
1086         return false;
1087     }
1088
1089     tmp.defined = true;
1090     return AddGroupCompat(info, def->group - 1, &tmp);
1091 }
1092
1093 static bool
1094 HandleIndicatorMapDef(CompatInfo *info, IndicatorMapDef *def,
1095                       enum merge_mode merge)
1096 {
1097     LEDInfo led;
1098     VarDef *var;
1099     bool ok;
1100
1101     if (def->merge != MERGE_DEFAULT)
1102         merge = def->merge;
1103
1104     led = info->ledDflt;
1105     led.merge = merge;
1106     led.name = def->name;
1107
1108     ok = true;
1109     for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
1110         const char *elem, *field;
1111         ExprDef *arrayNdx;
1112         if (!ExprResolveLhs(info->keymap->ctx, var->name, &elem, &field,
1113                             &arrayNdx)) {
1114             ok = false;
1115             continue;
1116         }
1117
1118         if (elem) {
1119             log_err(info->keymap->ctx,
1120                     "Cannot set defaults for \"%s\" element in indicator map; "
1121                     "Assignment to %s.%s ignored\n", elem, elem, field);
1122             ok = false;
1123         }
1124         else {
1125             ok = SetIndicatorMapField(info, &led, field, arrayNdx,
1126                                       var->value) && ok;
1127         }
1128     }
1129
1130     if (ok)
1131         return AddIndicatorMap(info, &led);
1132
1133     return false;
1134 }
1135
1136 static void
1137 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
1138 {
1139     bool ok;
1140     ParseCommon *stmt;
1141
1142     merge = (merge == MERGE_DEFAULT ? MERGE_AUGMENT : merge);
1143
1144     free(info->name);
1145     info->name = strdup_safe(file->name);
1146
1147     for (stmt = file->defs; stmt; stmt = stmt->next) {
1148         switch (stmt->type) {
1149         case STMT_INCLUDE:
1150             ok = HandleIncludeCompatMap(info, (IncludeStmt *) stmt);
1151             break;
1152         case STMT_INTERP:
1153             ok = HandleInterpDef(info, (InterpDef *) stmt, merge);
1154             break;
1155         case STMT_GROUP_COMPAT:
1156             ok = HandleGroupCompatDef(info, (GroupCompatDef *) stmt, merge);
1157             break;
1158         case STMT_INDICATOR_MAP:
1159             ok = HandleIndicatorMapDef(info, (IndicatorMapDef *) stmt, merge);
1160             break;
1161         case STMT_VAR:
1162             ok = HandleInterpVar(info, (VarDef *) stmt);
1163             break;
1164         case STMT_VMOD:
1165             ok = HandleVModDef((VModDef *) stmt, info->keymap, merge,
1166                                &info->vmods);
1167             break;
1168         default:
1169             log_err(info->keymap->ctx,
1170                     "Interpretation files may not include other types; "
1171                     "Ignoring %s\n", StmtTypeToString(stmt->type));
1172             ok = false;
1173             break;
1174         }
1175
1176         if (!ok)
1177             info->errorCount++;
1178
1179         if (info->errorCount > 10) {
1180             log_err(info->keymap->ctx,
1181                     "Abandoning compatibility map \"%s\"\n", file->topName);
1182             break;
1183         }
1184     }
1185 }
1186
1187 static void
1188 CopyInterps(CompatInfo *info, bool needSymbol, unsigned pred)
1189 {
1190     SymInterpInfo *si;
1191
1192     list_foreach(si, &info->interps, entry) {
1193         if (((si->interp.match & XkbSI_OpMask) != pred) ||
1194             (needSymbol && si->interp.sym == XKB_KEY_NoSymbol) ||
1195             (!needSymbol && si->interp.sym != XKB_KEY_NoSymbol))
1196             continue;
1197
1198         darray_append(info->keymap->sym_interpret, si->interp);
1199     }
1200 }
1201
1202 static void
1203 BindIndicators(CompatInfo *info, struct list *unbound_leds)
1204 {
1205     xkb_led_index_t i;
1206     LEDInfo *led, *next_led;
1207     struct xkb_indicator_map *map;
1208     struct xkb_keymap *keymap = info->keymap;
1209
1210     list_foreach(led, unbound_leds, entry) {
1211         if (led->indicator == XKB_LED_INVALID) {
1212             for (i = 0; i < XkbNumIndicators; i++) {
1213                 if (keymap->indicator_names[i] &&
1214                     streq(keymap->indicator_names[i],
1215                           xkb_atom_text(keymap->ctx, led->name))) {
1216                     led->indicator = i + 1;
1217                     break;
1218                 }
1219             }
1220         }
1221     }
1222
1223     list_foreach(led, unbound_leds, entry) {
1224         if (led->indicator == XKB_LED_INVALID) {
1225             for (i = 0; i < XkbNumIndicators; i++) {
1226                 if (keymap->indicator_names[i] == NULL) {
1227                     keymap->indicator_names[i] =
1228                         xkb_atom_text(keymap->ctx, led->name);
1229                     led->indicator = i + 1;
1230                     break;
1231                 }
1232             }
1233
1234             if (led->indicator == XKB_LED_INVALID) {
1235                 log_err(info->keymap->ctx,
1236                         "No unnamed indicators found; "
1237                         "Virtual indicator map \"%s\" not bound\n",
1238                         xkb_atom_text(keymap->ctx, led->name));
1239                 continue;
1240             }
1241         }
1242     }
1243
1244     list_foreach_safe(led, next_led, unbound_leds, entry) {
1245         if (led->indicator == XKB_LED_INVALID) {
1246             free(led);
1247             continue;
1248         }
1249
1250         if (!streq(keymap->indicator_names[led->indicator - 1],
1251                    xkb_atom_text(keymap->ctx, led->name))) {
1252             const char *old = keymap->indicator_names[led->indicator - 1];
1253             log_err(info->keymap->ctx,
1254                     "Multiple names bound to indicator %d; "
1255                     "Using %s, ignoring %s\n",
1256                     led->indicator, old,
1257                     xkb_atom_text(keymap->ctx, led->name));
1258             free(led);
1259             continue;
1260         }
1261
1262         map = &keymap->indicators[led->indicator - 1];
1263         map->flags = led->flags;
1264         map->which_groups = led->which_groups;
1265         map->groups = led->groups;
1266         map->which_mods = led->which_mods;
1267         map->mods.mods = led->mods;
1268         map->ctrls = led->ctrls;
1269         free(led);
1270     }
1271
1272     list_init(unbound_leds);
1273 }
1274
1275 static bool
1276 CopyIndicatorMapDefs(CompatInfo *info)
1277 {
1278     LEDInfo *led, *next_led;
1279     struct list unbound_leds;
1280     struct xkb_indicator_map *im;
1281     struct xkb_keymap *keymap = info->keymap;
1282
1283     list_init(&unbound_leds);
1284
1285     list_foreach_safe(led, next_led, &info->leds, entry) {
1286         if (led->groups != 0 && led->which_groups == 0)
1287             led->which_groups = XkbIM_UseEffective;
1288
1289         if (led->which_mods == 0 && led->mods)
1290             led->which_mods = XkbIM_UseEffective;
1291
1292         if (led->indicator == XKB_LED_INVALID) {
1293             list_append(&led->entry, &unbound_leds);
1294             continue;
1295         }
1296
1297         im = &keymap->indicators[led->indicator - 1];
1298         im->flags = led->flags;
1299         im->which_groups = led->which_groups;
1300         im->groups = led->groups;
1301         im->which_mods = led->which_mods;
1302         im->mods.mods = led->mods;
1303         im->ctrls = led->ctrls;
1304         keymap->indicator_names[led->indicator - 1] =
1305             xkb_atom_text(keymap->ctx, led->name);
1306         free(led);
1307     }
1308     list_init(&info->leds);
1309
1310     BindIndicators(info, &unbound_leds);
1311
1312     return true;
1313 }
1314
1315 bool
1316 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
1317                  enum merge_mode merge)
1318 {
1319     xkb_group_index_t i;
1320     CompatInfo info;
1321     GroupCompatInfo *gcm;
1322
1323     InitCompatInfo(&info, keymap, file->id);
1324     info.dflt.merge = merge;
1325     info.ledDflt.merge = merge;
1326
1327     HandleCompatMapFile(&info, file, merge);
1328
1329     if (info.errorCount != 0)
1330         goto err_info;
1331
1332     darray_init(keymap->sym_interpret);
1333     darray_growalloc(keymap->sym_interpret, info.nInterps);
1334
1335     if (info.name)
1336         keymap->compat_section_name = strdup(info.name);
1337
1338     if (info.nInterps > 0) {
1339         CopyInterps(&info, true, XkbSI_Exactly);
1340         CopyInterps(&info, true, XkbSI_AllOf | XkbSI_NoneOf);
1341         CopyInterps(&info, true, XkbSI_AnyOf);
1342         CopyInterps(&info, true, XkbSI_AnyOfOrNone);
1343         CopyInterps(&info, false, XkbSI_Exactly);
1344         CopyInterps(&info, false, XkbSI_AllOf | XkbSI_NoneOf);
1345         CopyInterps(&info, false, XkbSI_AnyOf);
1346         CopyInterps(&info, false, XkbSI_AnyOfOrNone);
1347     }
1348
1349     for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
1350          i++, gcm++) {
1351         if (gcm->file_id != 0 || gcm->mods != 0)
1352             keymap->groups[i].mods = gcm->mods;
1353     }
1354
1355     if (!CopyIndicatorMapDefs(&info))
1356         info.errorCount++;
1357
1358     ClearCompatInfo(&info);
1359     return true;
1360
1361 err_info:
1362     ClearCompatInfo(&info);
1363     return false;
1364 }
1365
1366 static void
1367 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
1368 {
1369     xkb_mod_index_t i;
1370     xkb_mod_mask_t vmask = mods->mods >> XkbNumModifiers;
1371
1372     /* The effective mask is only real mods for now. */
1373     mods->mask = mods->mods & 0xff;
1374
1375     for (i = 0; i < XkbNumVirtualMods; i++) {
1376         if (!(vmask & (1 << i)))
1377             continue;
1378         mods->mask |= keymap->vmods[i];
1379     }
1380 }
1381
1382 static void
1383 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
1384                  xkb_mod_mask_t rmodmask)
1385 {
1386     unsigned int flags;
1387     struct xkb_mods *mods;
1388
1389     switch (act->type) {
1390     case XkbSA_SetMods:
1391     case XkbSA_LatchMods:
1392     case XkbSA_LockMods:
1393         flags = act->mods.flags;
1394         mods = &act->mods.mods;
1395         break;
1396
1397     case XkbSA_ISOLock:
1398         flags = act->iso.flags;
1399         mods = &act->iso.mods;
1400         break;
1401
1402     default:
1403         return;
1404     }
1405
1406     if (flags & XkbSA_UseModMapMods) {
1407         /* XXX: what's that. */
1408         mods->mods &= 0xff;
1409         mods->mods |= rmodmask;
1410     }
1411     ComputeEffectiveMask(keymap, mods);
1412 }
1413
1414 /**
1415  * Find an interpretation which applies to this particular level, either by
1416  * finding an exact match for the symbol and modifier combination, or a
1417  * generic XKB_KEY_NoSymbol match.
1418  */
1419 static struct xkb_sym_interpret *
1420 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
1421                  xkb_group_index_t group, xkb_level_index_t level)
1422 {
1423     struct xkb_sym_interpret *ret = NULL;
1424     struct xkb_sym_interpret *interp;
1425     const xkb_keysym_t *syms;
1426     int num_syms;
1427
1428     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
1429     if (num_syms == 0)
1430         return NULL;
1431
1432     darray_foreach(interp, keymap->sym_interpret) {
1433         uint32_t mods;
1434         bool found;
1435
1436         if ((num_syms > 1 || interp->sym != syms[0]) &&
1437             interp->sym != XKB_KEY_NoSymbol)
1438             continue;
1439
1440         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
1441             mods = key->modmap;
1442         else
1443             mods = 0;
1444
1445         switch (interp->match & XkbSI_OpMask) {
1446         case XkbSI_NoneOf:
1447             found = !(interp->mods & mods);
1448             break;
1449         case XkbSI_AnyOfOrNone:
1450             found = (!mods || (interp->mods & mods));
1451             break;
1452         case XkbSI_AnyOf:
1453             found = !!(interp->mods & mods);
1454             break;
1455         case XkbSI_AllOf:
1456             found = ((interp->mods & mods) == interp->mods);
1457             break;
1458         case XkbSI_Exactly:
1459             found = (interp->mods == mods);
1460             break;
1461         default:
1462             found = false;
1463             break;
1464         }
1465
1466         if (found && interp->sym != XKB_KEY_NoSymbol)
1467             return interp;
1468         else if (found && !ret)
1469             ret = interp;
1470     }
1471
1472     return ret;
1473 }
1474
1475 /**
1476  */
1477 static bool
1478 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
1479 {
1480 #define INTERP_SIZE (8 * 4)
1481     struct xkb_sym_interpret *interps[INTERP_SIZE];
1482     xkb_mod_mask_t vmodmask = 0;
1483     int num_acts = 0;
1484     xkb_group_index_t group;
1485     xkb_level_index_t level;
1486     unsigned int i;
1487
1488     /* If we've been told not to bind interps to this key, then don't. */
1489     if (key->explicit & XkbExplicitInterpretMask)
1490         return true;
1491
1492     for (i = 0; i < INTERP_SIZE; i++)
1493         interps[i] = NULL;
1494
1495     for (group = 0; group < key->num_groups; group++) {
1496         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1497              level++) {
1498             i = (group * key->width) + level;
1499             if (i >= INTERP_SIZE) /* XXX FIXME */
1500                 return false;
1501             interps[i] = FindInterpForKey(keymap, key, group, level);
1502             if (interps[i])
1503                 num_acts++;
1504         }
1505     }
1506
1507     if (num_acts && !key->actions) {
1508         key->actions = calloc(key->num_groups * key->width,
1509                               sizeof(*key->actions));
1510         if (!key->actions)
1511             return false;
1512     }
1513
1514     for (group = 0; group < key->num_groups; group++) {
1515         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1516              level++) {
1517             struct xkb_sym_interpret *interp;
1518
1519             i = (group * key->width) + level;
1520             interp = interps[i];
1521
1522             /* Infer default key behaviours from the base level. */
1523             if (group == 0 && level == 0) {
1524                 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
1525                     (!interp || (interp->flags & XkbSI_AutoRepeat)))
1526                     key->repeats = true;
1527             }
1528
1529             if (!interp)
1530                 continue;
1531
1532             if ((group == 0 && level == 0) ||
1533                 !(interp->match & XkbSI_LevelOneOnly)) {
1534                 if (interp->virtual_mod != XkbNoModifier)
1535                     vmodmask |= (1 << interp->virtual_mod);
1536             }
1537
1538             key->actions[i] = interp->act;
1539         }
1540     }
1541
1542     if (!(key->explicit & XkbExplicitVModMapMask))
1543         key->vmodmap = vmodmask;
1544
1545     return true;
1546 #undef INTERP_SIZE
1547 }
1548
1549 /**
1550  * This collects a bunch of disparate functions which was done in the server
1551  * at various points that really should've been done within xkbcomp.  Turns out
1552  * your actions and types are a lot more useful when any of your modifiers
1553  * other than Shift actually do something ...
1554  */
1555 bool
1556 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
1557 {
1558     xkb_mod_index_t vmod;
1559     xkb_group_index_t grp;
1560     xkb_led_index_t led;
1561     unsigned int i, j;
1562     struct xkb_key *key;
1563
1564     /* Find all the interprets for the key and bind them to actions,
1565      * which will also update the vmodmap. */
1566     xkb_foreach_key(key, keymap)
1567         if (!ApplyInterpsToKey(keymap, key))
1568             return false;
1569
1570     /* Update keymap->vmods, the virtual -> real mod mapping. */
1571     for (vmod = 0; vmod < XkbNumVirtualMods; vmod++)
1572         keymap->vmods[vmod] = 0;
1573
1574     xkb_foreach_key(key, keymap) {
1575         if (!key->vmodmap)
1576             continue;
1577
1578         for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) {
1579             if (!(key->vmodmap & (1 << vmod)))
1580                 continue;
1581             keymap->vmods[vmod] |= key->modmap;
1582         }
1583     }
1584
1585     /* Now update the level masks for all the types to reflect the vmods. */
1586     for (i = 0; i < keymap->num_types; i++) {
1587         ComputeEffectiveMask(keymap, &keymap->types[i].mods);
1588
1589         for (j = 0; j < keymap->types[i].num_entries; j++) {
1590             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods);
1591             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve);
1592         }
1593     }
1594
1595     /* Update action modifiers. */
1596     xkb_foreach_key(key, keymap) {
1597         if (!key->actions)
1598             continue;
1599
1600         for (i = 0; i < key->num_groups * key->width; i++)
1601             UpdateActionMods(keymap, &key->actions[i], key->modmap);
1602     }
1603
1604     /* Update group modifiers. */
1605     for (grp = 0; grp < XkbNumKbdGroups; grp++)
1606         ComputeEffectiveMask(keymap, &keymap->groups[grp]);
1607
1608     /* Update vmod -> indicator maps. */
1609     for (led = 0; led < XkbNumIndicators; led++)
1610         ComputeEffectiveMask(keymap, &keymap->indicators[led].mods);
1611
1612     return true;
1613 }