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