XKBMAlloc.c revision eb411b4b
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#elif defined(HAVE_CONFIG_H)
30#include <config.h>
31#endif
32
33
34#include <stdio.h>
35#include "Xlibint.h"
36#include <X11/extensions/XKBproto.h>
37#include <X11/keysym.h>
38#include "XKBlibint.h"
39
40
41/***====================================================================***/
42
43Status
44XkbAllocClientMap(XkbDescPtr xkb,unsigned which,unsigned nTotalTypes)
45{
46register int	i;
47XkbClientMapPtr map;
48
49    if ((xkb==NULL)||((nTotalTypes>0)&&(nTotalTypes<XkbNumRequiredTypes)))
50	return BadValue;
51    if ((which&XkbKeySymsMask)&&
52	((!XkbIsLegalKeycode(xkb->min_key_code))||
53	 (!XkbIsLegalKeycode(xkb->max_key_code))||
54	 (xkb->max_key_code<xkb->min_key_code))) {
55#ifdef DEBUG
56fprintf(stderr,"bad keycode (%d,%d) in XkbAllocClientMap\n",
57				xkb->min_key_code,xkb->max_key_code);
58#endif
59	return BadValue;
60    }
61
62    if (xkb->map==NULL) {
63	map= _XkbTypedCalloc(1,XkbClientMapRec);
64	if (map==NULL)
65	    return BadAlloc;
66	xkb->map= map;
67    }
68    else map= xkb->map;
69
70    if ((which&XkbKeyTypesMask)&&(nTotalTypes>0)) {
71	if (map->types==NULL) {
72	    map->types= _XkbTypedCalloc(nTotalTypes,XkbKeyTypeRec);
73	    if (map->types==NULL)
74		return BadAlloc;
75	    map->num_types= 0;
76	    map->size_types= nTotalTypes;
77	}
78	else if (map->size_types<nTotalTypes) {
79	    XkbKeyTypeRec *prev_types = map->types;
80
81	    map->types= _XkbTypedRealloc(map->types,nTotalTypes,XkbKeyTypeRec);
82	    if (map->types==NULL) {
83		_XkbFree(prev_types);
84		map->num_types= map->size_types= 0;
85		return BadAlloc;
86	    }
87	    map->size_types= nTotalTypes;
88	    bzero(&map->types[map->num_types],
89		  ((map->size_types-map->num_types)*sizeof(XkbKeyTypeRec)));
90	}
91    }
92    if (which&XkbKeySymsMask) {
93	int nKeys= XkbNumKeys(xkb);
94	if (map->syms==NULL) {
95	    map->size_syms= (nKeys*15)/10;
96	    map->syms= _XkbTypedCalloc(map->size_syms,KeySym);
97	    if (!map->syms) {
98		map->size_syms= 0;
99		return BadAlloc;
100	    }
101	    map->num_syms= 1;
102	    map->syms[0]= NoSymbol;
103	}
104	if (map->key_sym_map==NULL) {
105	    i= xkb->max_key_code+1;
106	    map->key_sym_map= _XkbTypedCalloc(i,XkbSymMapRec);
107	    if (map->key_sym_map==NULL)
108		return BadAlloc;
109	}
110    }
111    if (which&XkbModifierMapMask) {
112	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
113	    (!XkbIsLegalKeycode(xkb->max_key_code))||
114	    (xkb->max_key_code<xkb->min_key_code))
115	    return BadMatch;
116	if (map->modmap==NULL) {
117	    i= xkb->max_key_code+1;
118	    map->modmap= _XkbTypedCalloc(i,unsigned char);
119	    if (map->modmap==NULL)
120		return BadAlloc;
121	}
122    }
123    return Success;
124}
125
126Status
127XkbAllocServerMap(XkbDescPtr xkb,unsigned which,unsigned nNewActions)
128{
129register int	i;
130XkbServerMapPtr map;
131
132    if (xkb==NULL)
133	return BadMatch;
134    if (xkb->server==NULL) {
135	map= _XkbTypedCalloc(1,XkbServerMapRec);
136	if (map==NULL)
137	    return BadAlloc;
138	for (i=0;i<XkbNumVirtualMods;i++) {
139	    map->vmods[i]= XkbNoModifierMask;
140	}
141	xkb->server= map;
142    }
143    else map= xkb->server;
144    if (which&XkbExplicitComponentsMask) {
145	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
146	    (!XkbIsLegalKeycode(xkb->max_key_code))||
147	    (xkb->max_key_code<xkb->min_key_code))
148	    return BadMatch;
149	if (map->explicit==NULL) {
150	    i= xkb->max_key_code+1;
151	    map->explicit= _XkbTypedCalloc(i,unsigned char);
152	    if (map->explicit==NULL)
153		return BadAlloc;
154	}
155    }
156    if (which&XkbKeyActionsMask) {
157	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
158	    (!XkbIsLegalKeycode(xkb->max_key_code))||
159	    (xkb->max_key_code<xkb->min_key_code))
160	    return BadMatch;
161        if (nNewActions<1)
162	    nNewActions= 1;
163	if (map->acts==NULL) {
164	    map->acts= _XkbTypedCalloc((nNewActions+1),XkbAction);
165	    if (map->acts==NULL)
166		return BadAlloc;
167	    map->num_acts= 1;
168	    map->size_acts= nNewActions+1;
169	}
170	else if ((map->size_acts-map->num_acts)<nNewActions) {
171	    unsigned need;
172	    XkbAction *prev_acts = map->acts;
173	    need= map->num_acts+nNewActions;
174	    map->acts= _XkbTypedRealloc(map->acts,need,XkbAction);
175	    if (map->acts==NULL) {
176		_XkbFree(prev_acts);
177	        map->num_acts= map->size_acts= 0;
178	        return BadAlloc;
179	    }
180	    map->size_acts= need;
181	    bzero(&map->acts[map->num_acts],
182		    ((map->size_acts-map->num_acts)*sizeof(XkbAction)));
183	}
184	if (map->key_acts==NULL) {
185	    i= xkb->max_key_code+1;
186	    map->key_acts= _XkbTypedCalloc(i,unsigned short);
187	    if (map->key_acts==NULL)
188		return BadAlloc;
189	}
190    }
191    if (which&XkbKeyBehaviorsMask) {
192	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
193	    (!XkbIsLegalKeycode(xkb->max_key_code))||
194	    (xkb->max_key_code<xkb->min_key_code))
195	    return BadMatch;
196	if (map->behaviors==NULL) {
197	    i= xkb->max_key_code+1;
198	    map->behaviors= _XkbTypedCalloc(i,XkbBehavior);
199	    if (map->behaviors==NULL)
200		return BadAlloc;
201	}
202    }
203    if (which&XkbVirtualModMapMask) {
204	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
205	    (!XkbIsLegalKeycode(xkb->max_key_code))||
206	    (xkb->max_key_code<xkb->min_key_code))
207	    return BadMatch;
208	if (map->vmodmap==NULL) {
209	    i= xkb->max_key_code+1;
210	    map->vmodmap= _XkbTypedCalloc(i,unsigned short);
211	    if (map->vmodmap==NULL)
212		return BadAlloc;
213	}
214    }
215    return Success;
216}
217
218/***====================================================================***/
219
220Status
221XkbCopyKeyType(XkbKeyTypePtr from,XkbKeyTypePtr into)
222{
223    if ((!from)||(!into))
224	return BadMatch;
225    if (into->map) {
226	_XkbFree(into->map);
227	into->map= NULL;
228    }
229    if (into->preserve) {
230	_XkbFree(into->preserve);
231	into->preserve= NULL;
232    }
233    if (into->level_names) {
234	_XkbFree(into->level_names);
235	into->level_names= NULL;
236    }
237    *into= *from;
238    if ((from->map)&&(into->map_count>0)) {
239	into->map= _XkbTypedCalloc(into->map_count,XkbKTMapEntryRec);
240	if (!into->map)
241	    return BadAlloc;
242	memcpy(into->map,from->map,into->map_count*sizeof(XkbKTMapEntryRec));
243    }
244    if ((from->preserve)&&(into->map_count>0)) {
245	into->preserve= _XkbTypedCalloc(into->map_count,XkbModsRec);
246	if (!into->preserve)
247	    return BadAlloc;
248	memcpy(into->preserve,from->preserve,
249				into->map_count*sizeof(XkbModsRec));
250    }
251    if ((from->level_names)&&(into->num_levels>0)) {
252	into->level_names= _XkbTypedCalloc(into->num_levels,Atom);
253	if (!into->level_names)
254	    return BadAlloc;
255	memcpy(into->level_names,from->level_names,
256				 into->num_levels*sizeof(Atom));
257    }
258    return Success;
259}
260
261Status
262XkbCopyKeyTypes(XkbKeyTypePtr from,XkbKeyTypePtr into,int num_types)
263{
264register int i,rtrn;
265
266    if ((!from)||(!into)||(num_types<0))
267	return BadMatch;
268    for (i=0;i<num_types;i++) {
269	if ((rtrn= XkbCopyKeyType(from++,into++))!=Success)
270	    return rtrn;
271    }
272    return Success;
273}
274
275XkbKeyTypePtr
276XkbAddKeyType(	XkbDescPtr	xkb,
277		Atom 		name,
278		int 		map_count,
279		Bool 		want_preserve,
280		int		num_lvls)
281{
282register int 	i;
283unsigned	tmp;
284XkbKeyTypePtr	type;
285XkbClientMapPtr	map;
286
287    if ((!xkb)||(num_lvls<1))
288	return NULL;
289    map= xkb->map;
290    if ((map)&&(map->types)) {
291	for (i=0;i<map->num_types;i++) {
292	    if (map->types[i].name==name) {
293		Status status;
294		status=XkbResizeKeyType(xkb,i,map_count,want_preserve,num_lvls);
295		return (status==Success?&map->types[i]:NULL);
296	    }
297	}
298    }
299    if ((!map)||(!map->types)||(!map->num_types<XkbNumRequiredTypes)) {
300	tmp= XkbNumRequiredTypes+1;
301	if (XkbAllocClientMap(xkb,XkbKeyTypesMask,tmp)!=Success)
302	    return NULL;
303        if (!map)
304            map = xkb->map;
305	tmp= 0;
306	if (map->num_types<=XkbKeypadIndex)
307	    tmp|= XkbKeypadMask;
308	if (map->num_types<=XkbAlphabeticIndex)
309	    tmp|= XkbAlphabeticMask;
310	if (map->num_types<=XkbTwoLevelIndex)
311	    tmp|= XkbTwoLevelMask;
312	if (map->num_types<=XkbOneLevelIndex)
313	    tmp|= XkbOneLevelMask;
314	if (XkbInitCanonicalKeyTypes(xkb,tmp,XkbNoModifier)==Success) {
315	    for (i=0;i<map->num_types;i++) {
316		Status status;
317		if (map->types[i].name!=name)
318		    continue;
319		status=XkbResizeKeyType(xkb,i,map_count,want_preserve,num_lvls);
320		return (status==Success?&map->types[i]:NULL);
321	    }
322	}
323    }
324    if ((map->num_types<=map->size_types)&&
325	(XkbAllocClientMap(xkb,XkbKeyTypesMask,map->num_types+1)!=Success)) {
326	return NULL;
327    }
328    type= &map->types[map->num_types];
329    map->num_types++;
330    bzero((char *)type,sizeof(XkbKeyTypeRec));
331    type->num_levels=	num_lvls;
332    type->map_count=	map_count;
333    type->name=		name;
334    if (map_count>0) {
335	type->map=	_XkbTypedCalloc(map_count,XkbKTMapEntryRec);
336	if (!type->map) {
337	    map->num_types--;
338	    return NULL;
339	}
340	if (want_preserve) {
341	    type->preserve=	_XkbTypedCalloc(map_count,XkbModsRec);
342	    if (!type->preserve) {
343		_XkbFree(type->map);
344		map->num_types--;
345		return NULL;
346	    }
347	}
348    }
349    return type;
350}
351
352Status
353XkbResizeKeyType(	XkbDescPtr	xkb,
354			int		type_ndx,
355			int		map_count,
356			Bool		want_preserve,
357			int		new_num_lvls)
358{
359XkbKeyTypePtr	type;
360KeyCode		matchingKeys[XkbMaxKeyCount],nMatchingKeys;
361
362    if ((type_ndx<0)||(type_ndx>=xkb->map->num_types)||(map_count<0)||
363    							(new_num_lvls<1))
364	return BadValue;
365    switch (type_ndx) {
366	case XkbOneLevelIndex:
367	    if (new_num_lvls!=1)
368		return BadMatch;
369	    break;
370	case XkbTwoLevelIndex:
371	case XkbAlphabeticIndex:
372	case XkbKeypadIndex:
373	    if (new_num_lvls!=2)
374		return BadMatch;
375	    break;
376    }
377    type= &xkb->map->types[type_ndx];
378    if (map_count==0) {
379	if (type->map!=NULL)
380	    _XkbFree(type->map);
381	type->map= NULL;
382	if (type->preserve!=NULL)
383	    _XkbFree(type->preserve);
384	type->preserve= NULL;
385	type->map_count= 0;
386    }
387    else {
388	XkbKTMapEntryRec *prev_map = type->map;
389
390	if ((map_count>type->map_count)||(type->map==NULL))
391	    type->map=_XkbTypedRealloc(type->map,map_count,XkbKTMapEntryRec);
392	if (!type->map) {
393	    if (prev_map)
394		_XkbFree(prev_map);
395	    return BadAlloc;
396	}
397	if (want_preserve) {
398	    XkbModsRec *prev_preserve = type->preserve;
399
400	    if ((map_count>type->map_count)||(type->preserve==NULL)) {
401		type->preserve= _XkbTypedRealloc(type->preserve,map_count,
402	     						    XkbModsRec);
403	    }
404	    if (!type->preserve) {
405		if (prev_preserve)
406		    _XkbFree(prev_preserve);
407		return BadAlloc;
408	    }
409	}
410	else if (type->preserve!=NULL) {
411	    _XkbFree(type->preserve);
412	    type->preserve= NULL;
413	}
414	type->map_count= map_count;
415    }
416
417    if ((new_num_lvls>type->num_levels)||(type->level_names==NULL)) {
418	Atom * prev_level_names = type->level_names;
419
420	type->level_names=_XkbTypedRealloc(type->level_names,new_num_lvls,Atom);
421	if (!type->level_names) {
422	    if (prev_level_names)
423		_XkbFree(prev_level_names);
424	    return BadAlloc;
425	}
426    }
427    /*
428     * Here's the theory:
429     *    If the width of the type changed, we might have to resize the symbol
430     * maps for any keys that use the type for one or more groups.  This is
431     * expensive, so we'll try to cull out any keys that are obviously okay:
432     * In any case:
433     *    - keys that have a group width <= the old width are okay (because
434     *      they could not possibly have been associated with the old type)
435     * If the key type increased in size:
436     *    - keys that already have a group width >= to the new width are okay
437     *    + keys that have a group width >= the old width but < the new width
438     *      might have to be enlarged.
439     * If the key type decreased in size:
440     *    - keys that have a group width > the old width don't have to be
441     *      resized (because they must have some other wider type associated
442     *      with some group).
443     *    + keys that have a group width == the old width might have to be
444     *      shrunk.
445     * The possibilities marked with '+' require us to examine the key types
446     * associated with each group for the key.
447     */
448    bzero(matchingKeys,XkbMaxKeyCount*sizeof(KeyCode));
449    nMatchingKeys= 0;
450    if (new_num_lvls>type->num_levels) {
451	int	 		nTotal;
452	KeySym	*		newSyms;
453	int			width,match,nResize;
454	register int		i,g,nSyms;
455
456	nResize= 0;
457	for (nTotal=1,i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
458	    width= XkbKeyGroupsWidth(xkb,i);
459	    if (width<type->num_levels)
460		continue;
461	    for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
462		if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
463		    matchingKeys[nMatchingKeys++]= i;
464		    match= 1;
465		}
466	    }
467	    if ((!match)||(width>=new_num_lvls))
468		nTotal+= XkbKeyNumSyms(xkb,i);
469	    else {
470		nTotal+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
471		nResize++;
472	    }
473	}
474	if (nResize>0) {
475	    int nextMatch;
476	    xkb->map->size_syms= (nTotal*12)/10;
477	    newSyms = _XkbTypedCalloc(xkb->map->size_syms,KeySym);
478	    if (newSyms==NULL)
479		return BadAlloc;
480	    nextMatch= 0;
481	    nSyms= 1;
482	    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
483		if (matchingKeys[nextMatch]==i) {
484		    KeySym *pOld;
485		    nextMatch++;
486		    width= XkbKeyGroupsWidth(xkb,i);
487		    pOld= XkbKeySymsPtr(xkb,i);
488		    for (g=XkbKeyNumGroups(xkb,i)-1;g>=0;g--) {
489			memcpy(&newSyms[nSyms+(new_num_lvls*g)],&pOld[width*g],
490							width*sizeof(KeySym));
491		    }
492		    xkb->map->key_sym_map[i].offset= nSyms;
493		    nSyms+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
494		}
495		else {
496		    memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),
497					XkbKeyNumSyms(xkb,i)*sizeof(KeySym));
498		    xkb->map->key_sym_map[i].offset= nSyms;
499		    nSyms+= XkbKeyNumSyms(xkb,i);
500		}
501	    }
502	    type->num_levels= new_num_lvls;
503	    _XkbFree(xkb->map->syms);
504	    xkb->map->syms= newSyms;
505	    xkb->map->num_syms= nSyms;
506	    return Success;
507	}
508    }
509    else if (new_num_lvls<type->num_levels) {
510	int 		width,match;
511	register int	g,i;
512	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
513	    width= XkbKeyGroupsWidth(xkb,i);
514	    if (width<type->num_levels)
515		continue;
516	    for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
517		if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
518		    matchingKeys[nMatchingKeys++]= i;
519		    match= 1;
520		}
521	    }
522	}
523    }
524    if (nMatchingKeys>0) {
525	int 		key,firstClear;
526	register int	i,g;
527	if (new_num_lvls>type->num_levels)
528	     firstClear= type->num_levels;
529	else firstClear= new_num_lvls;
530	for (i=0;i<nMatchingKeys;i++) {
531	    KeySym *	pSyms;
532	    int		width,nClear;
533
534	    key= matchingKeys[i];
535	    width= XkbKeyGroupsWidth(xkb,key);
536	    nClear= width-firstClear;
537	    pSyms= XkbKeySymsPtr(xkb,key);
538	    for (g=XkbKeyNumGroups(xkb,key)-1;g>=0;g--) {
539		if (XkbKeyKeyTypeIndex(xkb,key,g)==type_ndx) {
540		    if (nClear>0)
541			bzero(&pSyms[g*width+firstClear],nClear*sizeof(KeySym));
542		}
543	    }
544	}
545    }
546    type->num_levels= new_num_lvls;
547    return Success;
548}
549
550KeySym *
551XkbResizeKeySyms(XkbDescPtr xkb,int key,int needed)
552{
553register int i,nSyms,nKeySyms;
554unsigned nOldSyms;
555KeySym	*newSyms;
556
557    if (needed==0) {
558	xkb->map->key_sym_map[key].offset= 0;
559	return xkb->map->syms;
560    }
561    nOldSyms= XkbKeyNumSyms(xkb,key);
562    if (nOldSyms>=(unsigned)needed) {
563	return XkbKeySymsPtr(xkb,key);
564    }
565    if (xkb->map->size_syms-xkb->map->num_syms>=(unsigned)needed) {
566	if (nOldSyms>0) {
567	    memcpy(&xkb->map->syms[xkb->map->num_syms],XkbKeySymsPtr(xkb,key),
568						nOldSyms*sizeof(KeySym));
569	}
570	if ((needed-nOldSyms)>0) {
571	    bzero(&xkb->map->syms[xkb->map->num_syms+XkbKeyNumSyms(xkb,key)],
572					(needed-nOldSyms)*sizeof(KeySym));
573	}
574	xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
575	xkb->map->num_syms+= needed;
576	return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
577    }
578    xkb->map->size_syms+= (needed>32?needed:32);
579    newSyms = _XkbTypedCalloc(xkb->map->size_syms,KeySym);
580    if (newSyms==NULL)
581	return NULL;
582    newSyms[0]= NoSymbol;
583    nSyms = 1;
584    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
585	int nCopy;
586
587	nCopy= nKeySyms= XkbKeyNumSyms(xkb,i);
588	if ((nKeySyms==0)&&(i!=key))
589	    continue;
590	if (i==key)
591	    nKeySyms= needed;
592	if (nCopy!=0)
593	   memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),nCopy*sizeof(KeySym));
594	if (nKeySyms>nCopy)
595	    bzero(&newSyms[nSyms+nCopy],(nKeySyms-nCopy)*sizeof(KeySym));
596	xkb->map->key_sym_map[i].offset = nSyms;
597	nSyms+= nKeySyms;
598    }
599    _XkbFree(xkb->map->syms);
600    xkb->map->syms = newSyms;
601    xkb->map->num_syms = nSyms;
602    return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
603}
604
605static unsigned
606_ExtendRange(	unsigned int 	old_flags,
607		unsigned int	flag,
608		KeyCode		newKC,
609		KeyCode *	old_min,
610		unsigned char *	old_num)
611{
612    if ((old_flags&flag)==0) {
613	old_flags|= flag;
614	*old_min= newKC;
615	*old_num= 1;
616    }
617    else {
618	int	last= (*old_min)+(*old_num)-1;
619	if (newKC<*old_min) {
620	    *old_min= newKC;
621	    *old_num= (last-newKC)+1;
622	}
623	else if (newKC>last) {
624	    *old_num= (newKC-(*old_min))+1;
625	}
626    }
627    return old_flags;
628}
629
630Status
631XkbChangeKeycodeRange(	XkbDescPtr	xkb,
632			int 		minKC,
633			int 		maxKC,
634			XkbChangesPtr	changes)
635{
636int	tmp;
637
638    if ((!xkb)||(minKC<XkbMinLegalKeyCode)||(maxKC>XkbMaxLegalKeyCode))
639	return BadValue;
640    if (minKC>maxKC)
641	return BadMatch;
642    if (minKC<xkb->min_key_code) {
643	if (changes)
644	    changes->map.min_key_code= minKC;
645	tmp= xkb->min_key_code-minKC;
646	if (xkb->map)  {
647	    if (xkb->map->key_sym_map) {
648		bzero((char *)&xkb->map->key_sym_map[minKC],
649					tmp*sizeof(XkbSymMapRec));
650		if (changes) {
651		    changes->map.changed= _ExtendRange(changes->map.changed,
652		    				XkbKeySymsMask,minKC,
653	    					&changes->map.first_key_sym,
654	    					&changes->map.num_key_syms);
655		}
656	    }
657	    if (xkb->map->modmap) {
658		bzero((char *)&xkb->map->modmap[minKC],tmp);
659		if (changes) {
660		    changes->map.changed= _ExtendRange(changes->map.changed,
661		    				XkbModifierMapMask,minKC,
662	    					&changes->map.first_modmap_key,
663	    					&changes->map.num_modmap_keys);
664		}
665	    }
666	}
667	if (xkb->server) {
668	    if (xkb->server->behaviors) {
669		bzero((char *)&xkb->server->behaviors[minKC],
670						tmp*sizeof(XkbBehavior));
671		if (changes) {
672		    changes->map.changed= _ExtendRange(changes->map.changed,
673		    			XkbKeyBehaviorsMask,minKC,
674    					&changes->map.first_key_behavior,
675    					&changes->map.num_key_behaviors);
676		}
677	    }
678	    if (xkb->server->key_acts) {
679		bzero((char *)&xkb->server->key_acts[minKC],
680						tmp*sizeof(unsigned short));
681		if (changes) {
682		    changes->map.changed= _ExtendRange(changes->map.changed,
683		    			XkbKeyActionsMask,minKC,
684    					&changes->map.first_key_act,
685    					&changes->map.num_key_acts);
686		}
687	    }
688	    if (xkb->server->vmodmap) {
689		bzero((char *)&xkb->server->vmodmap[minKC],
690						tmp*sizeof(unsigned short));
691		if (changes) {
692		    changes->map.changed= _ExtendRange(changes->map.changed,
693		    			XkbVirtualModMapMask,minKC,
694		    			&changes->map.first_modmap_key,
695    					&changes->map.num_vmodmap_keys);
696		}
697	    }
698	}
699	if ((xkb->names)&&(xkb->names->keys)) {
700	    bzero((char *)&xkb->names->keys[minKC],tmp*sizeof(XkbKeyNameRec));
701	    if (changes) {
702		changes->names.changed= _ExtendRange(changes->names.changed,
703					XkbKeyNamesMask,minKC,
704					&changes->names.first_key,
705    					&changes->names.num_keys);
706	    }
707	}
708	xkb->min_key_code= minKC;
709    }
710    if (maxKC>xkb->max_key_code) {
711	if (changes)
712	    changes->map.max_key_code= maxKC;
713	tmp= maxKC-xkb->max_key_code;
714	if (xkb->map)  {
715	    if (xkb->map->key_sym_map) {
716		XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
717
718		xkb->map->key_sym_map= _XkbTypedRealloc(xkb->map->key_sym_map,
719						(maxKC+1),XkbSymMapRec);
720		if (!xkb->map->key_sym_map) {
721		    _XkbFree(prev_key_sym_map);
722		    return BadAlloc;
723		}
724		bzero((char *)&xkb->map->key_sym_map[xkb->max_key_code],
725					tmp*sizeof(XkbSymMapRec));
726		if (changes) {
727		    changes->map.changed= _ExtendRange(changes->map.changed,
728		    				XkbKeySymsMask,maxKC,
729	    					&changes->map.first_key_sym,
730	    					&changes->map.num_key_syms);
731		}
732	    }
733	    if (xkb->map->modmap) {
734		unsigned char *prev_modmap = xkb->map->modmap;
735
736		xkb->map->modmap= _XkbTypedRealloc(xkb->map->modmap,
737						(maxKC+1),unsigned char);
738		if (!xkb->map->modmap) {
739		    _XkbFree(prev_modmap);
740		    return BadAlloc;
741		}
742		bzero((char *)&xkb->map->modmap[xkb->max_key_code],tmp);
743		if (changes) {
744		    changes->map.changed= _ExtendRange(changes->map.changed,
745		    				XkbModifierMapMask,maxKC,
746	    					&changes->map.first_modmap_key,
747	    					&changes->map.num_modmap_keys);
748		}
749	    }
750	}
751	if (xkb->server) {
752	    if (xkb->server->behaviors) {
753		XkbBehavior *prev_behaviors = xkb->server->behaviors;
754
755		xkb->server->behaviors=_XkbTypedRealloc(xkb->server->behaviors,
756						(maxKC+1),XkbBehavior);
757		if (!xkb->server->behaviors) {
758		    _XkbFree(prev_behaviors);
759		    return BadAlloc;
760		}
761		bzero((char *)&xkb->server->behaviors[xkb->max_key_code],
762						tmp*sizeof(XkbBehavior));
763		if (changes) {
764		    changes->map.changed= _ExtendRange(changes->map.changed,
765		    			XkbKeyBehaviorsMask,maxKC,
766    					&changes->map.first_key_behavior,
767    					&changes->map.num_key_behaviors);
768		}
769	    }
770	    if (xkb->server->key_acts) {
771		unsigned short *prev_key_acts = xkb->server->key_acts;
772
773		xkb->server->key_acts= _XkbTypedRealloc(xkb->server->key_acts,
774						(maxKC+1),unsigned short);
775		if (!xkb->server->key_acts) {
776		    _XkbFree(prev_key_acts);
777		    return BadAlloc;
778		}
779		bzero((char *)&xkb->server->key_acts[xkb->max_key_code],
780						tmp*sizeof(unsigned short));
781		if (changes) {
782		    changes->map.changed= _ExtendRange(changes->map.changed,
783		    			XkbKeyActionsMask,maxKC,
784    					&changes->map.first_key_act,
785    					&changes->map.num_key_acts);
786		}
787	    }
788	    if (xkb->server->vmodmap) {
789		unsigned short *prev_vmodmap = xkb->server->vmodmap;
790
791		xkb->server->vmodmap= _XkbTypedRealloc(xkb->server->vmodmap,
792						(maxKC+1),unsigned short);
793		if (!xkb->server->vmodmap) {
794		    _XkbFree(prev_vmodmap);
795		    return BadAlloc;
796		}
797		bzero((char *)&xkb->server->vmodmap[xkb->max_key_code],
798						tmp*sizeof(unsigned short));
799		if (changes) {
800		    changes->map.changed= _ExtendRange(changes->map.changed,
801		    			XkbVirtualModMapMask,maxKC,
802		    			&changes->map.first_modmap_key,
803    					&changes->map.num_vmodmap_keys);
804		}
805	    }
806	}
807	if ((xkb->names)&&(xkb->names->keys)) {
808	    XkbKeyNameRec *prev_keys = xkb->names->keys;
809
810	    xkb->names->keys= _XkbTypedRealloc(xkb->names->keys,
811	    					(maxKC+1),XkbKeyNameRec);
812	    if (!xkb->names->keys) {
813		_XkbFree(prev_keys);
814		return BadAlloc;
815	    }
816	    bzero((char *)&xkb->names->keys[xkb->max_key_code],
817	    					tmp*sizeof(XkbKeyNameRec));
818	    if (changes) {
819		changes->names.changed= _ExtendRange(changes->names.changed,
820					XkbKeyNamesMask,maxKC,
821					&changes->names.first_key,
822    					&changes->names.num_keys);
823	    }
824	}
825	xkb->max_key_code= maxKC;
826    }
827    return Success;
828}
829
830XkbAction *
831XkbResizeKeyActions(XkbDescPtr xkb,int key,int needed)
832{
833register int i,nActs;
834XkbAction *newActs;
835
836    if (needed==0) {
837	xkb->server->key_acts[key]= 0;
838	return NULL;
839    }
840    if (XkbKeyHasActions(xkb,key)&&(XkbKeyNumSyms(xkb,key)>=(unsigned)needed))
841	return XkbKeyActionsPtr(xkb,key);
842    if (xkb->server->size_acts-xkb->server->num_acts>=(unsigned)needed) {
843	xkb->server->key_acts[key]= xkb->server->num_acts;
844	xkb->server->num_acts+= needed;
845	return &xkb->server->acts[xkb->server->key_acts[key]];
846    }
847    xkb->server->size_acts= xkb->server->num_acts+needed+8;
848    newActs = _XkbTypedCalloc(xkb->server->size_acts,XkbAction);
849    if (newActs==NULL)
850	return NULL;
851    newActs[0].type = XkbSA_NoAction;
852    nActs = 1;
853    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
854	int nKeyActs,nCopy;
855
856	if ((xkb->server->key_acts[i]==0)&&(i!=key))
857	    continue;
858
859	nCopy= nKeyActs= XkbKeyNumActions(xkb,i);
860	if (i==key) {
861	    nKeyActs= needed;
862	    if (needed<nCopy)
863		nCopy= needed;
864	}
865
866	if (nCopy>0)
867	    memcpy(&newActs[nActs],XkbKeyActionsPtr(xkb,i),
868						nCopy*sizeof(XkbAction));
869	if (nCopy<nKeyActs)
870	    bzero(&newActs[nActs+nCopy],(nKeyActs-nCopy)*sizeof(XkbAction));
871	xkb->server->key_acts[i]= nActs;
872	nActs+= nKeyActs;
873    }
874    _XkbFree(xkb->server->acts);
875    xkb->server->acts = newActs;
876    xkb->server->num_acts= nActs;
877    return &xkb->server->acts[xkb->server->key_acts[key]];
878}
879
880void
881XkbFreeClientMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
882{
883XkbClientMapPtr	map;
884
885    if ((xkb==NULL)||(xkb->map==NULL))
886	return;
887    if (freeMap)
888	what= XkbAllClientInfoMask;
889    map= xkb->map;
890    if (what&XkbKeyTypesMask) {
891	if (map->types!=NULL) {
892	    if (map->num_types>0) {
893		register int 	i;
894		XkbKeyTypePtr	type;
895		for (i=0,type=map->types;i<map->num_types;i++,type++) {
896		    if (type->map!=NULL) {
897			_XkbFree(type->map);
898			type->map= NULL;
899		    }
900		    if (type->preserve!=NULL) {
901			_XkbFree(type->preserve);
902			type->preserve= NULL;
903		    }
904		    type->map_count= 0;
905		    if (type->level_names!=NULL) {
906			_XkbFree(type->level_names);
907			type->level_names= NULL;
908		    }
909		}
910	    }
911	    _XkbFree(map->types);
912	    map->num_types= map->size_types= 0;
913	    map->types= NULL;
914	}
915    }
916    if (what&XkbKeySymsMask) {
917	if (map->key_sym_map!=NULL) {
918	    _XkbFree(map->key_sym_map);
919	    map->key_sym_map= NULL;
920	}
921	if (map->syms!=NULL) {
922	    _XkbFree(map->syms);
923	    map->size_syms= map->num_syms= 0;
924	    map->syms= NULL;
925	}
926    }
927    if ((what&XkbModifierMapMask)&&(map->modmap!=NULL)) {
928	_XkbFree(map->modmap);
929	map->modmap= NULL;
930    }
931    if (freeMap) {
932	_XkbFree(xkb->map);
933	xkb->map= NULL;
934    }
935    return;
936}
937
938void
939XkbFreeServerMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
940{
941XkbServerMapPtr	map;
942
943    if ((xkb==NULL)||(xkb->server==NULL))
944	return;
945    if (freeMap)
946	what= XkbAllServerInfoMask;
947    map= xkb->server;
948    if ((what&XkbExplicitComponentsMask)&&(map->explicit!=NULL)) {
949	_XkbFree(map->explicit);
950	map->explicit= NULL;
951    }
952    if (what&XkbKeyActionsMask) {
953	if (map->key_acts!=NULL) {
954	    _XkbFree(map->key_acts);
955	    map->key_acts= NULL;
956	}
957	if (map->acts!=NULL) {
958	    _XkbFree(map->acts);
959	    map->num_acts= map->size_acts= 0;
960	    map->acts= NULL;
961	}
962    }
963    if ((what&XkbKeyBehaviorsMask)&&(map->behaviors!=NULL)) {
964	_XkbFree(map->behaviors);
965	map->behaviors= NULL;
966    }
967    if ((what&XkbVirtualModMapMask)&&(map->vmodmap!=NULL)) {
968	_XkbFree(map->vmodmap);
969	map->vmodmap= NULL;
970    }
971
972    if (freeMap) {
973	_XkbFree(xkb->server);
974	xkb->server= NULL;
975    }
976    return;
977}
978