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
87#ifndef XKB_DFLT_RULES_PROP
88#define	XKB_DFLT_RULES_PROP	TRUE
89#endif
90
91char	*		XkbBaseDirectory=	XKB_BASE_DIRECTORY;
92char	*		XkbBinDirectory=	XKB_BIN_DIRECTORY;
93static int	 	XkbWantAccessX=		0;
94
95static char *		XkbRulesDflt=		NULL;
96static char *		XkbModelDflt=		NULL;
97static char *		XkbLayoutDflt=		NULL;
98static char *		XkbVariantDflt=		NULL;
99static char *		XkbOptionsDflt=		NULL;
100
101static char *           XkbRulesUsed=   NULL;
102static char *		XkbModelUsed=	NULL;
103static char *		XkbLayoutUsed=	NULL;
104static char *		XkbVariantUsed=	NULL;
105static char *		XkbOptionsUsed=	NULL;
106
107static XkbDescPtr	xkb_cached_map = NULL;
108
109static Bool		XkbWantRulesProp=	XKB_DFLT_RULES_PROP;
110
111/***====================================================================***/
112
113/**
114 * Get the current default XKB rules.
115 * Caller must free the data in rmlvo.
116 */
117void
118XkbGetRulesDflts(XkbRMLVOSet *rmlvo)
119{
120    if (XkbRulesDflt)   rmlvo->rules = XkbRulesDflt;
121    else                rmlvo->rules = XKB_DFLT_RULES;
122    if (XkbModelDflt)	rmlvo->model= XkbModelDflt;
123    else		rmlvo->model= XKB_DFLT_MODEL;
124    if (XkbLayoutDflt)	rmlvo->layout= XkbLayoutDflt;
125    else		rmlvo->layout= XKB_DFLT_LAYOUT;
126    if (XkbVariantDflt)	rmlvo->variant= XkbVariantDflt;
127    else		rmlvo->variant= XKB_DFLT_VARIANT;
128    if (XkbOptionsDflt)	rmlvo->options= XkbOptionsDflt;
129    else		rmlvo->options= XKB_DFLT_OPTIONS;
130
131    rmlvo->rules = strdup(rmlvo->rules);
132    rmlvo->model = strdup(rmlvo->model);
133    rmlvo->layout = strdup(rmlvo->layout);
134    rmlvo->variant = strdup(rmlvo->variant);
135    rmlvo->options = strdup(rmlvo->options);
136}
137
138void
139XkbFreeRMLVOSet(XkbRMLVOSet *rmlvo, Bool freeRMLVO)
140{
141    if (!rmlvo)
142        return;
143
144    free(rmlvo->rules);
145    free(rmlvo->model);
146    free(rmlvo->layout);
147    free(rmlvo->variant);
148    free(rmlvo->options);
149
150    if (freeRMLVO)
151        free(rmlvo);
152    else
153        memset(rmlvo, 0, sizeof(XkbRMLVOSet));
154}
155
156static Bool
157XkbWriteRulesProp(ClientPtr client, pointer closure)
158{
159int 			len,out;
160Atom			name;
161char *			pval;
162
163    len= (XkbRulesUsed?strlen(XkbRulesUsed):0);
164    len+= (XkbModelUsed?strlen(XkbModelUsed):0);
165    len+= (XkbLayoutUsed?strlen(XkbLayoutUsed):0);
166    len+= (XkbVariantUsed?strlen(XkbVariantUsed):0);
167    len+= (XkbOptionsUsed?strlen(XkbOptionsUsed):0);
168    if (len<1)
169	return TRUE;
170
171    len+= 5; /* trailing NULs */
172
173    name= MakeAtom(_XKB_RF_NAMES_PROP_ATOM,strlen(_XKB_RF_NAMES_PROP_ATOM),1);
174    if (name==None) {
175	ErrorF("[xkb] Atom error: %s not created\n",_XKB_RF_NAMES_PROP_ATOM);
176	return TRUE;
177    }
178    pval= (char*) malloc(len);
179    if (!pval) {
180	ErrorF("[xkb] Allocation error: %s proprerty not created\n",
181						_XKB_RF_NAMES_PROP_ATOM);
182	return TRUE;
183    }
184    out= 0;
185    if (XkbRulesUsed) {
186	strcpy(&pval[out],XkbRulesUsed);
187	out+= strlen(XkbRulesUsed);
188    }
189    pval[out++]= '\0';
190    if (XkbModelUsed) {
191	strcpy(&pval[out],XkbModelUsed);
192	out+= strlen(XkbModelUsed);
193    }
194    pval[out++]= '\0';
195    if (XkbLayoutUsed) {
196	strcpy(&pval[out],XkbLayoutUsed);
197	out+= strlen(XkbLayoutUsed);
198    }
199    pval[out++]= '\0';
200    if (XkbVariantUsed) {
201	strcpy(&pval[out],XkbVariantUsed);
202	out+= strlen(XkbVariantUsed);
203    }
204    pval[out++]= '\0';
205    if (XkbOptionsUsed) {
206	strcpy(&pval[out],XkbOptionsUsed);
207	out+= strlen(XkbOptionsUsed);
208    }
209    pval[out++]= '\0';
210    if (out!=len) {
211	ErrorF("[xkb] Internal Error! bad size (%d!=%d) for _XKB_RULES_NAMES\n",
212								out,len);
213    }
214    dixChangeWindowProperty(serverClient, screenInfo.screens[0]->root, name, XA_STRING, 8,
215			    PropModeReplace, len, pval, TRUE);
216    free(pval);
217    return TRUE;
218}
219
220static void
221XkbSetRulesUsed(XkbRMLVOSet *rmlvo)
222{
223    free(XkbRulesUsed);
224    XkbRulesUsed= (rmlvo->rules?_XkbDupString(rmlvo->rules):NULL);
225    free(XkbModelUsed);
226    XkbModelUsed= (rmlvo->model?_XkbDupString(rmlvo->model):NULL);
227    free(XkbLayoutUsed);
228    XkbLayoutUsed= (rmlvo->layout?_XkbDupString(rmlvo->layout):NULL);
229    free(XkbVariantUsed);
230    XkbVariantUsed= (rmlvo->variant?_XkbDupString(rmlvo->variant):NULL);
231    free(XkbOptionsUsed);
232    XkbOptionsUsed= (rmlvo->options?_XkbDupString(rmlvo->options):NULL);
233    if (XkbWantRulesProp)
234	QueueWorkProc(XkbWriteRulesProp,NULL,NULL);
235    return;
236}
237
238void
239XkbSetRulesDflts(XkbRMLVOSet *rmlvo)
240{
241    if (rmlvo->rules) {
242        free(XkbRulesDflt);
243        XkbRulesDflt= _XkbDupString(rmlvo->rules);
244    }
245    if (rmlvo->model) {
246	free(XkbModelDflt);
247	XkbModelDflt= _XkbDupString(rmlvo->model);
248    }
249    if (rmlvo->layout) {
250	free(XkbLayoutDflt);
251	XkbLayoutDflt= _XkbDupString(rmlvo->layout);
252    }
253    if (rmlvo->variant) {
254	free(XkbVariantDflt);
255	XkbVariantDflt= _XkbDupString(rmlvo->variant);
256    }
257    if (rmlvo->options) {
258	free(XkbOptionsDflt);
259	XkbOptionsDflt= _XkbDupString(rmlvo->options);
260    }
261    return;
262}
263
264void
265XkbDeleteRulesDflts(void)
266{
267    free(XkbRulesDflt);
268    XkbRulesDflt = NULL;
269    free(XkbModelDflt);
270    XkbModelDflt = NULL;
271    free(XkbLayoutDflt);
272    XkbLayoutDflt = NULL;
273    free(XkbVariantDflt);
274    XkbVariantDflt = NULL;
275    free(XkbOptionsDflt);
276    XkbOptionsDflt = NULL;
277
278    XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE);
279    xkb_cached_map = NULL;
280}
281
282#define DIFFERS(a, b) (strcmp((a) ? (a) : "", (b) ? (b) : "") != 0)
283
284static Bool
285XkbCompareUsedRMLVO(XkbRMLVOSet *rmlvo)
286{
287    if (DIFFERS(rmlvo->rules, XkbRulesUsed) ||
288        DIFFERS(rmlvo->model, XkbModelUsed) ||
289        DIFFERS(rmlvo->layout, XkbLayoutUsed) ||
290        DIFFERS(rmlvo->variant, XkbVariantUsed) ||
291        DIFFERS(rmlvo->options, XkbOptionsUsed))
292        return FALSE;
293    return TRUE;
294}
295
296#undef DIFFERS
297
298/***====================================================================***/
299
300#include "xkbDflts.h"
301
302static Bool
303XkbInitKeyTypes(XkbDescPtr xkb)
304{
305    if (xkb->defined & XkmTypesMask)
306        return TRUE;
307
308    initTypeNames(NULL);
309    if (XkbAllocClientMap(xkb,XkbKeyTypesMask,num_dflt_types)!=Success)
310	return FALSE;
311    if (XkbCopyKeyTypes(dflt_types,xkb->map->types,num_dflt_types)!=
312    								 Success) {
313	return FALSE;
314    }
315    xkb->map->size_types= xkb->map->num_types= num_dflt_types;
316    return TRUE;
317}
318
319static void
320XkbInitRadioGroups(XkbSrvInfoPtr xkbi)
321{
322    xkbi->nRadioGroups = 0;
323    xkbi->radioGroups = NULL;
324    return;
325}
326
327
328static Status
329XkbInitCompatStructs(XkbDescPtr xkb)
330{
331register int 	i;
332XkbCompatMapPtr	compat;
333
334    if (xkb->defined & XkmCompatMapMask)
335        return TRUE;
336
337    if (XkbAllocCompatMap(xkb,XkbAllCompatMask,num_dfltSI)!=Success)
338	return BadAlloc;
339    compat = xkb->compat;
340    if (compat->sym_interpret) {
341	compat->num_si = num_dfltSI;
342	memcpy((char *)compat->sym_interpret,(char *)dfltSI,sizeof(dfltSI));
343    }
344    for (i=0;i<XkbNumKbdGroups;i++) {
345	compat->groups[i]= compatMap.groups[i];
346	if (compat->groups[i].vmods!=0) {
347	    unsigned mask;
348	    mask= XkbMaskForVMask(xkb,compat->groups[i].vmods);
349	    compat->groups[i].mask= compat->groups[i].real_mods|mask;
350	}
351	else compat->groups[i].mask= compat->groups[i].real_mods;
352    }
353    return Success;
354}
355
356static void
357XkbInitSemantics(XkbDescPtr xkb)
358{
359    XkbInitKeyTypes(xkb);
360    XkbInitCompatStructs(xkb);
361    return;
362}
363
364/***====================================================================***/
365
366static Status
367XkbInitNames(XkbSrvInfoPtr xkbi)
368{
369XkbDescPtr	xkb;
370XkbNamesPtr	names;
371Status		rtrn;
372Atom		unknown;
373
374    xkb= xkbi->desc;
375    if ((rtrn=XkbAllocNames(xkb,XkbAllNamesMask,0,0))!=Success)
376	return rtrn;
377    unknown= CREATE_ATOM("unknown");
378    names = xkb->names;
379    if (names->keycodes==None)		names->keycodes= unknown;
380    if (names->geometry==None)		names->geometry= unknown;
381    if (names->phys_symbols==None)	names->phys_symbols= unknown;
382    if (names->symbols==None)		names->symbols= unknown;
383    if (names->types==None)		names->types= unknown;
384    if (names->compat==None)		names->compat= unknown;
385    if (!(xkb->defined & XkmVirtualModsMask)) {
386        if (names->vmods[vmod_NumLock]==None)
387            names->vmods[vmod_NumLock]= CREATE_ATOM("NumLock");
388        if (names->vmods[vmod_Alt]==None)
389            names->vmods[vmod_Alt]= CREATE_ATOM("Alt");
390        if (names->vmods[vmod_AltGr]==None)
391            names->vmods[vmod_AltGr]= CREATE_ATOM("ModeSwitch");
392    }
393
394    if (!(xkb->defined & XkmIndicatorsMask) ||
395        !(xkb->defined & XkmGeometryMask)) {
396        initIndicatorNames(NULL,xkb);
397        if (names->indicators[LED_CAPS-1]==None)
398            names->indicators[LED_CAPS-1] = CREATE_ATOM("Caps Lock");
399        if (names->indicators[LED_NUM-1]==None)
400            names->indicators[LED_NUM-1] = CREATE_ATOM("Num Lock");
401        if (names->indicators[LED_SCROLL-1]==None)
402            names->indicators[LED_SCROLL-1] = CREATE_ATOM("Scroll Lock");
403#ifdef LED_COMPOSE
404        if (names->indicators[LED_COMPOSE-1]==None)
405            names->indicators[LED_COMPOSE-1] = CREATE_ATOM("Compose");
406#endif
407    }
408
409    if (xkb->geom!=NULL)
410	 names->geometry= xkb->geom->name;
411    else names->geometry= unknown;
412
413    return Success;
414}
415
416static Status
417XkbInitIndicatorMap(XkbSrvInfoPtr xkbi)
418{
419XkbDescPtr		xkb;
420XkbIndicatorPtr		map;
421XkbSrvLedInfoPtr	sli;
422
423    xkb= xkbi->desc;
424    if (XkbAllocIndicatorMaps(xkb)!=Success)
425	return BadAlloc;
426
427    if (!(xkb->defined & XkmIndicatorsMask)) {
428        map= xkb->indicators;
429        map->phys_indicators = PHYS_LEDS;
430        map->maps[LED_CAPS-1].flags= XkbIM_NoExplicit;
431        map->maps[LED_CAPS-1].which_mods= XkbIM_UseLocked;
432        map->maps[LED_CAPS-1].mods.mask= LockMask;
433        map->maps[LED_CAPS-1].mods.real_mods= LockMask;
434
435        map->maps[LED_NUM-1].flags= XkbIM_NoExplicit;
436        map->maps[LED_NUM-1].which_mods= XkbIM_UseLocked;
437        map->maps[LED_NUM-1].mods.mask= 0;
438        map->maps[LED_NUM-1].mods.real_mods= 0;
439        map->maps[LED_NUM-1].mods.vmods= vmod_NumLockMask;
440
441        map->maps[LED_SCROLL-1].flags= XkbIM_NoExplicit;
442        map->maps[LED_SCROLL-1].which_mods= XkbIM_UseLocked;
443        map->maps[LED_SCROLL-1].mods.mask= Mod3Mask;
444        map->maps[LED_SCROLL-1].mods.real_mods= Mod3Mask;
445    }
446
447    sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0);
448    if (sli)
449	XkbCheckIndicatorMaps(xkbi->device,sli,XkbAllIndicatorsMask);
450
451    return Success;
452}
453
454static Status
455XkbInitControls(DeviceIntPtr pXDev,XkbSrvInfoPtr xkbi)
456{
457XkbDescPtr	xkb;
458XkbControlsPtr	ctrls;
459
460    xkb= xkbi->desc;
461    /* 12/31/94 (ef) -- XXX! Should check if controls loaded from file */
462    if (XkbAllocControls(xkb,XkbAllControlsMask)!=Success)
463	FatalError("Couldn't allocate keyboard controls\n");
464    ctrls= xkb->ctrls;
465    if (!(xkb->defined & XkmSymbolsMask))
466        ctrls->num_groups = 1;
467    ctrls->groups_wrap = XkbSetGroupInfo(1,XkbWrapIntoRange,0);
468    ctrls->internal.mask = 0;
469    ctrls->internal.real_mods = 0;
470    ctrls->internal.vmods = 0;
471    ctrls->ignore_lock.mask = 0;
472    ctrls->ignore_lock.real_mods = 0;
473    ctrls->ignore_lock.vmods = 0;
474    ctrls->enabled_ctrls = XkbAccessXTimeoutMask|XkbRepeatKeysMask|
475				XkbMouseKeysAccelMask|XkbAudibleBellMask|
476				XkbIgnoreGroupLockMask;
477    if (XkbWantAccessX)
478	ctrls->enabled_ctrls|= XkbAccessXKeysMask;
479    AccessXInit(pXDev);
480    return Success;
481}
482
483_X_EXPORT Bool
484InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet *rmlvo,
485                         BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
486{
487    int	i;
488    unsigned int check;
489    XkbSrvInfoPtr xkbi;
490    XkbDescPtr xkb;
491    XkbSrvLedInfoPtr sli;
492    XkbChangesRec changes;
493    XkbEventCauseRec cause;
494    XkbRMLVOSet rmlvo_dflts = { NULL };
495
496    if (dev->key || dev->kbdfeed)
497	return FALSE;
498
499    if (!rmlvo)
500    {
501        rmlvo = &rmlvo_dflts;
502        XkbGetRulesDflts(rmlvo);
503    }
504
505
506    memset(&changes, 0, sizeof(changes));
507    XkbSetCauseUnknown(&cause);
508
509    dev->key = calloc(1, sizeof(*dev->key));
510    if (!dev->key) {
511        ErrorF("XKB: Failed to allocate key class\n");
512        return FALSE;
513    }
514    dev->key->sourceid = dev->id;
515
516    dev->kbdfeed = calloc(1, sizeof(*dev->kbdfeed));
517    if (!dev->kbdfeed) {
518        ErrorF("XKB: Failed to allocate key feedback class\n");
519        goto unwind_key;
520    }
521
522    xkbi = calloc(1, sizeof(*xkbi));
523    if (!xkbi) {
524        ErrorF("XKB: Failed to allocate XKB info\n");
525        goto unwind_kbdfeed;
526    }
527    dev->key->xkbInfo = xkbi;
528
529    if (xkb_cached_map && !XkbCompareUsedRMLVO(rmlvo)) {
530        XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE);
531        xkb_cached_map = NULL;
532    }
533
534    if (xkb_cached_map)
535        LogMessageVerb(X_INFO, 4, "XKB: Reusing cached keymap\n");
536    else {
537        xkb_cached_map = XkbCompileKeymap(dev, rmlvo);
538        if (!xkb_cached_map) {
539            ErrorF("XKB: Failed to compile keymap\n");
540            goto unwind_info;
541        }
542    }
543
544    xkb = XkbAllocKeyboard();
545    if (!xkb) {
546        ErrorF("XKB: Failed to allocate keyboard description\n");
547        goto unwind_info;
548    }
549
550    if (!XkbCopyKeymap(xkb, xkb_cached_map)) {
551        ErrorF("XKB: Failed to copy keymap\n");
552        goto unwind_desc;
553    }
554    xkb->defined = xkb_cached_map->defined;
555    xkb->flags = xkb_cached_map->flags;
556    xkb->device_spec = xkb_cached_map->device_spec;
557    xkbi->desc = xkb;
558
559    if (xkb->min_key_code == 0)
560        xkb->min_key_code = 8;
561    if (xkb->max_key_code == 0)
562        xkb->max_key_code = 255;
563
564    i = XkbNumKeys(xkb) / 3 + 1;
565    if (XkbAllocClientMap(xkb, XkbAllClientInfoMask, 0) != Success)
566        goto unwind_desc;
567    if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, i) != Success)
568        goto unwind_desc;
569
570    xkbi->dfltPtrDelta = 1;
571    xkbi->device = dev;
572
573    XkbInitSemantics(xkb);
574    XkbInitNames(xkbi);
575    XkbInitRadioGroups(xkbi);
576
577    XkbInitControls(dev, xkbi);
578
579    XkbInitIndicatorMap(xkbi);
580
581    XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &changes,
582                     &check, &cause);
583
584    InitFocusClassDeviceStruct(dev);
585
586    xkbi->kbdProc = ctrl_func;
587    dev->kbdfeed->BellProc = bell_func;
588    dev->kbdfeed->CtrlProc = XkbDDXKeybdCtrlProc;
589
590    dev->kbdfeed->ctrl = defaultKeyboardControl;
591    if (dev->kbdfeed->ctrl.autoRepeat)
592        xkb->ctrls->enabled_ctrls |= XkbRepeatKeysMask;
593
594    memcpy(dev->kbdfeed->ctrl.autoRepeats, xkb->ctrls->per_key_repeat,
595           XkbPerKeyBitArraySize);
596
597    sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
598    if (sli)
599	XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask);
600    else
601        DebugF("XKB: No indicator feedback in XkbFinishInit!\n");
602
603    dev->kbdfeed->CtrlProc(dev,&dev->kbdfeed->ctrl);
604
605    XkbSetRulesDflts(rmlvo);
606    XkbSetRulesUsed(rmlvo);
607    XkbFreeRMLVOSet(&rmlvo_dflts, FALSE);
608
609    return TRUE;
610
611unwind_desc:
612    XkbFreeKeyboard(xkb, 0, TRUE);
613unwind_info:
614    free(xkbi);
615    dev->key->xkbInfo = NULL;
616unwind_kbdfeed:
617    free(dev->kbdfeed);
618    dev->kbdfeed = NULL;
619unwind_key:
620    free(dev->key);
621    dev->key = NULL;
622    return FALSE;
623}
624
625
626/***====================================================================***/
627
628	/*
629	 * Be very careful about what does and doesn't get freed by this
630	 * function.  To reduce fragmentation, XkbInitDevice allocates a
631	 * single huge block per device and divides it up into most of the
632	 * fixed-size structures for the device.   Don't free anything that
633	 * is part of this larger block.
634	 */
635void
636XkbFreeInfo(XkbSrvInfoPtr xkbi)
637{
638    free(xkbi->radioGroups);
639    xkbi->radioGroups = NULL;
640    if (xkbi->mouseKeyTimer) {
641	TimerFree(xkbi->mouseKeyTimer);
642	xkbi->mouseKeyTimer= NULL;
643    }
644    if (xkbi->slowKeysTimer) {
645	TimerFree(xkbi->slowKeysTimer);
646	xkbi->slowKeysTimer= NULL;
647    }
648    if (xkbi->bounceKeysTimer) {
649	TimerFree(xkbi->bounceKeysTimer);
650	xkbi->bounceKeysTimer= NULL;
651    }
652    if (xkbi->repeatKeyTimer) {
653	TimerFree(xkbi->repeatKeyTimer);
654	xkbi->repeatKeyTimer= NULL;
655    }
656    if (xkbi->krgTimer) {
657	TimerFree(xkbi->krgTimer);
658	xkbi->krgTimer= NULL;
659    }
660    xkbi->beepType= _BEEP_NONE;
661    if (xkbi->beepTimer) {
662	TimerFree(xkbi->beepTimer);
663	xkbi->beepTimer= NULL;
664    }
665    if (xkbi->desc) {
666	XkbFreeKeyboard(xkbi->desc,XkbAllComponentsMask,TRUE);
667	xkbi->desc= NULL;
668    }
669    free(xkbi);
670    return;
671}
672
673/***====================================================================***/
674
675extern int	XkbDfltRepeatDelay;
676extern int	XkbDfltRepeatInterval;
677
678extern unsigned short	XkbDfltAccessXTimeout;
679extern unsigned int	XkbDfltAccessXTimeoutMask;
680extern unsigned int	XkbDfltAccessXFeedback;
681extern unsigned char	XkbDfltAccessXOptions;
682
683int
684XkbProcessArguments(int argc,char *argv[],int i)
685{
686    if (strncmp(argv[i], "-xkbdir", 7) == 0) {
687	if(++i < argc) {
688#if !defined(WIN32) && !defined(__CYGWIN__)
689	    if (getuid() != geteuid()) {
690		LogMessage(X_WARNING, "-xkbdir is not available for setuid X servers\n");
691		return -1;
692	    } else
693#endif
694	    {
695		if (strlen(argv[i]) < PATH_MAX) {
696		    XkbBaseDirectory= argv[i];
697		    return 2;
698	        } else {
699		    LogMessage(X_ERROR, "-xkbdir pathname too long\n");
700		    return -1;
701		}
702	    }
703	}
704	else {
705	    return -1;
706	}
707    }
708    else if ((strncmp(argv[i],"-accessx",8)==0)||
709                 (strncmp(argv[i],"+accessx",8)==0)) {
710	int j=1;
711	if (argv[i][0]=='-')
712	    XkbWantAccessX= 0;
713	else {
714	    XkbWantAccessX= 1;
715
716	    if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
717		XkbDfltAccessXTimeout = atoi(argv[++i]);
718		j++;
719
720		if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
721		    /*
722		     * presumption that the reasonably useful range of
723		     * values fits in 0..MAXINT since SunOS 4 doesn't
724		     * have strtoul.
725		     */
726		    XkbDfltAccessXTimeoutMask=(unsigned int)
727					      strtol(argv[++i],NULL,16);
728		    j++;
729		}
730		if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
731		    if (argv[++i][0] == '1' )
732			XkbDfltAccessXFeedback=XkbAccessXFeedbackMask;
733		    else
734			XkbDfltAccessXFeedback=0;
735		    j++;
736		}
737		if ( ((i+1)<argc) && (isdigit(argv[i+1][0])) ) {
738		    XkbDfltAccessXOptions=(unsigned char)
739					   strtol(argv[++i],NULL,16);
740		    j++;
741		}
742	    }
743	}
744	return j;
745    }
746    if ((strcmp(argv[i], "-ardelay") == 0) ||
747        (strcmp (argv[i], "-ar1") == 0)) {	/* -ardelay int */
748	if (++i >= argc) UseMsg ();
749	XkbDfltRepeatDelay = (long)atoi(argv[i]);
750	return 2;
751    }
752    if ((strcmp(argv[i], "-arinterval") == 0) ||
753        (strcmp (argv[i], "-ar2") == 0)) {	/* -arinterval int */
754	if (++i >= argc) UseMsg ();
755	XkbDfltRepeatInterval = (long)atoi(argv[i]);
756	return 2;
757    }
758    return 0;
759}
760
761void
762XkbUseMsg(void)
763{
764    ErrorF("[+-]accessx [ timeout [ timeout_mask [ feedback [ options_mask] ] ] ]\n");
765    ErrorF("                       enable/disable accessx key sequences\n");
766    ErrorF("-ardelay               set XKB autorepeat delay\n");
767    ErrorF("-arinterval            set XKB autorepeat interval\n");
768}
769