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