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