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