c7f0958d431ebb2cdd9c74b17cb55b8aeaab062c
[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_context *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         if (old->name == new->name) {
62             if ((old->real_mods == new->real_mods) &&
63                 (old->vmods == new->vmods) &&
64                 (old->groups == new->groups) &&
65                 (old->ctrls == new->ctrls) &&
66                 (old->which_mods == new->which_mods) &&
67                 (old->which_groups == new->which_groups)) {
68                 old->defs.defined |= new->defs.defined;
69                 return oldLEDs;
70             }
71             if (new->defs.merge == MERGE_REPLACE) {
72                 CommonInfo *next = old->defs.next;
73                 if (((old->defs.file_id == new->defs.file_id)
74                      && (warningLevel > 0)) || (warningLevel > 9)) {
75                     WARN("Map for indicator %s redefined\n",
76                          xkb_atom_text(keymap->ctx, old->name));
77                     ACTION("Earlier definition ignored\n");
78                 }
79                 *old = *new;
80                 old->defs.next = next;
81                 return oldLEDs;
82             }
83             collide = 0;
84             if (UseNewField(_LED_Index, &old->defs, &new->defs, &collide)) {
85                 old->indicator = new->indicator;
86                 old->defs.defined |= _LED_Index;
87             }
88             if (UseNewField(_LED_Mods, &old->defs, &new->defs, &collide)) {
89                 old->which_mods = new->which_mods;
90                 old->real_mods = new->real_mods;
91                 old->vmods = new->vmods;
92                 old->defs.defined |= _LED_Mods;
93             }
94             if (UseNewField(_LED_Groups, &old->defs, &new->defs, &collide)) {
95                 old->which_groups = new->which_groups;
96                 old->groups = new->groups;
97                 old->defs.defined |= _LED_Groups;
98             }
99             if (UseNewField(_LED_Ctrls, &old->defs, &new->defs, &collide)) {
100                 old->ctrls = new->ctrls;
101                 old->defs.defined |= _LED_Ctrls;
102             }
103             if (UseNewField(_LED_Explicit, &old->defs, &new->defs,
104                             &collide)) {
105                 old->flags &= ~XkbIM_NoExplicit;
106                 old->flags |= (new->flags & XkbIM_NoExplicit);
107                 old->defs.defined |= _LED_Explicit;
108             }
109             if (UseNewField(_LED_Automatic, &old->defs, &new->defs,
110                             &collide)) {
111                 old->flags &= ~XkbIM_NoAutomatic;
112                 old->flags |= (new->flags & XkbIM_NoAutomatic);
113                 old->defs.defined |= _LED_Automatic;
114             }
115             if (UseNewField(_LED_DrivesKbd, &old->defs, &new->defs,
116                             &collide)) {
117                 old->flags &= ~XkbIM_LEDDrivesKB;
118                 old->flags |= (new->flags & XkbIM_LEDDrivesKB);
119                 old->defs.defined |= _LED_DrivesKbd;
120             }
121             if (collide) {
122                 WARN("Map for indicator %s redefined\n",
123                      xkb_atom_text(keymap->ctx, old->name));
124                 ACTION("Using %s definition for duplicate fields\n",
125                        (new->defs.merge == MERGE_AUGMENT ? "first" : "last"));
126             }
127             return oldLEDs;
128         }
129         if (old->defs.next == NULL)
130             last = old;
131     }
132     /* new definition */
133     old = uTypedAlloc(LEDInfo);
134     if (!old) {
135         WSGO("Couldn't allocate indicator map\n");
136         ACTION("Map for indicator %s not compiled\n",
137                xkb_atom_text(keymap->ctx, new->name));
138         return NULL;
139     }
140     *old = *new;
141     old->defs.next = NULL;
142     if (last) {
143         last->defs.next = &old->defs;
144         return oldLEDs;
145     }
146     return old;
147 }
148
149 static const LookupEntry modComponentNames[] = {
150     { "base", XkbIM_UseBase },
151     { "latched", XkbIM_UseLatched },
152     { "locked", XkbIM_UseLocked },
153     { "effective", XkbIM_UseEffective },
154     { "compat", XkbIM_UseCompat },
155     { "any", XkbIM_UseAnyMods },
156     { "none", 0 },
157     { NULL, 0 }
158 };
159 static const LookupEntry groupComponentNames[] = {
160     { "base", XkbIM_UseBase },
161     { "latched", XkbIM_UseLatched },
162     { "locked", XkbIM_UseLocked },
163     { "effective", XkbIM_UseEffective },
164     { "any", XkbIM_UseAnyGroup },
165     { "none", 0 },
166     { NULL, 0 }
167 };
168
169 static const LookupEntry groupNames[] = {
170     { "group1", 0x01 },
171     { "group2", 0x02 },
172     { "group3", 0x04 },
173     { "group4", 0x08 },
174     { "group5", 0x10 },
175     { "group6", 0x20 },
176     { "group7", 0x40 },
177     { "group8", 0x80 },
178     { "none", 0x00 },
179     { "all", 0xff },
180     { NULL, 0 }
181 };
182
183 int
184 SetIndicatorMapField(LEDInfo *led, struct xkb_keymap *keymap,
185                      char *field, ExprDef *arrayNdx, ExprDef *value)
186 {
187     ExprResult rtrn;
188     bool ok;
189
190     ok = true;
191     if ((strcasecmp(field, "modifiers") == 0) ||
192         (strcasecmp(field, "mods") == 0)) {
193         if (arrayNdx != NULL)
194             return ReportIndicatorNotArray(keymap, led, field);
195         if (!ExprResolveVModMask(value, &rtrn, keymap))
196             return ReportIndicatorBadType(keymap, led, field, "modifier mask");
197         led->real_mods = rtrn.uval & 0xff;
198         led->vmods = (rtrn.uval >> 8) & 0xff;
199         led->defs.defined |= _LED_Mods;
200     }
201     else if (strcasecmp(field, "groups") == 0) {
202         if (arrayNdx != NULL)
203             return ReportIndicatorNotArray(keymap, led, field);
204         if (!ExprResolveMask(keymap->ctx, value, &rtrn, groupNames))
205             return ReportIndicatorBadType(keymap, led, field, "group mask");
206         led->groups = rtrn.uval;
207         led->defs.defined |= _LED_Groups;
208     }
209     else if ((strcasecmp(field, "controls") == 0) ||
210              (strcasecmp(field, "ctrls") == 0)) {
211         if (arrayNdx != NULL)
212             return ReportIndicatorNotArray(keymap, led, field);
213         if (!ExprResolveMask(keymap->ctx, value, &rtrn, ctrlNames))
214             return ReportIndicatorBadType(keymap, led, field,
215                                           "controls mask");
216         led->ctrls = rtrn.uval;
217         led->defs.defined |= _LED_Ctrls;
218     }
219     else if (strcasecmp(field, "allowexplicit") == 0) {
220         if (arrayNdx != NULL)
221             return ReportIndicatorNotArray(keymap, led, field);
222         if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
223             return ReportIndicatorBadType(keymap, led, field, "boolean");
224         if (rtrn.uval)
225             led->flags &= ~XkbIM_NoExplicit;
226         else
227             led->flags |= XkbIM_NoExplicit;
228         led->defs.defined |= _LED_Explicit;
229     }
230     else if ((strcasecmp(field, "whichmodstate") == 0) ||
231              (strcasecmp(field, "whichmodifierstate") == 0)) {
232         if (arrayNdx != NULL)
233             return ReportIndicatorNotArray(keymap, led, field);
234         if (!ExprResolveMask(keymap->ctx, value, &rtrn, modComponentNames)) {
235             return ReportIndicatorBadType(keymap, led, field,
236                                           "mask of modifier state components");
237         }
238         led->which_mods = rtrn.uval;
239     }
240     else if (strcasecmp(field, "whichgroupstate") == 0) {
241         if (arrayNdx != NULL)
242             return ReportIndicatorNotArray(keymap, led, field);
243         if (!ExprResolveMask(keymap->ctx, value, &rtrn,
244                              groupComponentNames)) {
245             return ReportIndicatorBadType(keymap, led, field,
246                                           "mask of group state components");
247         }
248         led->which_groups = rtrn.uval;
249     }
250     else if ((strcasecmp(field, "driveskbd") == 0) ||
251              (strcasecmp(field, "driveskeyboard") == 0) ||
252              (strcasecmp(field, "leddriveskbd") == 0) ||
253              (strcasecmp(field, "leddriveskeyboard") == 0) ||
254              (strcasecmp(field, "indicatordriveskbd") == 0) ||
255              (strcasecmp(field, "indicatordriveskeyboard") == 0)) {
256         if (arrayNdx != NULL)
257             return ReportIndicatorNotArray(keymap, led, field);
258         if (!ExprResolveBoolean(keymap->ctx, value, &rtrn))
259             return ReportIndicatorBadType(keymap, led, field, "boolean");
260         if (rtrn.uval)
261             led->flags |= XkbIM_LEDDrivesKB;
262         else
263             led->flags &= ~XkbIM_LEDDrivesKB;
264         led->defs.defined |= _LED_DrivesKbd;
265     }
266     else if (strcasecmp(field, "index") == 0) {
267         if (arrayNdx != NULL)
268             return ReportIndicatorNotArray(keymap, led, field);
269         if (!ExprResolveInteger(keymap->ctx, value, &rtrn))
270             return ReportIndicatorBadType(keymap, led, field,
271                                           "indicator index");
272         if ((rtrn.uval < 1) || (rtrn.uval > 32)) {
273             ERROR("Illegal indicator index %d (range 1..%d)\n",
274                   rtrn.uval, XkbNumIndicators);
275             ACTION("Index definition for %s indicator ignored\n",
276                    xkb_atom_text(keymap->ctx, led->name));
277             return false;
278         }
279         led->indicator = rtrn.uval;
280         led->defs.defined |= _LED_Index;
281     }
282     else {
283         ERROR("Unknown field %s in map for %s indicator\n", field,
284               xkb_atom_text(keymap->ctx, led->name));
285         ACTION("Definition ignored\n");
286         ok = false;
287     }
288     return ok;
289 }
290
291 LEDInfo *
292 HandleIndicatorMapDef(IndicatorMapDef *def, struct xkb_keymap *keymap,
293                       LEDInfo *dflt, LEDInfo *oldLEDs, enum merge_mode merge)
294 {
295     LEDInfo led, *rtrn;
296     VarDef *var;
297     bool ok;
298
299     if (def->merge != MERGE_DEFAULT)
300         merge = def->merge;
301
302     led = *dflt;
303     led.defs.merge = merge;
304     led.name = def->name;
305
306     ok = true;
307     for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
308         ExprResult elem, field;
309         ExprDef *arrayNdx;
310         if (!ExprResolveLhs(keymap, var->name, &elem, &field, &arrayNdx)) {
311             ok = false;
312             continue;
313         }
314         if (elem.str != NULL) {
315             ERROR
316                 ("Cannot set defaults for \"%s\" element in indicator map\n",
317                 elem.str);
318             ACTION("Assignment to %s.%s ignored\n", elem.str, field.str);
319             ok = false;
320         }
321         else {
322             ok = SetIndicatorMapField(&led, keymap, field.str, arrayNdx,
323                                       var->value) && ok;
324         }
325         free(elem.str);
326         free(field.str);
327     }
328     if (ok) {
329         rtrn = AddIndicatorMap(keymap, oldLEDs, &led);
330         return rtrn;
331     }
332     return NULL;
333 }
334
335 static void
336 BindIndicators(struct xkb_keymap *keymap, LEDInfo *unbound)
337 {
338     int i;
339     LEDInfo *led, *next, *last;
340
341     for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next) {
342         if (led->indicator == _LED_NotBound) {
343             for (i = 0; i < XkbNumIndicators; i++) {
344                 if (keymap->indicator_names[i] &&
345                     strcmp(keymap->indicator_names[i],
346                            xkb_atom_text(keymap->ctx, led->name)) == 0) {
347                     led->indicator = i + 1;
348                     break;
349                 }
350             }
351         }
352     }
353
354     for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next) {
355         if (led->indicator == _LED_NotBound) {
356             for (i = 0; i < XkbNumIndicators; i++) {
357                 if (keymap->indicator_names[i] == NULL) {
358                     keymap->indicator_names[i] =
359                         xkb_atom_strdup(keymap->ctx, led->name);
360                     led->indicator = i + 1;
361                     break;
362                 }
363             }
364             if (led->indicator == _LED_NotBound) {
365                 ERROR("No unnamed indicators found\n");
366                 ACTION("Virtual indicator map \"%s\" not bound\n",
367                        xkb_atom_text(keymap->ctx, led->name));
368                 continue;
369             }
370         }
371     }
372     for (last = NULL, led = unbound; led != NULL; led = next) {
373         next = (LEDInfo *) led->defs.next;
374         if (led->indicator == _LED_NotBound) {
375             unbound = next;
376             free(led);
377         }
378         else {
379             if (strcmp(keymap->indicator_names[led->indicator - 1],
380                        xkb_atom_text(keymap->ctx, led->name)) != 0) {
381                 const char *old = keymap->indicator_names[led->indicator - 1];
382                 ERROR("Multiple names bound to indicator %d\n",
383                       (unsigned int) led->indicator);
384                 ACTION("Using %s, ignoring %s\n", old,
385                        xkb_atom_text(keymap->ctx, led->name));
386                 led->indicator = _LED_NotBound;
387                 unbound = next;
388                 free(led);
389             }
390             else {
391                 struct xkb_indicator_map * map;
392                 map = &keymap->indicators[led->indicator - 1];
393                 map->flags = led->flags;
394                 map->which_groups = led->which_groups;
395                 map->groups = led->groups;
396                 map->which_mods = led->which_mods;
397                 map->mods.mask = led->real_mods;
398                 map->mods.real_mods = led->real_mods;
399                 map->mods.vmods = led->vmods;
400                 map->ctrls = led->ctrls;
401                 if (last)
402                     last->defs.next = &next->defs;
403                 else
404                     unbound = next;
405                 led->defs.next = NULL;
406                 free(led);
407             }
408         }
409     }
410
411     for (led = unbound; led != NULL; led = next) {
412         next = led ? (LEDInfo *) led->defs.next : NULL;
413         free(led);
414     }
415 }
416
417 bool
418 CopyIndicatorMapDefs(struct xkb_keymap *keymap, LEDInfo *leds)
419 {
420     LEDInfo *led, *next;
421     LEDInfo *unbound = NULL, *last = NULL;
422
423     for (led = leds; led != NULL; led = next) {
424         next = (LEDInfo *) led->defs.next;
425         if ((led->groups != 0) && (led->which_groups == 0))
426             led->which_groups = XkbIM_UseEffective;
427         if ((led->which_mods == 0) && ((led->real_mods) || (led->vmods)))
428             led->which_mods = XkbIM_UseEffective;
429         if ((led->indicator == _LED_NotBound) || (!keymap->indicators)) {
430             led->defs.next = NULL;
431             if (last != NULL)
432                 last->defs.next = (CommonInfo *) led;
433             else
434                 unbound = led;
435             last = led;
436         }
437         else {
438             struct xkb_indicator_map * im;
439             im = &keymap->indicators[led->indicator - 1];
440             im->flags = led->flags;
441             im->which_groups = led->which_groups;
442             im->groups = led->groups;
443             im->which_mods = led->which_mods;
444             im->mods.mask = led->real_mods;
445             im->mods.real_mods = led->real_mods;
446             im->mods.vmods = led->vmods;
447             im->ctrls = led->ctrls;
448             free(keymap->indicator_names[led->indicator - 1]);
449             keymap->indicator_names[led->indicator - 1] =
450                 xkb_atom_strdup(keymap->ctx, led->name);
451             free(led);
452         }
453     }
454
455     if (unbound)
456         BindIndicators(keymap, unbound);
457
458     return true;
459 }