xkbInit.c revision 35c4bbdf
1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <xkb-config.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <ctype.h>
36#include <unistd.h>
37#include <math.h>
38#include <X11/X.h>
39#include <X11/Xproto.h>
40#include <X11/keysym.h>
41#include <X11/Xatom.h>
42#include "misc.h"
43#include "inputstr.h"
44#include "opaque.h"
45#include "property.h"
46#include "scrnintstr.h"
47#define	XKBSRV_NEED_FILE_FUNCS
48#include <xkbsrv.h>
49#include "xkbgeom.h"
50#include <X11/extensions/XKMformat.h>
51#include "xkbfile.h"
52#include "xkb.h"
53
54#define	CREATE_ATOM(s)	MakeAtom(s,sizeof(s)-1,1)
55
56#if defined(__alpha) || defined(__alpha__)
57#define	LED_COMPOSE	2
58#define LED_CAPS	3
59#define	LED_SCROLL	4
60#define	LED_NUM		5
61#define	PHYS_LEDS	0x1f
62#else
63#ifdef sun
64#define LED_NUM		1
65#define	LED_SCROLL	2
66#define	LED_COMPOSE	3
67#define LED_CAPS	4
68#define	PHYS_LEDS	0x0f
69#else
70#define	LED_CAPS	1
71#define	LED_NUM		2
72#define	LED_SCROLL	3
73#define	PHYS_LEDS	0x07
74#endif
75#endif
76
77#define	MAX_TOC	16
78typedef struct _SrvXkmInfo {
79    DeviceIntPtr dev;
80    FILE *file;
81    XkbDescPtr xkb;
82} SrvXkmInfo;
83
84/***====================================================================***/
85
86#ifndef XKB_DFLT_RULES_PROP
87#define	XKB_DFLT_RULES_PROP	TRUE
88#endif
89
90const char *XkbBaseDirectory = XKB_BASE_DIRECTORY;
91const char *XkbBinDirectory = XKB_BIN_DIRECTORY;
92static int XkbWantAccessX = 0;
93
94static char *XkbRulesDflt = NULL;
95static char *XkbModelDflt = NULL;
96static char *XkbLayoutDflt = NULL;
97static char *XkbVariantDflt = NULL;
98static char *XkbOptionsDflt = NULL;
99
100static char *XkbRulesUsed = NULL;
101static char *XkbModelUsed = NULL;
102static char *XkbLayoutUsed = NULL;
103static char *XkbVariantUsed = NULL;
104static char *XkbOptionsUsed = NULL;
105
106static XkbDescPtr xkb_cached_map = NULL;
107
108static Bool XkbWantRulesProp = XKB_DFLT_RULES_PROP;
109
110/***====================================================================***/
111
112/**
113 * Get the current default XKB rules.
114 * Caller must free the data in rmlvo.
115 */
116void
117XkbGetRulesDflts(XkbRMLVOSet * rmlvo)
118{
119    rmlvo->rules = strdup(XkbRulesDflt ? XkbRulesDflt : XKB_DFLT_RULES);
120    rmlvo->model = strdup(XkbModelDflt ? XkbModelDflt : XKB_DFLT_MODEL);
121    rmlvo->layout = strdup(XkbLayoutDflt ? XkbLayoutDflt : XKB_DFLT_LAYOUT);
122    rmlvo->variant = strdup(XkbVariantDflt ? XkbVariantDflt : XKB_DFLT_VARIANT);
123    rmlvo->options = strdup(XkbOptionsDflt ? XkbOptionsDflt : XKB_DFLT_OPTIONS);
124}
125
126void
127XkbFreeRMLVOSet(XkbRMLVOSet * rmlvo, Bool freeRMLVO)
128{
129    if (!rmlvo)
130        return;
131
132    free(rmlvo->rules);
133    free(rmlvo->model);
134    free(rmlvo->layout);
135    free(rmlvo->variant);
136    free(rmlvo->options);
137
138    if (freeRMLVO)
139        free(rmlvo);
140    else
141        memset(rmlvo, 0, sizeof(XkbRMLVOSet));
142}
143
144static Bool
145XkbWriteRulesProp(ClientPtr client, void *closure)
146{
147    int len, out;
148    Atom name;
149    char *pval;
150
151    len = (XkbRulesUsed ? strlen(XkbRulesUsed) : 0);
152    len += (XkbModelUsed ? strlen(XkbModelUsed) : 0);
153    len += (XkbLayoutUsed ? strlen(XkbLayoutUsed) : 0);
154    len += (XkbVariantUsed ? strlen(XkbVariantUsed) : 0);
155    len += (XkbOptionsUsed ? strlen(XkbOptionsUsed) : 0);
156    if (len < 1)
157        return TRUE;
158
159    len += 5;                   /* trailing NULs */
160
161    name =
162        MakeAtom(_XKB_RF_NAMES_PROP_ATOM, strlen(_XKB_RF_NAMES_PROP_ATOM), 1);
163    if (name == None) {
164        ErrorF("[xkb] Atom error: %s not created\n", _XKB_RF_NAMES_PROP_ATOM);
165        return TRUE;
166    }
167    pval = (char *) malloc(len);
168    if (!pval) {
169        ErrorF("[xkb] Allocation error: %s proprerty not created\n",
170               _XKB_RF_NAMES_PROP_ATOM);
171        return TRUE;
172    }
173    out = 0;
174    if (XkbRulesUsed) {
175        strcpy(&pval[out], XkbRulesUsed);
176        out += strlen(XkbRulesUsed);
177    }
178    pval[out++] = '\0';
179    if (XkbModelUsed) {
180        strcpy(&pval[out], XkbModelUsed);
181        out += strlen(XkbModelUsed);
182    }
183    pval[out++] = '\0';
184    if (XkbLayoutUsed) {
185        strcpy(&pval[out], XkbLayoutUsed);
186        out += strlen(XkbLayoutUsed);
187    }
188    pval[out++] = '\0';
189    if (XkbVariantUsed) {
190        strcpy(&pval[out], XkbVariantUsed);
191        out += strlen(XkbVariantUsed);
192    }
193    pval[out++] = '\0';
194    if (XkbOptionsUsed) {
195        strcpy(&pval[out], XkbOptionsUsed);
196        out += strlen(XkbOptionsUsed);
197    }
198    pval[out++] = '\0';
199    if (out != len) {
200        ErrorF("[xkb] Internal Error! bad size (%d!=%d) for _XKB_RULES_NAMES\n",
201               out, len);
202    }
203    dixChangeWindowProperty(serverClient, screenInfo.screens[0]->root, name,
204                            XA_STRING, 8, PropModeReplace, len, pval, TRUE);
205    free(pval);
206    return TRUE;
207}
208
209void
210XkbInitRules(XkbRMLVOSet *rmlvo,
211             const char *rules,
212             const char *model,
213             const char *layout,
214             const char *variant,
215             const char *options)
216{
217    rmlvo->rules = rules ? xnfstrdup(rules) : NULL;
218    rmlvo->model = model ? xnfstrdup(model) : NULL;
219    rmlvo->layout = layout ? xnfstrdup(layout) : NULL;
220    rmlvo->variant = variant ? xnfstrdup(variant) : NULL;
221    rmlvo->options = options ? xnfstrdup(options) : NULL;
222}
223
224static void
225XkbSetRulesUsed(XkbRMLVOSet * rmlvo)
226{
227    free(XkbRulesUsed);
228    XkbRulesUsed = (rmlvo->rules ? Xstrdup(rmlvo->rules) : NULL);
229    free(XkbModelUsed);
230    XkbModelUsed = (rmlvo->model ? Xstrdup(rmlvo->model) : NULL);
231    free(XkbLayoutUsed);
232    XkbLayoutUsed = (rmlvo->layout ? Xstrdup(rmlvo->layout) : NULL);
233    free(XkbVariantUsed);
234    XkbVariantUsed = (rmlvo->variant ? Xstrdup(rmlvo->variant) : NULL);
235    free(XkbOptionsUsed);
236    XkbOptionsUsed = (rmlvo->options ? Xstrdup(rmlvo->options) : NULL);
237    if (XkbWantRulesProp)
238        QueueWorkProc(XkbWriteRulesProp, NULL, NULL);
239    return;
240}
241
242void
243XkbSetRulesDflts(XkbRMLVOSet * rmlvo)
244{
245    if (rmlvo->rules) {
246        free(XkbRulesDflt);
247        XkbRulesDflt = Xstrdup(rmlvo->rules);
248    }
249    if (rmlvo->model) {
250        free(XkbModelDflt);
251        XkbModelDflt = Xstrdup(rmlvo->model);
252    }
253    if (rmlvo->layout) {
254        free(XkbLayoutDflt);
255        XkbLayoutDflt = Xstrdup(rmlvo->layout);
256    }
257    if (rmlvo->variant) {
258        free(XkbVariantDflt);
259        XkbVariantDflt = Xstrdup(rmlvo->variant);
260    }
261    if (rmlvo->options) {
262        free(XkbOptionsDflt);
263        XkbOptionsDflt = Xstrdup(rmlvo->options);
264    }
265    return;
266}
267
268void
269XkbDeleteRulesUsed(void)
270{
271    free(XkbRulesUsed);
272    XkbRulesUsed = NULL;
273    free(XkbModelUsed);
274    XkbModelUsed = NULL;
275    free(XkbLayoutUsed);
276    XkbLayoutUsed = NULL;
277    free(XkbVariantUsed);
278    XkbVariantUsed = NULL;
279    free(XkbOptionsUsed);
280    XkbOptionsUsed = NULL;
281}
282
283void
284XkbDeleteRulesDflts(void)
285{
286    free(XkbRulesDflt);
287    XkbRulesDflt = NULL;
288    free(XkbModelDflt);
289    XkbModelDflt = NULL;
290    free(XkbLayoutDflt);
291    XkbLayoutDflt = NULL;
292    free(XkbVariantDflt);
293    XkbVariantDflt = NULL;
294    free(XkbOptionsDflt);
295    XkbOptionsDflt = NULL;
296
297    XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE);
298    xkb_cached_map = NULL;
299}
300
301#define DIFFERS(a, b) (strcmp((a) ? (a) : "", (b) ? (b) : "") != 0)
302
303static Bool
304XkbCompareUsedRMLVO(XkbRMLVOSet * rmlvo)
305{
306    if (DIFFERS(rmlvo->rules, XkbRulesUsed) ||
307        DIFFERS(rmlvo->model, XkbModelUsed) ||
308        DIFFERS(rmlvo->layout, XkbLayoutUsed) ||
309        DIFFERS(rmlvo->variant, XkbVariantUsed) ||
310        DIFFERS(rmlvo->options, XkbOptionsUsed))
311        return FALSE;
312    return TRUE;
313}
314
315#undef DIFFERS
316
317/***====================================================================***/
318
319#include "xkbDflts.h"
320
321static Bool
322XkbInitKeyTypes(XkbDescPtr xkb)
323{
324    if (xkb->defined & XkmTypesMask)
325        return TRUE;
326
327    initTypeNames(NULL);
328    if (XkbAllocClientMap(xkb, XkbKeyTypesMask, num_dflt_types) != Success)
329        return FALSE;
330    if (XkbCopyKeyTypes(dflt_types, xkb->map->types, num_dflt_types) != Success) {
331        return FALSE;
332    }
333    xkb->map->size_types = xkb->map->num_types = num_dflt_types;
334    return TRUE;
335}
336
337static void
338XkbInitRadioGroups(XkbSrvInfoPtr xkbi)
339{
340    xkbi->nRadioGroups = 0;
341    xkbi->radioGroups = NULL;
342    return;
343}
344
345static Status
346XkbInitCompatStructs(XkbDescPtr xkb)
347{
348    register int i;
349    XkbCompatMapPtr compat;
350
351    if (xkb->defined & XkmCompatMapMask)
352        return TRUE;
353
354    if (XkbAllocCompatMap(xkb, XkbAllCompatMask, num_dfltSI) != Success)
355        return BadAlloc;
356    compat = xkb->compat;
357    if (compat->sym_interpret) {
358        compat->num_si = num_dfltSI;
359        memcpy((char *) compat->sym_interpret, (char *) dfltSI, sizeof(dfltSI));
360    }
361    for (i = 0; i < XkbNumKbdGroups; i++) {
362        compat->groups[i] = compatMap.groups[i];
363        if (compat->groups[i].vmods != 0) {
364            unsigned mask;
365
366            mask = XkbMaskForVMask(xkb, compat->groups[i].vmods);
367            compat->groups[i].mask = compat->groups[i].real_mods | mask;
368        }
369        else
370            compat->groups[i].mask = compat->groups[i].real_mods;
371    }
372    return Success;
373}
374
375static void
376XkbInitSemantics(XkbDescPtr xkb)
377{
378    XkbInitKeyTypes(xkb);
379    XkbInitCompatStructs(xkb);
380    return;
381}
382
383/***====================================================================***/
384
385static Status
386XkbInitNames(XkbSrvInfoPtr xkbi)
387{
388    XkbDescPtr xkb;
389    XkbNamesPtr names;
390    Status rtrn;
391    Atom unknown;
392
393    xkb = xkbi->desc;
394    if ((rtrn = XkbAllocNames(xkb, XkbAllNamesMask, 0, 0)) != Success)
395        return rtrn;
396    unknown = CREATE_ATOM("unknown");
397    names = xkb->names;
398    if (names->keycodes == None)
399        names->keycodes = unknown;
400    if (names->geometry == None)
401        names->geometry = unknown;
402    if (names->phys_symbols == None)
403        names->phys_symbols = unknown;
404    if (names->symbols == None)
405        names->symbols = unknown;
406    if (names->types == None)
407        names->types = unknown;
408    if (names->compat == None)
409        names->compat = unknown;
410    if (!(xkb->defined & XkmVirtualModsMask)) {
411        if (names->vmods[vmod_NumLock] == None)
412            names->vmods[vmod_NumLock] = CREATE_ATOM("NumLock");
413        if (names->vmods[vmod_Alt] == None)
414            names->vmods[vmod_Alt] = CREATE_ATOM("Alt");
415        if (names->vmods[vmod_AltGr] == None)
416            names->vmods[vmod_AltGr] = CREATE_ATOM("ModeSwitch");
417    }
418
419    if (!(xkb->defined & XkmIndicatorsMask) ||
420        !(xkb->defined & XkmGeometryMask)) {
421        initIndicatorNames(NULL, xkb);
422        if (names->indicators[LED_CAPS - 1] == None)
423            names->indicators[LED_CAPS - 1] = CREATE_ATOM("Caps Lock");
424        if (names->indicators[LED_NUM - 1] == None)
425            names->indicators[LED_NUM - 1] = CREATE_ATOM("Num Lock");
426        if (names->indicators[LED_SCROLL - 1] == None)
427            names->indicators[LED_SCROLL - 1] = CREATE_ATOM("Scroll Lock");
428#ifdef LED_COMPOSE
429        if (names->indicators[LED_COMPOSE - 1] == None)
430            names->indicators[LED_COMPOSE - 1] = CREATE_ATOM("Compose");
431#endif
432    }
433
434    if (xkb->geom != NULL)
435        names->geometry = xkb->geom->name;
436    else
437        names->geometry = unknown;
438
439    return Success;
440}
441
442static Status
443XkbInitIndicatorMap(XkbSrvInfoPtr xkbi)
444{
445    XkbDescPtr xkb;
446    XkbIndicatorPtr map;
447    XkbSrvLedInfoPtr sli;
448
449    xkb = xkbi->desc;
450    if (XkbAllocIndicatorMaps(xkb) != Success)
451        return BadAlloc;
452
453    if (!(xkb->defined & XkmIndicatorsMask)) {
454        map = xkb->indicators;
455        map->phys_indicators = PHYS_LEDS;
456        map->maps[LED_CAPS - 1].flags = XkbIM_NoExplicit;
457        map->maps[LED_CAPS - 1].which_mods = XkbIM_UseLocked;
458        map->maps[LED_CAPS - 1].mods.mask = LockMask;
459        map->maps[LED_CAPS - 1].mods.real_mods = LockMask;
460
461        map->maps[LED_NUM - 1].flags = XkbIM_NoExplicit;
462        map->maps[LED_NUM - 1].which_mods = XkbIM_UseLocked;
463        map->maps[LED_NUM - 1].mods.mask = 0;
464        map->maps[LED_NUM - 1].mods.real_mods = 0;
465        map->maps[LED_NUM - 1].mods.vmods = vmod_NumLockMask;
466
467        map->maps[LED_SCROLL - 1].flags = XkbIM_NoExplicit;
468        map->maps[LED_SCROLL - 1].which_mods = XkbIM_UseLocked;
469        map->maps[LED_SCROLL - 1].mods.mask = Mod3Mask;
470        map->maps[LED_SCROLL - 1].mods.real_mods = Mod3Mask;
471    }
472
473    sli = XkbFindSrvLedInfo(xkbi->device, XkbDfltXIClass, XkbDfltXIId, 0);
474    if (sli)
475        XkbCheckIndicatorMaps(xkbi->device, sli, XkbAllIndicatorsMask);
476
477    return Success;
478}
479
480static Status
481XkbInitControls(DeviceIntPtr pXDev, XkbSrvInfoPtr xkbi)
482{
483    XkbDescPtr xkb;
484    XkbControlsPtr ctrls;
485
486    xkb = xkbi->desc;
487    /* 12/31/94 (ef) -- XXX! Should check if controls loaded from file */
488    if (XkbAllocControls(xkb, XkbAllControlsMask) != Success)
489        FatalError("Couldn't allocate keyboard controls\n");
490    ctrls = xkb->ctrls;
491    if (!(xkb->defined & XkmSymbolsMask))
492        ctrls->num_groups = 1;
493    ctrls->groups_wrap = XkbSetGroupInfo(1, XkbWrapIntoRange, 0);
494    ctrls->internal.mask = 0;
495    ctrls->internal.real_mods = 0;
496    ctrls->internal.vmods = 0;
497    ctrls->ignore_lock.mask = 0;
498    ctrls->ignore_lock.real_mods = 0;
499    ctrls->ignore_lock.vmods = 0;
500    ctrls->enabled_ctrls = XkbAccessXTimeoutMask | XkbRepeatKeysMask |
501        XkbMouseKeysAccelMask | XkbAudibleBellMask | XkbIgnoreGroupLockMask;
502    if (XkbWantAccessX)
503        ctrls->enabled_ctrls |= XkbAccessXKeysMask;
504    AccessXInit(pXDev);
505    return Success;
506}
507
508static Bool
509InitKeyboardDeviceStructInternal(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
510                                 const char *keymap, int keymap_length,
511                                 BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
512{
513    int i;
514    unsigned int check;
515    XkbSrvInfoPtr xkbi;
516    XkbDescPtr xkb;
517    XkbSrvLedInfoPtr sli;
518    XkbChangesRec changes;
519    XkbEventCauseRec cause;
520    XkbRMLVOSet rmlvo_dflts = { NULL };
521
522    BUG_RETURN_VAL(dev == NULL, FALSE);
523    BUG_RETURN_VAL(dev->key != NULL, FALSE);
524    BUG_RETURN_VAL(dev->kbdfeed != NULL, FALSE);
525    BUG_RETURN_VAL(rmlvo && keymap, FALSE);
526
527    if (!rmlvo && !keymap) {
528        rmlvo = &rmlvo_dflts;
529        XkbGetRulesDflts(rmlvo);
530    }
531
532    memset(&changes, 0, sizeof(changes));
533    XkbSetCauseUnknown(&cause);
534
535    dev->key = calloc(1, sizeof(*dev->key));
536    if (!dev->key) {
537        ErrorF("XKB: Failed to allocate key class\n");
538        return FALSE;
539    }
540    dev->key->sourceid = dev->id;
541
542    dev->kbdfeed = calloc(1, sizeof(*dev->kbdfeed));
543    if (!dev->kbdfeed) {
544        ErrorF("XKB: Failed to allocate key feedback class\n");
545        goto unwind_key;
546    }
547
548    xkbi = calloc(1, sizeof(*xkbi));
549    if (!xkbi) {
550        ErrorF("XKB: Failed to allocate XKB info\n");
551        goto unwind_kbdfeed;
552    }
553    dev->key->xkbInfo = xkbi;
554
555    if (xkb_cached_map && (keymap || (rmlvo && !XkbCompareUsedRMLVO(rmlvo)))) {
556        XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE);
557        xkb_cached_map = NULL;
558    }
559
560    if (xkb_cached_map)
561        LogMessageVerb(X_INFO, 4, "XKB: Reusing cached keymap\n");
562    else {
563        if (rmlvo)
564            xkb_cached_map = XkbCompileKeymap(dev, rmlvo);
565        else
566            xkb_cached_map = XkbCompileKeymapFromString(dev, keymap, keymap_length);
567
568        if (!xkb_cached_map) {
569            ErrorF("XKB: Failed to compile keymap\n");
570            goto unwind_info;
571        }
572    }
573
574    xkb = XkbAllocKeyboard();
575    if (!xkb) {
576        ErrorF("XKB: Failed to allocate keyboard description\n");
577        goto unwind_info;
578    }
579
580    if (!XkbCopyKeymap(xkb, xkb_cached_map)) {
581        ErrorF("XKB: Failed to copy keymap\n");
582        goto unwind_desc;
583    }
584    xkb->defined = xkb_cached_map->defined;
585    xkb->flags = xkb_cached_map->flags;
586    xkb->device_spec = xkb_cached_map->device_spec;
587    xkbi->desc = xkb;
588
589    if (xkb->min_key_code == 0)
590        xkb->min_key_code = 8;
591    if (xkb->max_key_code == 0)
592        xkb->max_key_code = 255;
593
594    i = XkbNumKeys(xkb) / 3 + 1;
595    if (XkbAllocClientMap(xkb, XkbAllClientInfoMask, 0) != Success)
596        goto unwind_desc;
597    if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, i) != Success)
598        goto unwind_desc;
599
600    xkbi->dfltPtrDelta = 1;
601    xkbi->device = dev;
602
603    XkbInitSemantics(xkb);
604    XkbInitNames(xkbi);
605    XkbInitRadioGroups(xkbi);
606
607    XkbInitControls(dev, xkbi);
608
609    XkbInitIndicatorMap(xkbi);
610
611    XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &changes,
612                     &check, &cause);
613
614    if (!dev->focus)
615        InitFocusClassDeviceStruct(dev);
616
617    xkbi->kbdProc = ctrl_func;
618    dev->kbdfeed->BellProc = bell_func;
619    dev->kbdfeed->CtrlProc = XkbDDXKeybdCtrlProc;
620
621    dev->kbdfeed->ctrl = defaultKeyboardControl;
622    if (dev->kbdfeed->ctrl.autoRepeat)
623        xkb->ctrls->enabled_ctrls |= XkbRepeatKeysMask;
624
625    memcpy(dev->kbdfeed->ctrl.autoRepeats, xkb->ctrls->per_key_repeat,
626           XkbPerKeyBitArraySize);
627
628    sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
629    if (sli)
630        XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask);
631    else
632        DebugF("XKB: No indicator feedback in XkbFinishInit!\n");
633
634    dev->kbdfeed->CtrlProc(dev, &dev->kbdfeed->ctrl);
635
636    if (rmlvo) {
637        XkbSetRulesDflts(rmlvo);
638        XkbSetRulesUsed(rmlvo);
639    }
640    XkbFreeRMLVOSet(&rmlvo_dflts, FALSE);
641
642    return TRUE;
643
644 unwind_desc:
645    XkbFreeKeyboard(xkb, 0, TRUE);
646 unwind_info:
647    free(xkbi);
648    dev->key->xkbInfo = NULL;
649 unwind_kbdfeed:
650    free(dev->kbdfeed);
651    dev->kbdfeed = NULL;
652 unwind_key:
653    free(dev->key);
654    dev->key = NULL;
655    return FALSE;
656}
657
658_X_EXPORT Bool
659InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
660                         BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
661{
662    return InitKeyboardDeviceStructInternal(dev, rmlvo,
663                                            NULL, 0, bell_func, ctrl_func);
664}
665
666_X_EXPORT Bool
667InitKeyboardDeviceStructFromString(DeviceIntPtr dev,
668                                   const char *keymap, int keymap_length,
669                                   BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
670{
671    return InitKeyboardDeviceStructInternal(dev, NULL,
672                                            keymap, keymap_length,
673                                            bell_func, ctrl_func);
674}
675
676/***====================================================================***/
677
678        /*
679         * Be very careful about what does and doesn't get freed by this
680         * function.  To reduce fragmentation, XkbInitDevice allocates a
681         * single huge block per device and divides it up into most of the
682         * fixed-size structures for the device.   Don't free anything that
683         * is part of this larger block.
684         */
685void
686XkbFreeInfo(XkbSrvInfoPtr xkbi)
687{
688    free(xkbi->radioGroups);
689    xkbi->radioGroups = NULL;
690    if (xkbi->mouseKeyTimer) {
691        TimerFree(xkbi->mouseKeyTimer);
692        xkbi->mouseKeyTimer = NULL;
693    }
694    if (xkbi->slowKeysTimer) {
695        TimerFree(xkbi->slowKeysTimer);
696        xkbi->slowKeysTimer = NULL;
697    }
698    if (xkbi->bounceKeysTimer) {
699        TimerFree(xkbi->bounceKeysTimer);
700        xkbi->bounceKeysTimer = NULL;
701    }
702    if (xkbi->repeatKeyTimer) {
703        TimerFree(xkbi->repeatKeyTimer);
704        xkbi->repeatKeyTimer = NULL;
705    }
706    if (xkbi->krgTimer) {
707        TimerFree(xkbi->krgTimer);
708        xkbi->krgTimer = NULL;
709    }
710    xkbi->beepType = _BEEP_NONE;
711    if (xkbi->beepTimer) {
712        TimerFree(xkbi->beepTimer);
713        xkbi->beepTimer = NULL;
714    }
715    if (xkbi->desc) {
716        XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, TRUE);
717        xkbi->desc = NULL;
718    }
719    free(xkbi);
720    return;
721}
722
723/***====================================================================***/
724
725extern int XkbDfltRepeatDelay;
726extern int XkbDfltRepeatInterval;
727
728extern unsigned short XkbDfltAccessXTimeout;
729extern unsigned int XkbDfltAccessXTimeoutMask;
730extern unsigned int XkbDfltAccessXFeedback;
731extern unsigned char XkbDfltAccessXOptions;
732
733int
734XkbProcessArguments(int argc, char *argv[], int i)
735{
736    if (strncmp(argv[i], "-xkbdir", 7) == 0) {
737        if (++i < argc) {
738#if !defined(WIN32) && !defined(__CYGWIN__)
739            if (getuid() != geteuid()) {
740                LogMessage(X_WARNING,
741                           "-xkbdir is not available for setuid X servers\n");
742                return -1;
743            }
744            else
745#endif
746            {
747                if (strlen(argv[i]) < PATH_MAX) {
748                    XkbBaseDirectory = argv[i];
749                    return 2;
750                }
751                else {
752                    LogMessage(X_ERROR, "-xkbdir pathname too long\n");
753                    return -1;
754                }
755            }
756        }
757        else {
758            return -1;
759        }
760    }
761    else if ((strncmp(argv[i], "-accessx", 8) == 0) ||
762             (strncmp(argv[i], "+accessx", 8) == 0)) {
763        int j = 1;
764
765        if (argv[i][0] == '-')
766            XkbWantAccessX = 0;
767        else {
768            XkbWantAccessX = 1;
769
770            if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
771                XkbDfltAccessXTimeout = atoi(argv[++i]);
772                j++;
773
774                if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
775                    /*
776                     * presumption that the reasonably useful range of
777                     * values fits in 0..MAXINT since SunOS 4 doesn't
778                     * have strtoul.
779                     */
780                    XkbDfltAccessXTimeoutMask = (unsigned int)
781                        strtol(argv[++i], NULL, 16);
782                    j++;
783                }
784                if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
785                    if (argv[++i][0] == '1')
786                        XkbDfltAccessXFeedback = XkbAccessXFeedbackMask;
787                    else
788                        XkbDfltAccessXFeedback = 0;
789                    j++;
790                }
791                if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
792                    XkbDfltAccessXOptions = (unsigned char)
793                        strtol(argv[++i], NULL, 16);
794                    j++;
795                }
796            }
797        }
798        return j;
799    }
800    if ((strcmp(argv[i], "-ardelay") == 0) || (strcmp(argv[i], "-ar1") == 0)) { /* -ardelay int */
801        if (++i >= argc)
802            UseMsg();
803        else
804            XkbDfltRepeatDelay = (long) atoi(argv[i]);
805        return 2;
806    }
807    if ((strcmp(argv[i], "-arinterval") == 0) || (strcmp(argv[i], "-ar2") == 0)) {      /* -arinterval int */
808        if (++i >= argc)
809            UseMsg();
810        else
811            XkbDfltRepeatInterval = (long) atoi(argv[i]);
812        return 2;
813    }
814    return 0;
815}
816
817void
818XkbUseMsg(void)
819{
820    ErrorF
821        ("[+-]accessx [ timeout [ timeout_mask [ feedback [ options_mask] ] ] ]\n");
822    ErrorF("                       enable/disable accessx key sequences\n");
823    ErrorF("-ardelay               set XKB autorepeat delay\n");
824    ErrorF("-arinterval            set XKB autorepeat interval\n");
825}
826