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