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