indicators.c revision a57d84fe
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, 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                    WARN("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 && (warningLevel > 0))
137            {
138                WARN("Map for indicator %s redefined\n",
139                      XkbAtomText(NULL, old->name, XkbMessage));
140                ACTION("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        ACTION("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
167static 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};
184static 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
200int
201SetIndicatorMapField(LEDInfo * led,
202                     XkbDescPtr xkb,
203                     const 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            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,
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            ERROR
354                ("Cannot set defaults for \"%s\" element in indicator map\n",
355                 elem.str);
356            ACTION("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
373Bool
374CopyIndicatorMapDefs(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
443Bool
444BindIndicators(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                        ACTION
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                ERROR("Multiple names bound to indicator %d\n",
522                       (unsigned int) led->indicator);
523                ACTION("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}
576