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
47void
48ClearIndicatorMapInfo(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
59LEDInfo *
60AddIndicatorMap(LEDInfo *oldLEDs, const LEDInfo *new)
61{
62    LEDInfo *old, *last;
63
64    last = NULL;
65    for (old = oldLEDs; old != NULL; old = (LEDInfo *) old->defs.next)
66    {
67        if (old->name == new->name)
68        {
69            unsigned collide;
70
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            {
78                old->defs.defined |= new->defs.defined;
79                return oldLEDs;
80            }
81            if (new->defs.merge == MergeReplace)
82            {
83                CommonInfo *next = old->defs.next;
84                if (((old->defs.fileID == new->defs.fileID)
85                     && (warningLevel > 0)) || (warningLevel > 9))
86                {
87                    WARN("Map for indicator %s redefined\n",
88                          XkbAtomText(NULL, old->name, XkbMessage));
89                    ACTION("Earlier definition ignored\n");
90                }
91                *old = *new;
92                old->defs.next = next;
93                return oldLEDs;
94            }
95            collide = 0;
96            if (UseNewField(_LED_Index, &old->defs, &new->defs, &collide))
97            {
98                old->indicator = new->indicator;
99                old->defs.defined |= _LED_Index;
100            }
101            if (UseNewField(_LED_Mods, &old->defs, &new->defs, &collide))
102            {
103                old->which_mods = new->which_mods;
104                old->real_mods = new->real_mods;
105                old->vmods = new->vmods;
106                old->defs.defined |= _LED_Mods;
107            }
108            if (UseNewField(_LED_Groups, &old->defs, &new->defs, &collide))
109            {
110                old->which_groups = new->which_groups;
111                old->groups = new->groups;
112                old->defs.defined |= _LED_Groups;
113            }
114            if (UseNewField(_LED_Ctrls, &old->defs, &new->defs, &collide))
115            {
116                old->ctrls = new->ctrls;
117                old->defs.defined |= _LED_Ctrls;
118            }
119            if (UseNewField(_LED_Explicit, &old->defs, &new->defs, &collide))
120            {
121                old->flags &= ~XkbIM_NoExplicit;
122                old->flags |= (new->flags & XkbIM_NoExplicit);
123                old->defs.defined |= _LED_Explicit;
124            }
125            if (UseNewField(_LED_Automatic, &old->defs, &new->defs, &collide))
126            {
127                old->flags &= ~XkbIM_NoAutomatic;
128                old->flags |= (new->flags & XkbIM_NoAutomatic);
129                old->defs.defined |= _LED_Automatic;
130            }
131            if (UseNewField(_LED_DrivesKbd, &old->defs, &new->defs, &collide))
132            {
133                old->flags &= ~XkbIM_LEDDrivesKB;
134                old->flags |= (new->flags & XkbIM_LEDDrivesKB);
135                old->defs.defined |= _LED_DrivesKbd;
136            }
137            if (collide && (warningLevel > 0))
138            {
139                WARN("Map for indicator %s redefined\n",
140                      XkbAtomText(NULL, old->name, XkbMessage));
141                ACTION("Using %s definition for duplicate fields\n",
142                        (new->defs.merge == MergeAugment ? "first" : "last"));
143            }
144            return oldLEDs;
145        }
146        if (old->defs.next == NULL)
147            last = old;
148    }
149    /* new definition */
150    old = malloc(sizeof(LEDInfo));
151    if (!old)
152    {
153        WSGO("Couldn't allocate indicator map\n");
154        ACTION("Map for indicator %s not compiled\n",
155                XkbAtomText(NULL, new->name, XkbMessage));
156        return NULL;
157    }
158    *old = *new;
159    old->defs.next = NULL;
160    if (last)
161    {
162        last->defs.next = &old->defs;
163        return oldLEDs;
164    }
165    return old;
166}
167
168static LookupEntry modComponentNames[] = {
169    {"base", XkbIM_UseBase}
170    ,
171    {"latched", XkbIM_UseLatched}
172    ,
173    {"locked", XkbIM_UseLocked}
174    ,
175    {"effective", XkbIM_UseEffective}
176    ,
177    {"compat", XkbIM_UseCompat}
178    ,
179    {"any", XkbIM_UseAnyMods}
180    ,
181    {"none", 0}
182    ,
183    {NULL, 0}
184};
185static LookupEntry groupComponentNames[] = {
186    {"base", XkbIM_UseBase}
187    ,
188    {"latched", XkbIM_UseLatched}
189    ,
190    {"locked", XkbIM_UseLocked}
191    ,
192    {"effective", XkbIM_UseEffective}
193    ,
194    {"any", XkbIM_UseAnyGroup}
195    ,
196    {"none", 0}
197    ,
198    {NULL, 0}
199};
200
201int
202SetIndicatorMapField(LEDInfo *led, XkbDescPtr xkb, const char *field,
203                     const ExprDef *arrayNdx, const 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            ERROR("Illegal indicator index %d (range 1..%d)\n",
307                   rtrn.uval, XkbNumIndicators);
308            ACTION("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        ERROR("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
325LEDInfo *
326HandleIndicatorMapDef(IndicatorMapDef *def, XkbDescPtr xkb,
327                      const LEDInfo *dflt, LEDInfo *oldLEDs, unsigned merge)
328{
329    LEDInfo led;
330    Bool ok;
331
332    if (def->merge != MergeDefault)
333        merge = def->merge;
334
335    led = *dflt;
336    led.defs.merge = merge;
337    led.name = def->name;
338
339    ok = True;
340    for (VarDef *var = def->body; var != NULL;
341         var = (VarDef *) var->common.next)
342    {
343        ExprResult elem, field;
344        ExprDef *arrayNdx;
345        if (!ExprResolveLhs(var->name, &elem, &field, &arrayNdx))
346        {
347            ok = False;
348            continue;
349        }
350        if (elem.str != NULL)
351        {
352            ERROR
353                ("Cannot set defaults for \"%s\" element in indicator map\n",
354                 elem.str);
355            ACTION("Assignment to %s.%s ignored\n", elem.str, field.str);
356            ok = False;
357        }
358        else
359        {
360            ok = SetIndicatorMapField(&led, xkb, field.str, arrayNdx,
361                                      var->value) && ok;
362        }
363    }
364    if (ok)
365    {
366        LEDInfo *rtrn = AddIndicatorMap(oldLEDs, &led);
367        return rtrn;
368    }
369    return NULL;
370}
371
372Bool
373CopyIndicatorMapDefs(XkbFileInfo * result, LEDInfo * leds,
374                     LEDInfo ** unboundRtrn)
375{
376    LEDInfo *led, *next;
377    LEDInfo *unbound, *last;
378    XkbDescPtr xkb;
379
380    xkb = result->xkb;
381    if (XkbAllocNames(xkb, XkbIndicatorNamesMask, 0, 0) != Success)
382    {
383        WSGO("Couldn't allocate names\n");
384        ACTION("Indicator names may be incorrect\n");
385    }
386    if (XkbAllocIndicatorMaps(xkb) != Success)
387    {
388        WSGO("Can't allocate indicator maps\n");
389        ACTION("Indicator map definitions may be lost\n");
390        return False;
391    }
392    last = unbound = (unboundRtrn ? *unboundRtrn : NULL);
393    while ((last != NULL) && (last->defs.next != NULL))
394    {
395        last = (LEDInfo *) last->defs.next;
396    }
397    for (led = leds; led != NULL; led = next)
398    {
399        next = (LEDInfo *) led->defs.next;
400        if ((led->groups != 0) && (led->which_groups == 0))
401            led->which_groups = XkbIM_UseEffective;
402        if ((led->which_mods == 0) && ((led->real_mods) || (led->vmods)))
403            led->which_mods = XkbIM_UseEffective;
404        if ((led->indicator == _LED_NotBound) || (!xkb->indicators))
405        {
406            if (unboundRtrn != NULL)
407            {
408                led->defs.next = NULL;
409                if (last != NULL)
410                    last->defs.next = (CommonInfo *) led;
411                else
412                    unbound = led;
413                last = led;
414            }
415            else
416                free(led);
417        }
418        else
419        {
420            XkbIndicatorMapPtr im;
421            im = &xkb->indicators->maps[led->indicator - 1];
422            im->flags = led->flags;
423            im->which_groups = led->which_groups;
424            im->groups = led->groups;
425            im->which_mods = led->which_mods;
426            im->mods.mask = led->real_mods;
427            im->mods.real_mods = led->real_mods;
428            im->mods.vmods = led->vmods;
429            im->ctrls = led->ctrls;
430            if (xkb->names != NULL)
431                xkb->names->indicators[led->indicator - 1] = led->name;
432            free(led);
433        }
434    }
435    if (unboundRtrn != NULL)
436    {
437        *unboundRtrn = unbound;
438    }
439    return True;
440}
441
442Bool
443BindIndicators(XkbFileInfo * result,
444               Bool force, LEDInfo * unbound, LEDInfo ** unboundRtrn)
445{
446    XkbDescPtr xkb;
447    LEDInfo *led, *next, *last;
448
449    xkb = result->xkb;
450    if (xkb->names != NULL)
451    {
452        for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
453        {
454            if (led->indicator == _LED_NotBound)
455            {
456                for (int i = 0; i < XkbNumIndicators; i++)
457                {
458                    if (xkb->names->indicators[i] == led->name)
459                    {
460                        led->indicator = i + 1;
461                        break;
462                    }
463                }
464            }
465        }
466        if (force)
467        {
468            for (led = unbound; led != NULL; led = (LEDInfo *) led->defs.next)
469            {
470                if (led->indicator == _LED_NotBound)
471                {
472                    for (int i = 0; i < XkbNumIndicators; i++)
473                    {
474                        if (xkb->names->indicators[i] == None)
475                        {
476                            xkb->names->indicators[i] = led->name;
477                            led->indicator = i + 1;
478                            xkb->indicators->phys_indicators &= ~(1 << i);
479                            break;
480                        }
481                    }
482                    if (led->indicator == _LED_NotBound)
483                    {
484                        ERROR("No unnamed indicators found\n");
485                        ACTION
486                            ("Virtual indicator map \"%s\" not bound\n",
487                             XkbAtomGetString(xkb->dpy, led->name));
488                        continue;
489                    }
490                }
491            }
492        }
493    }
494    for (last = NULL, led = unbound; led != NULL; led = next)
495    {
496        next = (LEDInfo *) led->defs.next;
497        if (led->indicator == _LED_NotBound)
498        {
499            if (force)
500            {
501                unbound = next;
502                free(led);
503            }
504            else
505            {
506                if (last)
507                    last->defs.next = &led->defs;
508                else
509                    unbound = led;
510                last = led;
511            }
512        }
513        else
514        {
515            if ((xkb->names != NULL) &&
516                (xkb->names->indicators[led->indicator - 1] != led->name))
517            {
518                Atom old = xkb->names->indicators[led->indicator - 1];
519                ERROR("Multiple names bound to indicator %d\n",
520                       (unsigned int) led->indicator);
521                ACTION("Using %s, ignoring %s\n",
522                        XkbAtomGetString(xkb->dpy, old),
523                        XkbAtomGetString(xkb->dpy, led->name));
524                led->indicator = _LED_NotBound;
525                if (force)
526                {
527                    free(led);
528                    unbound = next;
529                }
530                else
531                {
532                    if (last)
533                        last->defs.next = &led->defs;
534                    else
535                        unbound = led;
536                    last = led;
537                }
538            }
539            else
540            {
541                XkbIndicatorMapPtr map;
542                map = &xkb->indicators->maps[led->indicator - 1];
543                map->flags = led->flags;
544                map->which_groups = led->which_groups;
545                map->groups = led->groups;
546                map->which_mods = led->which_mods;
547                map->mods.mask = led->real_mods;
548                map->mods.real_mods = led->real_mods;
549                map->mods.vmods = led->vmods;
550                map->ctrls = led->ctrls;
551                if (last)
552                    last->defs.next = &next->defs;
553                else
554                    unbound = next;
555                led->defs.next = NULL;
556                free(led);
557            }
558        }
559    }
560    if (unboundRtrn)
561    {
562        *unboundRtrn = unbound;
563    }
564    else if (unbound)
565    {
566        for (led = unbound; led != NULL; led = next)
567        {
568            next = (LEDInfo *) led->defs.next;
569            free(led);
570        }
571    }
572    return True;
573}
574