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