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	free(type->map);
296	type->map= NULL;
297	free(type->preserve);
298	type->preserve= NULL;
299	type->map_count= 0;
300    }
301    else {
302	XkbKTMapEntryRec *prev_map = type->map;
303
304	if ((map_count>type->map_count)||(type->map==NULL))
305	    type->map = realloc(type->map,map_count * sizeof(XkbKTMapEntryRec));
306	if (!type->map) {
307	    free(prev_map);
308	    return BadAlloc;
309	}
310	if (want_preserve) {
311	    XkbModsRec *prev_preserve = type->preserve;
312
313	    if ((map_count>type->map_count)||(type->preserve==NULL)) {
314		type->preserve = realloc(type->preserve,
315					  map_count * sizeof(XkbModsRec));
316	    }
317	    if (!type->preserve) {
318		free(prev_preserve);
319		return BadAlloc;
320	    }
321	}
322	else {
323	    free(type->preserve);
324	    type->preserve = NULL;
325	}
326	type->map_count= map_count;
327    }
328
329    if ((new_num_lvls>type->num_levels)||(type->level_names==NULL)) {
330	Atom * prev_level_names = type->level_names;
331
332	type->level_names = realloc(type->level_names,
333				     new_num_lvls * sizeof(Atom));
334	if (!type->level_names) {
335	    free(prev_level_names);
336	    return BadAlloc;
337	}
338    }
339    /*
340     * Here's the theory:
341     *    If the width of the type changed, we might have to resize the symbol
342     * maps for any keys that use the type for one or more groups.  This is
343     * expensive, so we'll try to cull out any keys that are obviously okay:
344     * In any case:
345     *    - keys that have a group width <= the old width are okay (because
346     *      they could not possibly have been associated with the old type)
347     * If the key type increased in size:
348     *    - keys that already have a group width >= to the new width are okay
349     *    + keys that have a group width >= the old width but < the new width
350     *      might have to be enlarged.
351     * If the key type decreased in size:
352     *    - keys that have a group width > the old width don't have to be
353     *      resized (because they must have some other wider type associated
354     *      with some group).
355     *    + keys that have a group width == the old width might have to be
356     *      shrunk.
357     * The possibilities marked with '+' require us to examine the key types
358     * associated with each group for the key.
359     */
360    memset(matchingKeys, 0, XkbMaxKeyCount*sizeof(KeyCode));
361    nMatchingKeys= 0;
362    if (new_num_lvls>type->num_levels) {
363	int	 		nTotal;
364	KeySym	*		newSyms;
365	int			width,match,nResize;
366	register int		i,g,nSyms;
367
368	nResize= 0;
369	for (nTotal=1,i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
370	    width= XkbKeyGroupsWidth(xkb,i);
371	    if (width<type->num_levels)
372		continue;
373	    for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
374		if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
375		    matchingKeys[nMatchingKeys++]= i;
376		    match= 1;
377		}
378	    }
379	    if ((!match)||(width>=new_num_lvls))
380		nTotal+= XkbKeyNumSyms(xkb,i);
381	    else {
382		nTotal+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
383		nResize++;
384	    }
385	}
386	if (nResize>0) {
387	    int nextMatch;
388	    xkb->map->size_syms= (nTotal*15)/10;
389	    newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
390	    if (newSyms==NULL)
391		return BadAlloc;
392	    nextMatch= 0;
393	    nSyms= 1;
394	    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
395		if (matchingKeys[nextMatch]==i) {
396		    KeySym *pOld;
397		    nextMatch++;
398		    width= XkbKeyGroupsWidth(xkb,i);
399		    pOld= XkbKeySymsPtr(xkb,i);
400		    for (g=XkbKeyNumGroups(xkb,i)-1;g>=0;g--) {
401			memcpy(&newSyms[nSyms+(new_num_lvls*g)],&pOld[width*g],
402							width*sizeof(KeySym));
403		    }
404		    xkb->map->key_sym_map[i].offset= nSyms;
405		    nSyms+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
406		}
407		else {
408		    memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),
409					XkbKeyNumSyms(xkb,i)*sizeof(KeySym));
410		    xkb->map->key_sym_map[i].offset= nSyms;
411		    nSyms+= XkbKeyNumSyms(xkb,i);
412		}
413	    }
414	    type->num_levels= new_num_lvls;
415	    free(xkb->map->syms);
416	    xkb->map->syms= newSyms;
417	    xkb->map->num_syms= nSyms;
418	    return Success;
419	}
420    }
421    else if (new_num_lvls<type->num_levels) {
422	int 		width,match;
423	register int	g,i;
424	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
425	    width= XkbKeyGroupsWidth(xkb,i);
426	    if (width<type->num_levels)
427		continue;
428	    for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
429		if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
430		    matchingKeys[nMatchingKeys++]= i;
431		    match= 1;
432		}
433	    }
434	}
435    }
436    if (nMatchingKeys>0) {
437	int 		key,firstClear;
438	register int	i,g;
439	if (new_num_lvls>type->num_levels)
440	     firstClear= type->num_levels;
441	else firstClear= new_num_lvls;
442	for (i=0;i<nMatchingKeys;i++) {
443	    KeySym *	pSyms;
444	    int		width,nClear;
445
446	    key= matchingKeys[i];
447	    width= XkbKeyGroupsWidth(xkb,key);
448	    nClear= width-firstClear;
449	    pSyms= XkbKeySymsPtr(xkb,key);
450	    for (g=XkbKeyNumGroups(xkb,key)-1;g>=0;g--) {
451		if (XkbKeyKeyTypeIndex(xkb,key,g)==type_ndx) {
452		    if (nClear>0)
453			memset(&pSyms[g*width+firstClear], 0, nClear*sizeof(KeySym));
454		}
455	    }
456	}
457    }
458    type->num_levels= new_num_lvls;
459    return Success;
460}
461
462KeySym *
463XkbResizeKeySyms(XkbDescPtr xkb,int key,int needed)
464{
465register int i,nSyms,nKeySyms;
466unsigned nOldSyms;
467KeySym	*newSyms;
468
469    if (needed==0) {
470	xkb->map->key_sym_map[key].offset= 0;
471	return xkb->map->syms;
472    }
473    nOldSyms= XkbKeyNumSyms(xkb,key);
474    if (nOldSyms>=(unsigned)needed) {
475	return XkbKeySymsPtr(xkb,key);
476    }
477    if (xkb->map->size_syms-xkb->map->num_syms>=(unsigned)needed) {
478	if (nOldSyms>0) {
479	    memcpy(&xkb->map->syms[xkb->map->num_syms],XkbKeySymsPtr(xkb,key),
480						nOldSyms*sizeof(KeySym));
481	}
482	if ((needed-nOldSyms)>0) {
483	    memset(&xkb->map->syms[xkb->map->num_syms+XkbKeyNumSyms(xkb, key)],
484                   0, (needed-nOldSyms)*sizeof(KeySym));
485	}
486	xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
487	xkb->map->num_syms+= needed;
488	return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
489    }
490    xkb->map->size_syms+= (needed>32?needed:32);
491    newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
492    if (newSyms==NULL)
493	return NULL;
494    newSyms[0]= NoSymbol;
495    nSyms = 1;
496    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
497	int nCopy;
498
499	nCopy= nKeySyms= XkbKeyNumSyms(xkb,i);
500	if ((nKeySyms==0)&&(i!=key))
501	    continue;
502	if (i==key)
503	    nKeySyms= needed;
504	if (nCopy!=0)
505	   memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),nCopy*sizeof(KeySym));
506	if (nKeySyms>nCopy)
507	    memset(&newSyms[nSyms+nCopy], 0, (nKeySyms-nCopy)*sizeof(KeySym));
508	xkb->map->key_sym_map[i].offset = nSyms;
509	nSyms+= nKeySyms;
510    }
511    free(xkb->map->syms);
512    xkb->map->syms = newSyms;
513    xkb->map->num_syms = nSyms;
514    return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
515}
516
517static unsigned
518_ExtendRange(	unsigned int 	old_flags,
519		unsigned int	flag,
520		KeyCode		newKC,
521		KeyCode *	old_min,
522		unsigned char *	old_num)
523{
524    if ((old_flags&flag)==0) {
525	old_flags|= flag;
526	*old_min= newKC;
527	*old_num= 1;
528    }
529    else {
530	int	last= (*old_min)+(*old_num)-1;
531	if (newKC<*old_min) {
532	    *old_min= newKC;
533	    *old_num= (last-newKC)+1;
534	}
535	else if (newKC>last) {
536	    *old_num= (newKC-(*old_min))+1;
537	}
538    }
539    return old_flags;
540}
541
542Status
543XkbChangeKeycodeRange(	XkbDescPtr	xkb,
544			int 		minKC,
545			int 		maxKC,
546			XkbChangesPtr	changes)
547{
548int	tmp;
549
550    if ((!xkb)||(minKC<XkbMinLegalKeyCode)||(maxKC>XkbMaxLegalKeyCode))
551	return BadValue;
552    if (minKC>maxKC)
553	return BadMatch;
554    if (minKC<xkb->min_key_code) {
555	if (changes)
556	    changes->map.min_key_code= minKC;
557	tmp= xkb->min_key_code-minKC;
558	if (xkb->map)  {
559	    if (xkb->map->key_sym_map) {
560		memset((char *)&xkb->map->key_sym_map[minKC], 0,
561					tmp*sizeof(XkbSymMapRec));
562		if (changes) {
563		    changes->map.changed= _ExtendRange(changes->map.changed,
564		    				XkbKeySymsMask,minKC,
565	    					&changes->map.first_key_sym,
566	    					&changes->map.num_key_syms);
567		}
568	    }
569	    if (xkb->map->modmap) {
570		memset((char *)&xkb->map->modmap[minKC], 0, tmp);
571		if (changes) {
572		    changes->map.changed= _ExtendRange(changes->map.changed,
573		    				XkbModifierMapMask,minKC,
574	    					&changes->map.first_modmap_key,
575	    					&changes->map.num_modmap_keys);
576		}
577	    }
578	}
579	if (xkb->server) {
580	    if (xkb->server->behaviors) {
581		memset((char *)&xkb->server->behaviors[minKC], 0,
582						tmp*sizeof(XkbBehavior));
583		if (changes) {
584		    changes->map.changed= _ExtendRange(changes->map.changed,
585		    			XkbKeyBehaviorsMask,minKC,
586    					&changes->map.first_key_behavior,
587    					&changes->map.num_key_behaviors);
588		}
589	    }
590	    if (xkb->server->key_acts) {
591		memset((char *)&xkb->server->key_acts[minKC], 0,
592						tmp*sizeof(unsigned short));
593		if (changes) {
594		    changes->map.changed= _ExtendRange(changes->map.changed,
595		    			XkbKeyActionsMask,minKC,
596    					&changes->map.first_key_act,
597    					&changes->map.num_key_acts);
598		}
599	    }
600	    if (xkb->server->vmodmap) {
601		memset((char *)&xkb->server->vmodmap[minKC], 0,
602						tmp*sizeof(unsigned short));
603		if (changes) {
604		    changes->map.changed= _ExtendRange(changes->map.changed,
605		    			XkbVirtualModMapMask,minKC,
606		    			&changes->map.first_modmap_key,
607    					&changes->map.num_vmodmap_keys);
608		}
609	    }
610	}
611	if ((xkb->names)&&(xkb->names->keys)) {
612	    memset((char *)&xkb->names->keys[minKC], 0, tmp*sizeof(XkbKeyNameRec));
613	    if (changes) {
614		changes->names.changed= _ExtendRange(changes->names.changed,
615					XkbKeyNamesMask,minKC,
616					&changes->names.first_key,
617    					&changes->names.num_keys);
618	    }
619	}
620	xkb->min_key_code= minKC;
621    }
622    if (maxKC>xkb->max_key_code) {
623	if (changes)
624	    changes->map.max_key_code= maxKC;
625	tmp= maxKC-xkb->max_key_code;
626	if (xkb->map)  {
627	    if (xkb->map->key_sym_map) {
628		XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
629
630		xkb->map->key_sym_map = realloc(xkb->map->key_sym_map,
631						(maxKC+1) * sizeof(XkbSymMapRec));
632		if (!xkb->map->key_sym_map) {
633		    free(prev_key_sym_map);
634		    return BadAlloc;
635		}
636		memset((char *)&xkb->map->key_sym_map[xkb->max_key_code], 0,
637					tmp*sizeof(XkbSymMapRec));
638		if (changes) {
639		    changes->map.changed= _ExtendRange(changes->map.changed,
640		    				XkbKeySymsMask,maxKC,
641	    					&changes->map.first_key_sym,
642	    					&changes->map.num_key_syms);
643		}
644	    }
645	    if (xkb->map->modmap) {
646		unsigned char *prev_modmap = xkb->map->modmap;
647
648		xkb->map->modmap = realloc(xkb->map->modmap,
649					    (maxKC+1) * sizeof(unsigned char));
650		if (!xkb->map->modmap) {
651		    free(prev_modmap);
652		    return BadAlloc;
653		}
654		memset((char *)&xkb->map->modmap[xkb->max_key_code], 0, tmp);
655		if (changes) {
656		    changes->map.changed= _ExtendRange(changes->map.changed,
657		    				XkbModifierMapMask,maxKC,
658	    					&changes->map.first_modmap_key,
659	    					&changes->map.num_modmap_keys);
660		}
661	    }
662	}
663	if (xkb->server) {
664	    if (xkb->server->behaviors) {
665		XkbBehavior *prev_behaviors = xkb->server->behaviors;
666
667		xkb->server->behaviors = realloc(xkb->server->behaviors,
668						(maxKC+1) * sizeof(XkbBehavior));
669		if (!xkb->server->behaviors) {
670		    free(prev_behaviors);
671		    return BadAlloc;
672		}
673		memset((char *)&xkb->server->behaviors[xkb->max_key_code], 0,
674						tmp*sizeof(XkbBehavior));
675		if (changes) {
676		    changes->map.changed= _ExtendRange(changes->map.changed,
677		    			XkbKeyBehaviorsMask,maxKC,
678    					&changes->map.first_key_behavior,
679    					&changes->map.num_key_behaviors);
680		}
681	    }
682	    if (xkb->server->key_acts) {
683		unsigned short *prev_key_acts = xkb->server->key_acts;
684
685		xkb->server->key_acts= realloc(xkb->server->key_acts,
686						(maxKC+1) * sizeof(unsigned short));
687		if (!xkb->server->key_acts) {
688		    free(prev_key_acts);
689		    return BadAlloc;
690		}
691		memset((char *)&xkb->server->key_acts[xkb->max_key_code], 0,
692						tmp*sizeof(unsigned short));
693		if (changes) {
694		    changes->map.changed= _ExtendRange(changes->map.changed,
695		    			XkbKeyActionsMask,maxKC,
696    					&changes->map.first_key_act,
697    					&changes->map.num_key_acts);
698		}
699	    }
700	    if (xkb->server->vmodmap) {
701		unsigned short *prev_vmodmap = xkb->server->vmodmap;
702
703		xkb->server->vmodmap= realloc(xkb->server->vmodmap,
704						(maxKC+1) * sizeof(unsigned short));
705		if (!xkb->server->vmodmap) {
706		    free(prev_vmodmap);
707		    return BadAlloc;
708		}
709		memset((char *)&xkb->server->vmodmap[xkb->max_key_code], 0,
710						tmp*sizeof(unsigned short));
711		if (changes) {
712		    changes->map.changed= _ExtendRange(changes->map.changed,
713		    			XkbVirtualModMapMask,maxKC,
714		    			&changes->map.first_modmap_key,
715    					&changes->map.num_vmodmap_keys);
716		}
717	    }
718	}
719	if ((xkb->names)&&(xkb->names->keys)) {
720	    XkbKeyNameRec *prev_keys = xkb->names->keys;
721
722	    xkb->names->keys = realloc(xkb->names->keys,
723					(maxKC+1) * sizeof(XkbKeyNameRec));
724	    if (!xkb->names->keys) {
725		free(prev_keys);
726		return BadAlloc;
727	    }
728	    memset((char *)&xkb->names->keys[xkb->max_key_code], 0,
729	    					tmp*sizeof(XkbKeyNameRec));
730	    if (changes) {
731		changes->names.changed= _ExtendRange(changes->names.changed,
732					XkbKeyNamesMask,maxKC,
733					&changes->names.first_key,
734    					&changes->names.num_keys);
735	    }
736	}
737	xkb->max_key_code= maxKC;
738    }
739    return Success;
740}
741
742XkbAction *
743XkbResizeKeyActions(XkbDescPtr xkb,int key,int needed)
744{
745register int i,nActs;
746XkbAction *newActs;
747
748    if (needed==0) {
749	xkb->server->key_acts[key]= 0;
750	return NULL;
751    }
752    if (XkbKeyHasActions(xkb,key)&&(XkbKeyNumSyms(xkb,key)>=(unsigned)needed))
753	return XkbKeyActionsPtr(xkb,key);
754    if (xkb->server->size_acts-xkb->server->num_acts>=(unsigned)needed) {
755	xkb->server->key_acts[key]= xkb->server->num_acts;
756	xkb->server->num_acts+= needed;
757	return &xkb->server->acts[xkb->server->key_acts[key]];
758    }
759    xkb->server->size_acts= xkb->server->num_acts+needed+8;
760    newActs = calloc(xkb->server->size_acts, sizeof(XkbAction));
761    if (newActs==NULL)
762	return NULL;
763    newActs[0].type = XkbSA_NoAction;
764    nActs = 1;
765    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
766	int nKeyActs,nCopy;
767
768	if ((xkb->server->key_acts[i]==0)&&(i!=key))
769	    continue;
770
771	nCopy= nKeyActs= XkbKeyNumActions(xkb,i);
772	if (i==key) {
773	    nKeyActs= needed;
774	    if (needed<nCopy)
775		nCopy= needed;
776	}
777
778	if (nCopy>0)
779	    memcpy(&newActs[nActs],XkbKeyActionsPtr(xkb,i),
780						nCopy*sizeof(XkbAction));
781	if (nCopy<nKeyActs)
782	    memset(&newActs[nActs+nCopy], 0, (nKeyActs-nCopy)*sizeof(XkbAction));
783	xkb->server->key_acts[i]= nActs;
784	nActs+= nKeyActs;
785    }
786    free(xkb->server->acts);
787    xkb->server->acts = newActs;
788    xkb->server->num_acts= nActs;
789    return &xkb->server->acts[xkb->server->key_acts[key]];
790}
791
792void
793XkbFreeClientMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
794{
795XkbClientMapPtr	map;
796
797    if ((xkb==NULL)||(xkb->map==NULL))
798	return;
799    if (freeMap)
800	what= XkbAllClientInfoMask;
801    map= xkb->map;
802    if (what&XkbKeyTypesMask) {
803	if (map->types!=NULL) {
804	    if (map->num_types>0) {
805		register int 	i;
806		XkbKeyTypePtr	type;
807		for (i=0,type=map->types;i<map->num_types;i++,type++) {
808		    free(type->map);
809		    type->map = NULL;
810		    free(type->preserve);
811		    type->preserve = NULL;
812		    type->map_count= 0;
813		    free(type->level_names);
814		    type->level_names = NULL;
815		}
816	    }
817	    free(map->types);
818	    map->num_types= map->size_types= 0;
819	    map->types= NULL;
820	}
821    }
822    if (what&XkbKeySymsMask) {
823	free(map->key_sym_map);
824	map->key_sym_map = NULL;
825	if (map->syms!=NULL) {
826	    free(map->syms);
827	    map->size_syms= map->num_syms= 0;
828	    map->syms= NULL;
829	}
830    }
831    if ((what&XkbModifierMapMask)&&(map->modmap!=NULL)) {
832	free(map->modmap);
833	map->modmap= NULL;
834    }
835    if (freeMap) {
836	free(xkb->map);
837	xkb->map= NULL;
838    }
839    return;
840}
841
842void
843XkbFreeServerMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
844{
845XkbServerMapPtr	map;
846
847    if ((xkb==NULL)||(xkb->server==NULL))
848	return;
849    if (freeMap)
850	what= XkbAllServerInfoMask;
851    map= xkb->server;
852    if ((what&XkbExplicitComponentsMask)&&(map->explicit!=NULL)) {
853	free(map->explicit);
854	map->explicit= NULL;
855    }
856    if (what&XkbKeyActionsMask) {
857	free(map->key_acts);
858	map->key_acts = NULL;
859	if (map->acts!=NULL) {
860	    free(map->acts);
861	    map->num_acts= map->size_acts= 0;
862	    map->acts= NULL;
863	}
864    }
865    if ((what&XkbKeyBehaviorsMask)&&(map->behaviors!=NULL)) {
866	free(map->behaviors);
867	map->behaviors= NULL;
868    }
869    if ((what&XkbVirtualModMapMask)&&(map->vmodmap!=NULL)) {
870	free(map->vmodmap);
871	map->vmodmap= NULL;
872    }
873
874    if (freeMap) {
875	free(xkb->server);
876	xkb->server= NULL;
877    }
878    return;
879}
880