4d76a2b7a89226c52b5ff0528d8b54faaa7141c8
[platform/upstream/libxkbcommon.git] / src / xkbcomp / indicators.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 "indicators.h"
28 #include "expr.h"
29 #include "action.h"
30
31 /***====================================================================***/
32
33 #define ReportIndicatorBadType(keymap, l, f, w)                            \
34     ReportBadType("indicator map", (f),                                 \
35                   xkb_atom_text((keymap)->ctx, (l)->name), (w))
36 #define ReportIndicatorNotArray(keymap, l, f)                              \
37     ReportNotArray("indicator map", (f),                                \
38                    xkb_atom_text((keymap)->ctx, (l)->name))
39
40 /***====================================================================***/
41
42 void
43 ClearIndicatorMapInfo(struct xkb_ctx *ctx, LEDInfo * info)
44 {
45     info->name = xkb_atom_intern(ctx, "default");
46     info->indicator = _LED_NotBound;
47     info->flags = info->which_mods = info->real_mods = 0;
48     info->vmods = 0;
49     info->which_groups = info->groups = 0;
50     info->ctrls = 0;
51 }
52
53 LEDInfo *
54 AddIndicatorMap(struct xkb_keymap *keymap, LEDInfo *oldLEDs, LEDInfo *new)
55 {
56     LEDInfo *old, *last;
57     unsigned collide;
58
59     last = NULL;
60     for (old = oldLEDs; old != NULL; old = (LEDInfo *) old->defs.next)
61     {
62         if (old->name == new->name)
63         {
64             if ((old->real_mods == new->real_mods) &&
65                 (old->vmods == new->vmods) &&
66                 (old->groups == new->groups) &&
67                 (old->ctrls == new->ctrls) &&
68                 (old->which_mods == new->which_mods) &&
69                 (old->which_groups == new->which_groups))
70             {
71                 old->defs.defined |= new->defs.defined;
72                 return oldLEDs;
73             }
74             if (new->defs.merge == MergeReplace)
75             {
76                 CommonInfo *next = old->defs.next;
77                 if (((old->defs.fileID == new->defs.fileID)
78                      && (warningLevel > 0)) || (warningLevel > 9))
79                 {
80                     WARN("Map for indicator %s redefined\n",
81                           xkb_atom_text(keymap->ctx, old->name));
82                     ACTION("Earlier definition ignored\n");
83                 }
84                 *old = *new;
85                 old->defs.next = next;
86                 return oldLEDs;
87             }
88             collide = 0;
89             if (UseNewField(_LED_Index, &old->defs, &new->defs, &collide))
90             {
91                 old->indicator = new->indicator;
92                 old->defs.defined |= _LED_Index;
93             }
94             if (UseNewField(_LED_Mods, &old->defs, &new->defs, &collide))
95             {
96                 old->which_mods = new->which_mods;
97                 old->real_mods = new->real_mods;
98                 old->vmods = new->vmods;
99                 old->defs.defined |= _LED_Mods;
100             }
101             if (UseNewField(_LED_Groups, &old->defs, &new->defs, &collide))
102             {
103                 old->which_groups = new->which_groups;
104                 old->groups = new->groups;
105                 old->defs.defined |= _LED_Groups;
106             }
107             if (UseNewField(_LED_Ctrls, &old->defs, &new->defs, &collide))
108             {
109                 old->ctrls = new->ctrls;
110                 old->defs.defined |= _LED_Ctrls;
111             }
112             if (UseNewField(_LED_Explicit, &old->defs, &new->defs, &collide))
113             {
114                 old->flags &= ~XkbIM_NoExplicit;
115                 old->flags |= (new->flags & XkbIM_NoExplicit);
116                 old->defs.defined |= _LED_Explicit;
117             }
118             if (UseNewField(_LED_Automatic, &old->defs, &new->defs, &collide))
119             {
120                 old->flags &= ~XkbIM_NoAutomatic;
121                 old->flags |= (new->flags & XkbIM_NoAutomatic);
122                 old->defs.defined |= _LED_Automatic;
123             }
124             if (UseNewField(_LED_DrivesKbd, &old->defs, &new->defs, &collide))
125             {
126                 old->flags &= ~XkbIM_LEDDrivesKB;
127                 old->flags |= (new->flags & XkbIM_LEDDrivesKB);
128                 old->defs.defined |= _LED_DrivesKbd;
129             }
130             if (collide)
131             {
132                 WARN("Map for indicator %s redefined\n",
133                      xkb_atom_text(keymap->ctx, old->name));
134                 ACTION("Using %s definition for duplicate fields\n",
135                         (new->defs.merge == MergeAugment ? "first" : "last"));
136             }
137             return oldLEDs;
138         }
139         if (old->defs.next == NULL)
140             last = old;
141     }
142     /* new definition */
143     old = uTypedAlloc(LEDInfo);
144     if (!old)
145     {
146         WSGO("Couldn't allocate indicator map\n");
147         ACTION("Map for indicator %s not compiled\n",
148                 xkb_atom_text(keymap->ctx, new->name));
149         return NULL;
150     }
151     *old = *new;
152     old->defs.next = NULL;
153     if (last)
154     {
155         last->defs.next = &old->defs;
156         return oldLEDs;
157     }
158     return old;
159 }
160
161 static const LookupEntry modComponentNames[] = {
162     {"base", XkbIM_UseBase},
163     {"latched", XkbIM_UseLatched},
164     {"locked", XkbIM_UseLocked},
165     {"effective", XkbIM_UseEffective},
166     {"compat", XkbIM_UseCompat},
167     {"any", XkbIM_UseAnyMods},
168     {"none", 0},
169     {NULL, 0}
170 };
171 static const LookupEntry groupComponentNames[] = {
172     {"base", XkbIM_UseBase},
173     {"latched", XkbIM_UseLatched},
174     {"locked", XkbIM_UseLocked},
175     {"effective", XkbIM_UseEffective},
176     {"any", XkbIM_UseAnyGroup},
177     {"none", 0},
178     {NULL, 0}
179 };
180
181 static const LookupEntry groupNames[] = {
182     {"group1", 0x01},
183     {"group2", 0x02},
184     {"group3", 0x04},
185     {"group4", 0x08},
186     {"group5", 0x10},
187     {"group6", 0x20},
188     {"group7", 0x40},
189     {"group8", 0x80},
190     {"none", 0x00},
191     {"all", 0xff},
192     {NULL, 0}
193 };
194
195 int
196 SetIndicatorMapField(LEDInfo *led, struct xkb_keymap *keymap,
197                      char *field, ExprDef *arrayNdx, ExprDef *value)
198 {
199     ExprResult rtrn;
200     bool ok;
201
202     ok = true;
203     if ((strcasecmp(field, "modifiers") == 0) ||
204         (strcasecmp(field, "mods") == 0))
205     {
206         if (arrayNdx != NULL)
207             return ReportIndicatorNotArray(keymap, led, field);
208         if (!ExprResolveVModMask(value, &rtrn, keymap))
209             return ReportIndicatorBadType(keymap, led, field, "modifier mask");
210         led->real_mods = rtrn.uval & 0xff;
211         led->vmods = (rtrn.uval >> 8) & 0xff;
212         led->defs.defined |= _LED_Mods;
213     }
214     else if (strcasecmp(field, "groups") == 0)
215     {
216         if (arrayNdx != NULL)
217             return ReportIndicatorNotArray(keymap, led, field);
218         if (!ExprResolveMask(keymap->ctx, value, &rtrn, groupNames))
219             return ReportIndicatorBadType(keymap, led, field, "group mask");
220         led->groups = rtrn.uval;
221         led->defs.defined |= _LED_Groups;
222     }
223     else if ((strcasecmp(field, "controls") == 0) ||
224              (strcasecmp(field, "ctrls") == 0))
225     {
226         if (arrayNdx != NULL)
227             return ReportIndicatorNotArray(keymap, led, field);
228         if (!ExprResolveMask(keymap->ctx, value, &rtrn, ctrlNames))
229             return ReportIndicatorBadType(keymap, led, field,
230                                           "controls mask");
231         led->ctrls = rtrn.uval;
232         led->defs.defined |= _LED_Ctrls;
233     }
234     else if (strcasecmp(field, "allowexplicit") == 0)
235     {
236         if (arrayNdx != NULL)
237             return ReportIndicatorNotArray(keymap, led, field);
238         if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
239             return ReportIndicatorBadType(keymap, led, field, "boolean");
240         if (rtrn.uval)
241             led->flags &= ~XkbIM_NoExplicit;
242         else
243             led->flags |= XkbIM_NoExplicit;
244         led->defs.defined |= _LED_Explicit;
245     }
246     else if ((strcasecmp(field, "whichmodstate") == 0) ||
247              (strcasecmp(field, "whichmodifierstate") == 0))
248     {
249         if (arrayNdx != NULL)
250             return ReportIndicatorNotArray(keymap, led, field);
251         if (!ExprResolveMask(keymap->ctx, value, &rtrn, modComponentNames))
252         {
253             return ReportIndicatorBadType(keymap, led, field,
254                                           "mask of modifier state components");
255         }
256         led->which_mods = rtrn.uval;
257     }
258     else if (strcasecmp(field, "whichgroupstate") == 0)
259     {
260         if (arrayNdx != NULL)
261             return ReportIndicatorNotArray(keymap, led, field);
262         if (!ExprResolveMask(keymap->ctx, value, &rtrn, groupComponentNames))
263         {
264             return ReportIndicatorBadType(keymap, led, field,
265                                           "mask of group state components");
266         }
267         led->which_groups = rtrn.uval;
268     }
269     else if ((strcasecmp(field, "driveskbd") == 0) ||
270              (strcasecmp(field, "driveskeyboard") == 0) ||
271              (strcasecmp(field, "leddriveskbd") == 0) ||
272              (strcasecmp(field, "leddriveskeyboard") == 0) ||
273              (strcasecmp(field, "indicatordriveskbd") == 0) ||
274              (strcasecmp(field, "indicatordriveskeyboard") == 0))
275     {
276         if (arrayNdx != NULL)
277             return ReportIndicatorNotArray(keymap, led, field);
278         if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
279             return ReportIndicatorBadType(keymap, led, field, "boolean");
280         if (rtrn.uval)
281             led->flags |= XkbIM_LEDDrivesKB;
282         else
283             led->flags &= ~XkbIM_LEDDrivesKB;
284         led->defs.defined |= _LED_DrivesKbd;
285     }
286     else if (strcasecmp(field, "index") == 0)
287     {
288         if (arrayNdx != NULL)
289             return ReportIndicatorNotArray(keymap, led, field);
290         if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
291             return ReportIndicatorBadType(keymap, led, field,
292                                           "indicator index");
293         if ((rtrn.uval < 1) || (rtrn.uval > 32))
294         {
295             ERROR("Illegal indicator index %d (range 1..%d)\n",
296                    rtrn.uval, XkbNumIndicators);
297             ACTION("Index definition for %s indicator ignored\n",
298                     xkb_atom_text(keymap->ctx, led->name));
299             return false;
300         }
301         led->indicator = rtrn.uval;
302         led->defs.defined |= _LED_Index;
303     }
304     else
305     {
306         ERROR("Unknown field %s in map for %s indicator\n", field,
307                xkb_atom_text(keymap->ctx, led->name));
308         ACTION("Definition ignored\n");
309         ok = false;
310     }
311     return ok;
312 }
313
314 LEDInfo *
315 HandleIndicatorMapDef(IndicatorMapDef *def, struct xkb_keymap *keymap,
316                       LEDInfo *dflt, LEDInfo *oldLEDs, unsigned merge)
317 {
318     LEDInfo led, *rtrn;
319     VarDef *var;
320     bool ok;
321
322     if (def->merge != MergeDefault)
323         merge = def->merge;
324
325     led = *dflt;
326     led.defs.merge = merge;
327     led.name = def->name;
328
329     ok = true;
330     for (var = def->body; var != NULL; var = (VarDef *) var->common.next)
331     {
332         ExprResult elem, field;
333         ExprDef *arrayNdx;
334         if (!ExprResolveLhs(keymap, var->name, &elem, &field, &arrayNdx))
335         {
336             ok = false;
337             continue;
338         }
339         if (elem.str != NULL)
340         {
341             ERROR
342                 ("Cannot set defaults for \"%s\" element in indicator map\n",
343                  elem.str);
344             ACTION("Assignment to %s.%s ignored\n", elem.str, field.str);
345             ok = false;
346         }
347         else
348         {
349             ok = SetIndicatorMapField(&led, keymap, field.str, arrayNdx,
350                                       var->value) && ok;
351         }
352         free(elem.str);
353         free(field.str);
354     }
355     if (ok)
356     {
357         rtrn = AddIndicatorMap(keymap, oldLEDs, &led);
358         return rtrn;
359     }
360     return NULL;
361 }
362
363 bool
364 CopyIndicatorMapDefs(struct xkb_keymap *keymap, LEDInfo *leds,
365                      LEDInfo **unboundRtrn)
366 {
367     LEDInfo *led, *next;
368     LEDInfo *unbound, *last;
369
370     if (XkbcAllocNames(keymap, XkbIndicatorNamesMask, 0) != Success)
371     {
372         WSGO("Couldn't allocate names\n");
373         ACTION("Indicator names may be incorrect\n");
374     }
375     if (XkbcAllocIndicatorMaps(keymap) != Success)
376     {
377         WSGO("Can't allocate indicator maps\n");
378         ACTION("Indicator map definitions may be lost\n");
379         return false;
380     }
381     last = unbound = (unboundRtrn ? *unboundRtrn : NULL);
382     while ((last != NULL) && (last->defs.next != NULL))
383     {
384         last = (LEDInfo *) last->defs.next;
385     }
386     for (led = leds; led != NULL; led = next)
387     {
388         next = (LEDInfo *) led->defs.next;
389         if ((led->groups != 0) && (led->which_groups == 0))
390             led->which_groups = XkbIM_UseEffective;
391         if ((led->which_mods == 0) && ((led->real_mods) || (led->vmods)))
392             led->which_mods = XkbIM_UseEffective;
393         if ((led->indicator == _LED_NotBound) || (!keymap->indicators))
394         {
395             if (unboundRtrn != NULL)
396             {
397                 led->defs.next = NULL;
398                 if (last != NULL)
399                     last->defs.next = (CommonInfo *) led;
400                 else
401                     unbound = led;
402                 last = led;
403             }
404             else
405                 free(led);
406         }
407         else
408         {
409             struct xkb_indicator_map * im;
410             im = &keymap->indicators->maps[led->indicator - 1];
411             im->flags = led->flags;
412             im->which_groups = led->which_groups;
413             im->groups = led->groups;
414             im->which_mods = led->which_mods;
415             im->mods.mask = led->real_mods;
416             im->mods.real_mods = led->real_mods;
417             im->mods.vmods = led->vmods;
418             im->ctrls = led->ctrls;
419             if (keymap->names != NULL)
420             {
421                 free(UNCONSTIFY(keymap->names->indicators[led->indicator - 1]));
422                 keymap->names->indicators[led->indicator-1] =
423                     xkb_atom_strdup(keymap->ctx, led->name);
424             }
425             free(led);
426         }
427     }
428     if (unboundRtrn != NULL)
429     {
430         *unboundRtrn = unbound;
431     }
432     return true;
433 }
434
435 bool
436 BindIndicators(struct xkb_keymap *keymap, bool force, LEDInfo *unbound,
437                LEDInfo **unboundRtrn)
438 {
439     int i;
440     LEDInfo *led, *next, *last;
441
442     if (keymap->names != NULL)
443     {
444         for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
445         {
446             if (led->indicator == _LED_NotBound)
447             {
448                 for (i = 0; i < XkbNumIndicators; i++)
449                 {
450                     if (keymap->names->indicators[i] &&
451                         strcmp(keymap->names->indicators[i],
452                                xkb_atom_text(keymap->ctx, led->name)) == 0)
453                     {
454                         led->indicator = i + 1;
455                         break;
456                     }
457                 }
458             }
459         }
460         if (force)
461         {
462             for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
463             {
464                 if (led->indicator == _LED_NotBound)
465                 {
466                     for (i = 0; i < XkbNumIndicators; i++)
467                     {
468                         if (keymap->names->indicators[i] == NULL)
469                         {
470                             keymap->names->indicators[i] =
471                                 xkb_atom_strdup(keymap->ctx, led->name);
472                             led->indicator = i + 1;
473                             break;
474                         }
475                     }
476                     if (led->indicator == _LED_NotBound)
477                     {
478                         ERROR("No unnamed indicators found\n");
479                         ACTION
480                             ("Virtual indicator map \"%s\" not bound\n",
481                              xkb_atom_text(keymap->ctx, led->name));
482                         continue;
483                     }
484                 }
485             }
486         }
487     }
488     for (last = NULL, led = unbound; led != NULL; led = next)
489     {
490         next = (LEDInfo *) led->defs.next;
491         if (led->indicator == _LED_NotBound)
492         {
493             if (force)
494             {
495                 unbound = next;
496                 free(led);
497             }
498             else
499             {
500                 if (last)
501                     last->defs.next = &led->defs;
502                 else
503                     unbound = led;
504                 last = led;
505             }
506         }
507         else
508         {
509             if ((keymap->names != NULL) &&
510                 (strcmp(keymap->names->indicators[led->indicator - 1],
511                         xkb_atom_text(keymap->ctx, led->name)) != 0))
512             {
513                 const char *old = keymap->names->indicators[led->indicator - 1];
514                 ERROR("Multiple names bound to indicator %d\n",
515                        (unsigned int) led->indicator);
516                 ACTION("Using %s, ignoring %s\n", old,
517                        xkb_atom_text(keymap->ctx, led->name));
518                 led->indicator = _LED_NotBound;
519                 if (force)
520                 {
521                     free(led);
522                     unbound = next;
523                 }
524                 else
525                 {
526                     if (last)
527                         last->defs.next = &led->defs;
528                     else
529                         unbound = led;
530                     last = led;
531                 }
532             }
533             else
534             {
535                 struct xkb_indicator_map * map;
536                 map = &keymap->indicators->maps[led->indicator - 1];
537                 map->flags = led->flags;
538                 map->which_groups = led->which_groups;
539                 map->groups = led->groups;
540                 map->which_mods = led->which_mods;
541                 map->mods.mask = led->real_mods;
542                 map->mods.real_mods = led->real_mods;
543                 map->mods.vmods = led->vmods;
544                 map->ctrls = led->ctrls;
545                 if (last)
546                     last->defs.next = &next->defs;
547                 else
548                     unbound = next;
549                 led->defs.next = NULL;
550                 free(led);
551             }
552         }
553     }
554     if (unboundRtrn)
555     {
556         *unboundRtrn = unbound;
557     }
558     else
559     {
560         for (led = unbound; led != NULL; led = next)
561         {
562             next = led ? (LEDInfo *) led->defs.next : NULL;
563             free(led);
564         }
565     }
566     return true;
567 }