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