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