1706f2543Smrg/************************************************************
2706f2543SmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3706f2543Smrg
4706f2543SmrgPermission to use, copy, modify, and distribute this
5706f2543Smrgsoftware and its documentation for any purpose and without
6706f2543Smrgfee is hereby granted, provided that the above copyright
7706f2543Smrgnotice appear in all copies and that both that copyright
8706f2543Smrgnotice and this permission notice appear in supporting
9706f2543Smrgdocumentation, and that the name of Silicon Graphics not be
10706f2543Smrgused in advertising or publicity pertaining to distribution
11706f2543Smrgof the software without specific prior written permission.
12706f2543SmrgSilicon Graphics makes no representation about the suitability
13706f2543Smrgof this software for any purpose. It is provided "as is"
14706f2543Smrgwithout any express or implied warranty.
15706f2543Smrg
16706f2543SmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18706f2543SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19706f2543SmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20706f2543SmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21706f2543SmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22706f2543SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23706f2543SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
24706f2543Smrg
25706f2543Smrg********************************************************/
26706f2543Smrg
27706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
28706f2543Smrg#include <dix-config.h>
29706f2543Smrg#elif defined(HAVE_CONFIG_H)
30706f2543Smrg#include <config.h>
31706f2543Smrg#endif
32706f2543Smrg
33706f2543Smrg#include <stdio.h>
34706f2543Smrg#include <X11/X.h>
35706f2543Smrg#include <X11/Xproto.h>
36706f2543Smrg#include "misc.h"
37706f2543Smrg#include "inputstr.h"
38706f2543Smrg#include <X11/keysym.h>
39706f2543Smrg#define	XKBSRV_NEED_FILE_FUNCS
40706f2543Smrg#include <xkbsrv.h>
41706f2543Smrg
42706f2543Smrg/***====================================================================***/
43706f2543Smrg
44706f2543SmrgStatus
45706f2543SmrgXkbAllocClientMap(XkbDescPtr xkb,unsigned which,unsigned nTotalTypes)
46706f2543Smrg{
47706f2543Smrgregister int	i;
48706f2543SmrgXkbClientMapPtr map;
49706f2543Smrg
50706f2543Smrg    if ((xkb==NULL)||((nTotalTypes>0)&&(nTotalTypes<XkbNumRequiredTypes)))
51706f2543Smrg	return BadValue;
52706f2543Smrg    if ((which&XkbKeySymsMask)&&
53706f2543Smrg	((!XkbIsLegalKeycode(xkb->min_key_code))||
54706f2543Smrg	 (!XkbIsLegalKeycode(xkb->max_key_code))||
55706f2543Smrg	 (xkb->max_key_code<xkb->min_key_code))) {
56706f2543Smrg        DebugF("bad keycode (%d,%d) in XkbAllocClientMap\n",
57706f2543Smrg				xkb->min_key_code,xkb->max_key_code);
58706f2543Smrg	return BadValue;
59706f2543Smrg    }
60706f2543Smrg
61706f2543Smrg    if (xkb->map==NULL) {
62706f2543Smrg	map= calloc(1, sizeof(XkbClientMapRec));
63706f2543Smrg	if (map==NULL)
64706f2543Smrg	    return BadAlloc;
65706f2543Smrg	xkb->map= map;
66706f2543Smrg    }
67706f2543Smrg    else map= xkb->map;
68706f2543Smrg
69706f2543Smrg    if ((which&XkbKeyTypesMask)&&(nTotalTypes>0)) {
70706f2543Smrg	if (map->types==NULL) {
71706f2543Smrg	    map->types= calloc(nTotalTypes, sizeof(XkbKeyTypeRec));
72706f2543Smrg	    if (map->types==NULL)
73706f2543Smrg		return BadAlloc;
74706f2543Smrg	    map->num_types= 0;
75706f2543Smrg	    map->size_types= nTotalTypes;
76706f2543Smrg	}
77706f2543Smrg	else if (map->size_types<nTotalTypes) {
78706f2543Smrg	    XkbKeyTypeRec *prev_types = map->types;
79706f2543Smrg
80706f2543Smrg	    map->types= realloc(map->types,nTotalTypes * sizeof(XkbKeyTypeRec));
81706f2543Smrg	    if (map->types==NULL) {
82706f2543Smrg		free(prev_types);
83706f2543Smrg		map->num_types= map->size_types= 0;
84706f2543Smrg		return BadAlloc;
85706f2543Smrg	    }
86706f2543Smrg	    map->size_types= nTotalTypes;
87706f2543Smrg	    memset(&map->types[map->num_types], 0,
88706f2543Smrg		  ((map->size_types-map->num_types)*sizeof(XkbKeyTypeRec)));
89706f2543Smrg	}
90706f2543Smrg    }
91706f2543Smrg    if (which&XkbKeySymsMask) {
92706f2543Smrg	int nKeys= XkbNumKeys(xkb);
93706f2543Smrg	if (map->syms==NULL) {
94706f2543Smrg	    map->size_syms= (nKeys*15)/10;
95706f2543Smrg	    map->syms= calloc(map->size_syms, sizeof(KeySym));
96706f2543Smrg	    if (!map->syms) {
97706f2543Smrg		map->size_syms= 0;
98706f2543Smrg		return BadAlloc;
99706f2543Smrg	    }
100706f2543Smrg	    map->num_syms= 1;
101706f2543Smrg	    map->syms[0]= NoSymbol;
102706f2543Smrg	}
103706f2543Smrg	if (map->key_sym_map==NULL) {
104706f2543Smrg	    i= xkb->max_key_code+1;
105706f2543Smrg	    map->key_sym_map= calloc(i, sizeof(XkbSymMapRec));
106706f2543Smrg	    if (map->key_sym_map==NULL)
107706f2543Smrg		return BadAlloc;
108706f2543Smrg	}
109706f2543Smrg    }
110706f2543Smrg    if (which&XkbModifierMapMask) {
111706f2543Smrg	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
112706f2543Smrg	    (!XkbIsLegalKeycode(xkb->max_key_code))||
113706f2543Smrg	    (xkb->max_key_code<xkb->min_key_code))
114706f2543Smrg	    return BadMatch;
115706f2543Smrg	if (map->modmap==NULL) {
116706f2543Smrg	    i= xkb->max_key_code+1;
117706f2543Smrg	    map->modmap= calloc(i, sizeof(unsigned char));
118706f2543Smrg	    if (map->modmap==NULL)
119706f2543Smrg		return BadAlloc;
120706f2543Smrg	}
121706f2543Smrg    }
122706f2543Smrg    return Success;
123706f2543Smrg}
124706f2543Smrg
125706f2543SmrgStatus
126706f2543SmrgXkbAllocServerMap(XkbDescPtr xkb,unsigned which,unsigned nNewActions)
127706f2543Smrg{
128706f2543Smrgregister int	i;
129706f2543SmrgXkbServerMapPtr map;
130706f2543Smrg
131706f2543Smrg    if (xkb==NULL)
132706f2543Smrg	return BadMatch;
133706f2543Smrg    if (xkb->server==NULL) {
134706f2543Smrg	map= calloc(1, sizeof(XkbServerMapRec));
135706f2543Smrg	if (map==NULL)
136706f2543Smrg	    return BadAlloc;
137706f2543Smrg	for (i=0;i<XkbNumVirtualMods;i++) {
138706f2543Smrg	    map->vmods[i]= XkbNoModifierMask;
139706f2543Smrg	}
140706f2543Smrg	xkb->server= map;
141706f2543Smrg    }
142706f2543Smrg    else map= xkb->server;
143706f2543Smrg    if (which&XkbExplicitComponentsMask) {
144706f2543Smrg	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
145706f2543Smrg	    (!XkbIsLegalKeycode(xkb->max_key_code))||
146706f2543Smrg	    (xkb->max_key_code<xkb->min_key_code))
147706f2543Smrg	    return BadMatch;
148706f2543Smrg	if (map->explicit==NULL) {
149706f2543Smrg	    i= xkb->max_key_code+1;
150706f2543Smrg	    map->explicit= calloc(i, sizeof(unsigned char));
151706f2543Smrg	    if (map->explicit==NULL)
152706f2543Smrg		return BadAlloc;
153706f2543Smrg	}
154706f2543Smrg    }
155706f2543Smrg    if (which&XkbKeyActionsMask) {
156706f2543Smrg	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
157706f2543Smrg	    (!XkbIsLegalKeycode(xkb->max_key_code))||
158706f2543Smrg	    (xkb->max_key_code<xkb->min_key_code))
159706f2543Smrg	    return BadMatch;
160706f2543Smrg        if (nNewActions<1)
161706f2543Smrg	    nNewActions= 1;
162706f2543Smrg	if (map->acts==NULL) {
163706f2543Smrg	    map->acts= calloc((nNewActions+1), sizeof(XkbAction));
164706f2543Smrg	    if (map->acts==NULL)
165706f2543Smrg		return BadAlloc;
166706f2543Smrg	    map->num_acts= 1;
167706f2543Smrg	    map->size_acts= nNewActions+1;
168706f2543Smrg	}
169706f2543Smrg	else if ((map->size_acts-map->num_acts)<nNewActions) {
170706f2543Smrg	    unsigned need;
171706f2543Smrg	    XkbAction *prev_acts = map->acts;
172706f2543Smrg	    need= map->num_acts+nNewActions;
173706f2543Smrg	    map->acts= realloc(map->acts,need * sizeof(XkbAction));
174706f2543Smrg	    if (map->acts==NULL) {
175706f2543Smrg		free(prev_acts);
176706f2543Smrg	        map->num_acts= map->size_acts= 0;
177706f2543Smrg	        return BadAlloc;
178706f2543Smrg	    }
179706f2543Smrg	    map->size_acts= need;
180706f2543Smrg	    memset(&map->acts[map->num_acts], 0,
181706f2543Smrg		    ((map->size_acts-map->num_acts)*sizeof(XkbAction)));
182706f2543Smrg	}
183706f2543Smrg	if (map->key_acts==NULL) {
184706f2543Smrg	    i= xkb->max_key_code+1;
185706f2543Smrg	    map->key_acts= calloc(i, sizeof(unsigned short));
186706f2543Smrg	    if (map->key_acts==NULL)
187706f2543Smrg		return BadAlloc;
188706f2543Smrg	}
189706f2543Smrg    }
190706f2543Smrg    if (which&XkbKeyBehaviorsMask) {
191706f2543Smrg	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
192706f2543Smrg	    (!XkbIsLegalKeycode(xkb->max_key_code))||
193706f2543Smrg	    (xkb->max_key_code<xkb->min_key_code))
194706f2543Smrg	    return BadMatch;
195706f2543Smrg	if (map->behaviors==NULL) {
196706f2543Smrg	    i= xkb->max_key_code+1;
197706f2543Smrg	    map->behaviors= calloc(i, sizeof(XkbBehavior));
198706f2543Smrg	    if (map->behaviors==NULL)
199706f2543Smrg		return BadAlloc;
200706f2543Smrg	}
201706f2543Smrg    }
202706f2543Smrg    if (which&XkbVirtualModMapMask) {
203706f2543Smrg	if ((!XkbIsLegalKeycode(xkb->min_key_code))||
204706f2543Smrg	    (!XkbIsLegalKeycode(xkb->max_key_code))||
205706f2543Smrg	    (xkb->max_key_code<xkb->min_key_code))
206706f2543Smrg	    return BadMatch;
207706f2543Smrg	if (map->vmodmap==NULL) {
208706f2543Smrg	    i= xkb->max_key_code+1;
209706f2543Smrg	    map->vmodmap= calloc(i, sizeof(unsigned short));
210706f2543Smrg	    if (map->vmodmap==NULL)
211706f2543Smrg		return BadAlloc;
212706f2543Smrg	}
213706f2543Smrg    }
214706f2543Smrg    return Success;
215706f2543Smrg}
216706f2543Smrg
217706f2543Smrg/***====================================================================***/
218706f2543Smrg
219706f2543Smrgstatic Status
220706f2543SmrgXkbCopyKeyType(XkbKeyTypePtr from,XkbKeyTypePtr into)
221706f2543Smrg{
222706f2543Smrg    if ((!from)||(!into))
223706f2543Smrg	return BadMatch;
224706f2543Smrg    free(into->map);
225706f2543Smrg    into->map = NULL;
226706f2543Smrg    free(into->preserve);
227706f2543Smrg    into->preserve = NULL;
228706f2543Smrg    free(into->level_names);
229706f2543Smrg    into->level_names = NULL;
230706f2543Smrg    *into= *from;
231706f2543Smrg    if ((from->map)&&(into->map_count>0)) {
232706f2543Smrg	into->map= calloc(into->map_count, sizeof(XkbKTMapEntryRec));
233706f2543Smrg	if (!into->map)
234706f2543Smrg	    return BadAlloc;
235706f2543Smrg	memcpy(into->map,from->map,into->map_count*sizeof(XkbKTMapEntryRec));
236706f2543Smrg    }
237706f2543Smrg    if ((from->preserve)&&(into->map_count>0)) {
238706f2543Smrg	into->preserve= calloc(into->map_count, sizeof(XkbModsRec));
239706f2543Smrg	if (!into->preserve)
240706f2543Smrg	    return BadAlloc;
241706f2543Smrg	memcpy(into->preserve,from->preserve,
242706f2543Smrg				into->map_count*sizeof(XkbModsRec));
243706f2543Smrg    }
244706f2543Smrg    if ((from->level_names)&&(into->num_levels>0)) {
245706f2543Smrg	into->level_names= calloc(into->num_levels, sizeof(Atom));
246706f2543Smrg	if (!into->level_names)
247706f2543Smrg	    return BadAlloc;
248706f2543Smrg	memcpy(into->level_names,from->level_names,
249706f2543Smrg				 into->num_levels*sizeof(Atom));
250706f2543Smrg    }
251706f2543Smrg    return Success;
252706f2543Smrg}
253706f2543Smrg
254706f2543SmrgStatus
255706f2543SmrgXkbCopyKeyTypes(XkbKeyTypePtr from,XkbKeyTypePtr into,int num_types)
256706f2543Smrg{
257706f2543Smrgregister int i,rtrn;
258706f2543Smrg
259706f2543Smrg    if ((!from)||(!into)||(num_types<0))
260706f2543Smrg	return BadMatch;
261706f2543Smrg    for (i=0;i<num_types;i++) {
262706f2543Smrg	if ((rtrn= XkbCopyKeyType(from++,into++))!=Success)
263706f2543Smrg	    return rtrn;
264706f2543Smrg    }
265706f2543Smrg    return Success;
266706f2543Smrg}
267706f2543Smrg
268706f2543SmrgStatus
269706f2543SmrgXkbResizeKeyType(	XkbDescPtr	xkb,
270706f2543Smrg			int		type_ndx,
271706f2543Smrg			int		map_count,
272706f2543Smrg			Bool		want_preserve,
273706f2543Smrg			int		new_num_lvls)
274706f2543Smrg{
275706f2543SmrgXkbKeyTypePtr	type;
276706f2543SmrgKeyCode		matchingKeys[XkbMaxKeyCount],nMatchingKeys;
277706f2543Smrg
278706f2543Smrg    if ((type_ndx<0)||(type_ndx>=xkb->map->num_types)||(map_count<0)||
279706f2543Smrg    							(new_num_lvls<1))
280706f2543Smrg	return BadValue;
281706f2543Smrg    switch (type_ndx) {
282706f2543Smrg	case XkbOneLevelIndex:
283706f2543Smrg	    if (new_num_lvls!=1)
284706f2543Smrg		return BadMatch;
285706f2543Smrg	    break;
286706f2543Smrg	case XkbTwoLevelIndex:
287706f2543Smrg	case XkbAlphabeticIndex:
288706f2543Smrg	case XkbKeypadIndex:
289706f2543Smrg	    if (new_num_lvls!=2)
290706f2543Smrg		return BadMatch;
291706f2543Smrg	    break;
292706f2543Smrg    }
293706f2543Smrg    type= &xkb->map->types[type_ndx];
294706f2543Smrg    if (map_count==0) {
295706f2543Smrg	free(type->map);
296706f2543Smrg	type->map= NULL;
297706f2543Smrg	free(type->preserve);
298706f2543Smrg	type->preserve= NULL;
299706f2543Smrg	type->map_count= 0;
300706f2543Smrg    }
301706f2543Smrg    else {
302706f2543Smrg	XkbKTMapEntryRec *prev_map = type->map;
303706f2543Smrg
304706f2543Smrg	if ((map_count>type->map_count)||(type->map==NULL))
305706f2543Smrg	    type->map = realloc(type->map,map_count * sizeof(XkbKTMapEntryRec));
306706f2543Smrg	if (!type->map) {
307706f2543Smrg	    free(prev_map);
308706f2543Smrg	    return BadAlloc;
309706f2543Smrg	}
310706f2543Smrg	if (want_preserve) {
311706f2543Smrg	    XkbModsRec *prev_preserve = type->preserve;
312706f2543Smrg
313706f2543Smrg	    if ((map_count>type->map_count)||(type->preserve==NULL)) {
314706f2543Smrg		type->preserve = realloc(type->preserve,
315706f2543Smrg					  map_count * sizeof(XkbModsRec));
316706f2543Smrg	    }
317706f2543Smrg	    if (!type->preserve) {
318706f2543Smrg		free(prev_preserve);
319706f2543Smrg		return BadAlloc;
320706f2543Smrg	    }
321706f2543Smrg	}
322706f2543Smrg	else {
323706f2543Smrg	    free(type->preserve);
324706f2543Smrg	    type->preserve = NULL;
325706f2543Smrg	}
326706f2543Smrg	type->map_count= map_count;
327706f2543Smrg    }
328706f2543Smrg
329706f2543Smrg    if ((new_num_lvls>type->num_levels)||(type->level_names==NULL)) {
330706f2543Smrg	Atom * prev_level_names = type->level_names;
331706f2543Smrg
332706f2543Smrg	type->level_names = realloc(type->level_names,
333706f2543Smrg				     new_num_lvls * sizeof(Atom));
334706f2543Smrg	if (!type->level_names) {
335706f2543Smrg	    free(prev_level_names);
336706f2543Smrg	    return BadAlloc;
337706f2543Smrg	}
338706f2543Smrg    }
339706f2543Smrg    /*
340706f2543Smrg     * Here's the theory:
341706f2543Smrg     *    If the width of the type changed, we might have to resize the symbol
342706f2543Smrg     * maps for any keys that use the type for one or more groups.  This is
343706f2543Smrg     * expensive, so we'll try to cull out any keys that are obviously okay:
344706f2543Smrg     * In any case:
345706f2543Smrg     *    - keys that have a group width <= the old width are okay (because
346706f2543Smrg     *      they could not possibly have been associated with the old type)
347706f2543Smrg     * If the key type increased in size:
348706f2543Smrg     *    - keys that already have a group width >= to the new width are okay
349706f2543Smrg     *    + keys that have a group width >= the old width but < the new width
350706f2543Smrg     *      might have to be enlarged.
351706f2543Smrg     * If the key type decreased in size:
352706f2543Smrg     *    - keys that have a group width > the old width don't have to be
353706f2543Smrg     *      resized (because they must have some other wider type associated
354706f2543Smrg     *      with some group).
355706f2543Smrg     *    + keys that have a group width == the old width might have to be
356706f2543Smrg     *      shrunk.
357706f2543Smrg     * The possibilities marked with '+' require us to examine the key types
358706f2543Smrg     * associated with each group for the key.
359706f2543Smrg     */
360706f2543Smrg    memset(matchingKeys, 0, XkbMaxKeyCount*sizeof(KeyCode));
361706f2543Smrg    nMatchingKeys= 0;
362706f2543Smrg    if (new_num_lvls>type->num_levels) {
363706f2543Smrg	int	 		nTotal;
364706f2543Smrg	KeySym	*		newSyms;
365706f2543Smrg	int			width,match,nResize;
366706f2543Smrg	register int		i,g,nSyms;
367706f2543Smrg
368706f2543Smrg	nResize= 0;
369706f2543Smrg	for (nTotal=1,i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
370706f2543Smrg	    width= XkbKeyGroupsWidth(xkb,i);
371706f2543Smrg	    if (width<type->num_levels)
372706f2543Smrg		continue;
373706f2543Smrg	    for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
374706f2543Smrg		if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
375706f2543Smrg		    matchingKeys[nMatchingKeys++]= i;
376706f2543Smrg		    match= 1;
377706f2543Smrg		}
378706f2543Smrg	    }
379706f2543Smrg	    if ((!match)||(width>=new_num_lvls))
380706f2543Smrg		nTotal+= XkbKeyNumSyms(xkb,i);
381706f2543Smrg	    else {
382706f2543Smrg		nTotal+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
383706f2543Smrg		nResize++;
384706f2543Smrg	    }
385706f2543Smrg	}
386706f2543Smrg	if (nResize>0) {
387706f2543Smrg	    int nextMatch;
388706f2543Smrg	    xkb->map->size_syms= (nTotal*15)/10;
389706f2543Smrg	    newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
390706f2543Smrg	    if (newSyms==NULL)
391706f2543Smrg		return BadAlloc;
392706f2543Smrg	    nextMatch= 0;
393706f2543Smrg	    nSyms= 1;
394706f2543Smrg	    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
395706f2543Smrg		if (matchingKeys[nextMatch]==i) {
396706f2543Smrg		    KeySym *pOld;
397706f2543Smrg		    nextMatch++;
398706f2543Smrg		    width= XkbKeyGroupsWidth(xkb,i);
399706f2543Smrg		    pOld= XkbKeySymsPtr(xkb,i);
400706f2543Smrg		    for (g=XkbKeyNumGroups(xkb,i)-1;g>=0;g--) {
401706f2543Smrg			memcpy(&newSyms[nSyms+(new_num_lvls*g)],&pOld[width*g],
402706f2543Smrg							width*sizeof(KeySym));
403706f2543Smrg		    }
404706f2543Smrg		    xkb->map->key_sym_map[i].offset= nSyms;
405706f2543Smrg		    nSyms+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
406706f2543Smrg		}
407706f2543Smrg		else {
408706f2543Smrg		    memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),
409706f2543Smrg					XkbKeyNumSyms(xkb,i)*sizeof(KeySym));
410706f2543Smrg		    xkb->map->key_sym_map[i].offset= nSyms;
411706f2543Smrg		    nSyms+= XkbKeyNumSyms(xkb,i);
412706f2543Smrg		}
413706f2543Smrg	    }
414706f2543Smrg	    type->num_levels= new_num_lvls;
415706f2543Smrg	    free(xkb->map->syms);
416706f2543Smrg	    xkb->map->syms= newSyms;
417706f2543Smrg	    xkb->map->num_syms= nSyms;
418706f2543Smrg	    return Success;
419706f2543Smrg	}
420706f2543Smrg    }
421706f2543Smrg    else if (new_num_lvls<type->num_levels) {
422706f2543Smrg	int 		width,match;
423706f2543Smrg	register int	g,i;
424706f2543Smrg	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
425706f2543Smrg	    width= XkbKeyGroupsWidth(xkb,i);
426706f2543Smrg	    if (width<type->num_levels)
427706f2543Smrg		continue;
428706f2543Smrg	    for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
429706f2543Smrg		if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
430706f2543Smrg		    matchingKeys[nMatchingKeys++]= i;
431706f2543Smrg		    match= 1;
432706f2543Smrg		}
433706f2543Smrg	    }
434706f2543Smrg	}
435706f2543Smrg    }
436706f2543Smrg    if (nMatchingKeys>0) {
437706f2543Smrg	int 		key,firstClear;
438706f2543Smrg	register int	i,g;
439706f2543Smrg	if (new_num_lvls>type->num_levels)
440706f2543Smrg	     firstClear= type->num_levels;
441706f2543Smrg	else firstClear= new_num_lvls;
442706f2543Smrg	for (i=0;i<nMatchingKeys;i++) {
443706f2543Smrg	    KeySym *	pSyms;
444706f2543Smrg	    int		width,nClear;
445706f2543Smrg
446706f2543Smrg	    key= matchingKeys[i];
447706f2543Smrg	    width= XkbKeyGroupsWidth(xkb,key);
448706f2543Smrg	    nClear= width-firstClear;
449706f2543Smrg	    pSyms= XkbKeySymsPtr(xkb,key);
450706f2543Smrg	    for (g=XkbKeyNumGroups(xkb,key)-1;g>=0;g--) {
451706f2543Smrg		if (XkbKeyKeyTypeIndex(xkb,key,g)==type_ndx) {
452706f2543Smrg		    if (nClear>0)
453706f2543Smrg			memset(&pSyms[g*width+firstClear], 0, nClear*sizeof(KeySym));
454706f2543Smrg		}
455706f2543Smrg	    }
456706f2543Smrg	}
457706f2543Smrg    }
458706f2543Smrg    type->num_levels= new_num_lvls;
459706f2543Smrg    return Success;
460706f2543Smrg}
461706f2543Smrg
462706f2543SmrgKeySym *
463706f2543SmrgXkbResizeKeySyms(XkbDescPtr xkb,int key,int needed)
464706f2543Smrg{
465706f2543Smrgregister int i,nSyms,nKeySyms;
466706f2543Smrgunsigned nOldSyms;
467706f2543SmrgKeySym	*newSyms;
468706f2543Smrg
469706f2543Smrg    if (needed==0) {
470706f2543Smrg	xkb->map->key_sym_map[key].offset= 0;
471706f2543Smrg	return xkb->map->syms;
472706f2543Smrg    }
473706f2543Smrg    nOldSyms= XkbKeyNumSyms(xkb,key);
474706f2543Smrg    if (nOldSyms>=(unsigned)needed) {
475706f2543Smrg	return XkbKeySymsPtr(xkb,key);
476706f2543Smrg    }
477706f2543Smrg    if (xkb->map->size_syms-xkb->map->num_syms>=(unsigned)needed) {
478706f2543Smrg	if (nOldSyms>0) {
479706f2543Smrg	    memcpy(&xkb->map->syms[xkb->map->num_syms],XkbKeySymsPtr(xkb,key),
480706f2543Smrg						nOldSyms*sizeof(KeySym));
481706f2543Smrg	}
482706f2543Smrg	if ((needed-nOldSyms)>0) {
483706f2543Smrg	    memset(&xkb->map->syms[xkb->map->num_syms+XkbKeyNumSyms(xkb, key)],
484706f2543Smrg                   0, (needed-nOldSyms)*sizeof(KeySym));
485706f2543Smrg	}
486706f2543Smrg	xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
487706f2543Smrg	xkb->map->num_syms+= needed;
488706f2543Smrg	return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
489706f2543Smrg    }
490706f2543Smrg    xkb->map->size_syms+= (needed>32?needed:32);
491706f2543Smrg    newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
492706f2543Smrg    if (newSyms==NULL)
493706f2543Smrg	return NULL;
494706f2543Smrg    newSyms[0]= NoSymbol;
495706f2543Smrg    nSyms = 1;
496706f2543Smrg    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
497706f2543Smrg	int nCopy;
498706f2543Smrg
499706f2543Smrg	nCopy= nKeySyms= XkbKeyNumSyms(xkb,i);
500706f2543Smrg	if ((nKeySyms==0)&&(i!=key))
501706f2543Smrg	    continue;
502706f2543Smrg	if (i==key)
503706f2543Smrg	    nKeySyms= needed;
504706f2543Smrg	if (nCopy!=0)
505706f2543Smrg	   memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),nCopy*sizeof(KeySym));
506706f2543Smrg	if (nKeySyms>nCopy)
507706f2543Smrg	    memset(&newSyms[nSyms+nCopy], 0, (nKeySyms-nCopy)*sizeof(KeySym));
508706f2543Smrg	xkb->map->key_sym_map[i].offset = nSyms;
509706f2543Smrg	nSyms+= nKeySyms;
510706f2543Smrg    }
511706f2543Smrg    free(xkb->map->syms);
512706f2543Smrg    xkb->map->syms = newSyms;
513706f2543Smrg    xkb->map->num_syms = nSyms;
514706f2543Smrg    return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
515706f2543Smrg}
516706f2543Smrg
517706f2543Smrgstatic unsigned
518706f2543Smrg_ExtendRange(	unsigned int 	old_flags,
519706f2543Smrg		unsigned int	flag,
520706f2543Smrg		KeyCode		newKC,
521706f2543Smrg		KeyCode *	old_min,
522706f2543Smrg		unsigned char *	old_num)
523706f2543Smrg{
524706f2543Smrg    if ((old_flags&flag)==0) {
525706f2543Smrg	old_flags|= flag;
526706f2543Smrg	*old_min= newKC;
527706f2543Smrg	*old_num= 1;
528706f2543Smrg    }
529706f2543Smrg    else {
530706f2543Smrg	int	last= (*old_min)+(*old_num)-1;
531706f2543Smrg	if (newKC<*old_min) {
532706f2543Smrg	    *old_min= newKC;
533706f2543Smrg	    *old_num= (last-newKC)+1;
534706f2543Smrg	}
535706f2543Smrg	else if (newKC>last) {
536706f2543Smrg	    *old_num= (newKC-(*old_min))+1;
537706f2543Smrg	}
538706f2543Smrg    }
539706f2543Smrg    return old_flags;
540706f2543Smrg}
541706f2543Smrg
542706f2543SmrgStatus
543706f2543SmrgXkbChangeKeycodeRange(	XkbDescPtr	xkb,
544706f2543Smrg			int 		minKC,
545706f2543Smrg			int 		maxKC,
546706f2543Smrg			XkbChangesPtr	changes)
547706f2543Smrg{
548706f2543Smrgint	tmp;
549706f2543Smrg
550706f2543Smrg    if ((!xkb)||(minKC<XkbMinLegalKeyCode)||(maxKC>XkbMaxLegalKeyCode))
551706f2543Smrg	return BadValue;
552706f2543Smrg    if (minKC>maxKC)
553706f2543Smrg	return BadMatch;
554706f2543Smrg    if (minKC<xkb->min_key_code) {
555706f2543Smrg	if (changes)
556706f2543Smrg	    changes->map.min_key_code= minKC;
557706f2543Smrg	tmp= xkb->min_key_code-minKC;
558706f2543Smrg	if (xkb->map)  {
559706f2543Smrg	    if (xkb->map->key_sym_map) {
560706f2543Smrg		memset((char *)&xkb->map->key_sym_map[minKC], 0,
561706f2543Smrg					tmp*sizeof(XkbSymMapRec));
562706f2543Smrg		if (changes) {
563706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
564706f2543Smrg		    				XkbKeySymsMask,minKC,
565706f2543Smrg	    					&changes->map.first_key_sym,
566706f2543Smrg	    					&changes->map.num_key_syms);
567706f2543Smrg		}
568706f2543Smrg	    }
569706f2543Smrg	    if (xkb->map->modmap) {
570706f2543Smrg		memset((char *)&xkb->map->modmap[minKC], 0, tmp);
571706f2543Smrg		if (changes) {
572706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
573706f2543Smrg		    				XkbModifierMapMask,minKC,
574706f2543Smrg	    					&changes->map.first_modmap_key,
575706f2543Smrg	    					&changes->map.num_modmap_keys);
576706f2543Smrg		}
577706f2543Smrg	    }
578706f2543Smrg	}
579706f2543Smrg	if (xkb->server) {
580706f2543Smrg	    if (xkb->server->behaviors) {
581706f2543Smrg		memset((char *)&xkb->server->behaviors[minKC], 0,
582706f2543Smrg						tmp*sizeof(XkbBehavior));
583706f2543Smrg		if (changes) {
584706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
585706f2543Smrg		    			XkbKeyBehaviorsMask,minKC,
586706f2543Smrg    					&changes->map.first_key_behavior,
587706f2543Smrg    					&changes->map.num_key_behaviors);
588706f2543Smrg		}
589706f2543Smrg	    }
590706f2543Smrg	    if (xkb->server->key_acts) {
591706f2543Smrg		memset((char *)&xkb->server->key_acts[minKC], 0,
592706f2543Smrg						tmp*sizeof(unsigned short));
593706f2543Smrg		if (changes) {
594706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
595706f2543Smrg		    			XkbKeyActionsMask,minKC,
596706f2543Smrg    					&changes->map.first_key_act,
597706f2543Smrg    					&changes->map.num_key_acts);
598706f2543Smrg		}
599706f2543Smrg	    }
600706f2543Smrg	    if (xkb->server->vmodmap) {
601706f2543Smrg		memset((char *)&xkb->server->vmodmap[minKC], 0,
602706f2543Smrg						tmp*sizeof(unsigned short));
603706f2543Smrg		if (changes) {
604706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
605706f2543Smrg		    			XkbVirtualModMapMask,minKC,
606706f2543Smrg		    			&changes->map.first_modmap_key,
607706f2543Smrg    					&changes->map.num_vmodmap_keys);
608706f2543Smrg		}
609706f2543Smrg	    }
610706f2543Smrg	}
611706f2543Smrg	if ((xkb->names)&&(xkb->names->keys)) {
612706f2543Smrg	    memset((char *)&xkb->names->keys[minKC], 0, tmp*sizeof(XkbKeyNameRec));
613706f2543Smrg	    if (changes) {
614706f2543Smrg		changes->names.changed= _ExtendRange(changes->names.changed,
615706f2543Smrg					XkbKeyNamesMask,minKC,
616706f2543Smrg					&changes->names.first_key,
617706f2543Smrg    					&changes->names.num_keys);
618706f2543Smrg	    }
619706f2543Smrg	}
620706f2543Smrg	xkb->min_key_code= minKC;
621706f2543Smrg    }
622706f2543Smrg    if (maxKC>xkb->max_key_code) {
623706f2543Smrg	if (changes)
624706f2543Smrg	    changes->map.max_key_code= maxKC;
625706f2543Smrg	tmp= maxKC-xkb->max_key_code;
626706f2543Smrg	if (xkb->map)  {
627706f2543Smrg	    if (xkb->map->key_sym_map) {
628706f2543Smrg		XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
629706f2543Smrg
630706f2543Smrg		xkb->map->key_sym_map = realloc(xkb->map->key_sym_map,
631706f2543Smrg						(maxKC+1) * sizeof(XkbSymMapRec));
632706f2543Smrg		if (!xkb->map->key_sym_map) {
633706f2543Smrg		    free(prev_key_sym_map);
634706f2543Smrg		    return BadAlloc;
635706f2543Smrg		}
636706f2543Smrg		memset((char *)&xkb->map->key_sym_map[xkb->max_key_code], 0,
637706f2543Smrg					tmp*sizeof(XkbSymMapRec));
638706f2543Smrg		if (changes) {
639706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
640706f2543Smrg		    				XkbKeySymsMask,maxKC,
641706f2543Smrg	    					&changes->map.first_key_sym,
642706f2543Smrg	    					&changes->map.num_key_syms);
643706f2543Smrg		}
644706f2543Smrg	    }
645706f2543Smrg	    if (xkb->map->modmap) {
646706f2543Smrg		unsigned char *prev_modmap = xkb->map->modmap;
647706f2543Smrg
648706f2543Smrg		xkb->map->modmap = realloc(xkb->map->modmap,
649706f2543Smrg					    (maxKC+1) * sizeof(unsigned char));
650706f2543Smrg		if (!xkb->map->modmap) {
651706f2543Smrg		    free(prev_modmap);
652706f2543Smrg		    return BadAlloc;
653706f2543Smrg		}
654706f2543Smrg		memset((char *)&xkb->map->modmap[xkb->max_key_code], 0, tmp);
655706f2543Smrg		if (changes) {
656706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
657706f2543Smrg		    				XkbModifierMapMask,maxKC,
658706f2543Smrg	    					&changes->map.first_modmap_key,
659706f2543Smrg	    					&changes->map.num_modmap_keys);
660706f2543Smrg		}
661706f2543Smrg	    }
662706f2543Smrg	}
663706f2543Smrg	if (xkb->server) {
664706f2543Smrg	    if (xkb->server->behaviors) {
665706f2543Smrg		XkbBehavior *prev_behaviors = xkb->server->behaviors;
666706f2543Smrg
667706f2543Smrg		xkb->server->behaviors = realloc(xkb->server->behaviors,
668706f2543Smrg						(maxKC+1) * sizeof(XkbBehavior));
669706f2543Smrg		if (!xkb->server->behaviors) {
670706f2543Smrg		    free(prev_behaviors);
671706f2543Smrg		    return BadAlloc;
672706f2543Smrg		}
673706f2543Smrg		memset((char *)&xkb->server->behaviors[xkb->max_key_code], 0,
674706f2543Smrg						tmp*sizeof(XkbBehavior));
675706f2543Smrg		if (changes) {
676706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
677706f2543Smrg		    			XkbKeyBehaviorsMask,maxKC,
678706f2543Smrg    					&changes->map.first_key_behavior,
679706f2543Smrg    					&changes->map.num_key_behaviors);
680706f2543Smrg		}
681706f2543Smrg	    }
682706f2543Smrg	    if (xkb->server->key_acts) {
683706f2543Smrg		unsigned short *prev_key_acts = xkb->server->key_acts;
684706f2543Smrg
685706f2543Smrg		xkb->server->key_acts= realloc(xkb->server->key_acts,
686706f2543Smrg						(maxKC+1) * sizeof(unsigned short));
687706f2543Smrg		if (!xkb->server->key_acts) {
688706f2543Smrg		    free(prev_key_acts);
689706f2543Smrg		    return BadAlloc;
690706f2543Smrg		}
691706f2543Smrg		memset((char *)&xkb->server->key_acts[xkb->max_key_code], 0,
692706f2543Smrg						tmp*sizeof(unsigned short));
693706f2543Smrg		if (changes) {
694706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
695706f2543Smrg		    			XkbKeyActionsMask,maxKC,
696706f2543Smrg    					&changes->map.first_key_act,
697706f2543Smrg    					&changes->map.num_key_acts);
698706f2543Smrg		}
699706f2543Smrg	    }
700706f2543Smrg	    if (xkb->server->vmodmap) {
701706f2543Smrg		unsigned short *prev_vmodmap = xkb->server->vmodmap;
702706f2543Smrg
703706f2543Smrg		xkb->server->vmodmap= realloc(xkb->server->vmodmap,
704706f2543Smrg						(maxKC+1) * sizeof(unsigned short));
705706f2543Smrg		if (!xkb->server->vmodmap) {
706706f2543Smrg		    free(prev_vmodmap);
707706f2543Smrg		    return BadAlloc;
708706f2543Smrg		}
709706f2543Smrg		memset((char *)&xkb->server->vmodmap[xkb->max_key_code], 0,
710706f2543Smrg						tmp*sizeof(unsigned short));
711706f2543Smrg		if (changes) {
712706f2543Smrg		    changes->map.changed= _ExtendRange(changes->map.changed,
713706f2543Smrg		    			XkbVirtualModMapMask,maxKC,
714706f2543Smrg		    			&changes->map.first_modmap_key,
715706f2543Smrg    					&changes->map.num_vmodmap_keys);
716706f2543Smrg		}
717706f2543Smrg	    }
718706f2543Smrg	}
719706f2543Smrg	if ((xkb->names)&&(xkb->names->keys)) {
720706f2543Smrg	    XkbKeyNameRec *prev_keys = xkb->names->keys;
721706f2543Smrg
722706f2543Smrg	    xkb->names->keys = realloc(xkb->names->keys,
723706f2543Smrg					(maxKC+1) * sizeof(XkbKeyNameRec));
724706f2543Smrg	    if (!xkb->names->keys) {
725706f2543Smrg		free(prev_keys);
726706f2543Smrg		return BadAlloc;
727706f2543Smrg	    }
728706f2543Smrg	    memset((char *)&xkb->names->keys[xkb->max_key_code], 0,
729706f2543Smrg	    					tmp*sizeof(XkbKeyNameRec));
730706f2543Smrg	    if (changes) {
731706f2543Smrg		changes->names.changed= _ExtendRange(changes->names.changed,
732706f2543Smrg					XkbKeyNamesMask,maxKC,
733706f2543Smrg					&changes->names.first_key,
734706f2543Smrg    					&changes->names.num_keys);
735706f2543Smrg	    }
736706f2543Smrg	}
737706f2543Smrg	xkb->max_key_code= maxKC;
738706f2543Smrg    }
739706f2543Smrg    return Success;
740706f2543Smrg}
741706f2543Smrg
742706f2543SmrgXkbAction *
743706f2543SmrgXkbResizeKeyActions(XkbDescPtr xkb,int key,int needed)
744706f2543Smrg{
745706f2543Smrgregister int i,nActs;
746706f2543SmrgXkbAction *newActs;
747706f2543Smrg
748706f2543Smrg    if (needed==0) {
749706f2543Smrg	xkb->server->key_acts[key]= 0;
750706f2543Smrg	return NULL;
751706f2543Smrg    }
752706f2543Smrg    if (XkbKeyHasActions(xkb,key)&&(XkbKeyNumSyms(xkb,key)>=(unsigned)needed))
753706f2543Smrg	return XkbKeyActionsPtr(xkb,key);
754706f2543Smrg    if (xkb->server->size_acts-xkb->server->num_acts>=(unsigned)needed) {
755706f2543Smrg	xkb->server->key_acts[key]= xkb->server->num_acts;
756706f2543Smrg	xkb->server->num_acts+= needed;
757706f2543Smrg	return &xkb->server->acts[xkb->server->key_acts[key]];
758706f2543Smrg    }
759706f2543Smrg    xkb->server->size_acts= xkb->server->num_acts+needed+8;
760706f2543Smrg    newActs = calloc(xkb->server->size_acts, sizeof(XkbAction));
761706f2543Smrg    if (newActs==NULL)
762706f2543Smrg	return NULL;
763706f2543Smrg    newActs[0].type = XkbSA_NoAction;
764706f2543Smrg    nActs = 1;
765706f2543Smrg    for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
766706f2543Smrg	int nKeyActs,nCopy;
767706f2543Smrg
768706f2543Smrg	if ((xkb->server->key_acts[i]==0)&&(i!=key))
769706f2543Smrg	    continue;
770706f2543Smrg
771706f2543Smrg	nCopy= nKeyActs= XkbKeyNumActions(xkb,i);
772706f2543Smrg	if (i==key) {
773706f2543Smrg	    nKeyActs= needed;
774706f2543Smrg	    if (needed<nCopy)
775706f2543Smrg		nCopy= needed;
776706f2543Smrg	}
777706f2543Smrg
778706f2543Smrg	if (nCopy>0)
779706f2543Smrg	    memcpy(&newActs[nActs],XkbKeyActionsPtr(xkb,i),
780706f2543Smrg						nCopy*sizeof(XkbAction));
781706f2543Smrg	if (nCopy<nKeyActs)
782706f2543Smrg	    memset(&newActs[nActs+nCopy], 0, (nKeyActs-nCopy)*sizeof(XkbAction));
783706f2543Smrg	xkb->server->key_acts[i]= nActs;
784706f2543Smrg	nActs+= nKeyActs;
785706f2543Smrg    }
786706f2543Smrg    free(xkb->server->acts);
787706f2543Smrg    xkb->server->acts = newActs;
788706f2543Smrg    xkb->server->num_acts= nActs;
789706f2543Smrg    return &xkb->server->acts[xkb->server->key_acts[key]];
790706f2543Smrg}
791706f2543Smrg
792706f2543Smrgvoid
793706f2543SmrgXkbFreeClientMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
794706f2543Smrg{
795706f2543SmrgXkbClientMapPtr	map;
796706f2543Smrg
797706f2543Smrg    if ((xkb==NULL)||(xkb->map==NULL))
798706f2543Smrg	return;
799706f2543Smrg    if (freeMap)
800706f2543Smrg	what= XkbAllClientInfoMask;
801706f2543Smrg    map= xkb->map;
802706f2543Smrg    if (what&XkbKeyTypesMask) {
803706f2543Smrg	if (map->types!=NULL) {
804706f2543Smrg	    if (map->num_types>0) {
805706f2543Smrg		register int 	i;
806706f2543Smrg		XkbKeyTypePtr	type;
807706f2543Smrg		for (i=0,type=map->types;i<map->num_types;i++,type++) {
808706f2543Smrg		    free(type->map);
809706f2543Smrg		    type->map = NULL;
810706f2543Smrg		    free(type->preserve);
811706f2543Smrg		    type->preserve = NULL;
812706f2543Smrg		    type->map_count= 0;
813706f2543Smrg		    free(type->level_names);
814706f2543Smrg		    type->level_names = NULL;
815706f2543Smrg		}
816706f2543Smrg	    }
817706f2543Smrg	    free(map->types);
818706f2543Smrg	    map->num_types= map->size_types= 0;
819706f2543Smrg	    map->types= NULL;
820706f2543Smrg	}
821706f2543Smrg    }
822706f2543Smrg    if (what&XkbKeySymsMask) {
823706f2543Smrg	free(map->key_sym_map);
824706f2543Smrg	map->key_sym_map = NULL;
825706f2543Smrg	if (map->syms!=NULL) {
826706f2543Smrg	    free(map->syms);
827706f2543Smrg	    map->size_syms= map->num_syms= 0;
828706f2543Smrg	    map->syms= NULL;
829706f2543Smrg	}
830706f2543Smrg    }
831706f2543Smrg    if ((what&XkbModifierMapMask)&&(map->modmap!=NULL)) {
832706f2543Smrg	free(map->modmap);
833706f2543Smrg	map->modmap= NULL;
834706f2543Smrg    }
835706f2543Smrg    if (freeMap) {
836706f2543Smrg	free(xkb->map);
837706f2543Smrg	xkb->map= NULL;
838706f2543Smrg    }
839706f2543Smrg    return;
840706f2543Smrg}
841706f2543Smrg
842706f2543Smrgvoid
843706f2543SmrgXkbFreeServerMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
844706f2543Smrg{
845706f2543SmrgXkbServerMapPtr	map;
846706f2543Smrg
847706f2543Smrg    if ((xkb==NULL)||(xkb->server==NULL))
848706f2543Smrg	return;
849706f2543Smrg    if (freeMap)
850706f2543Smrg	what= XkbAllServerInfoMask;
851706f2543Smrg    map= xkb->server;
852706f2543Smrg    if ((what&XkbExplicitComponentsMask)&&(map->explicit!=NULL)) {
853706f2543Smrg	free(map->explicit);
854706f2543Smrg	map->explicit= NULL;
855706f2543Smrg    }
856706f2543Smrg    if (what&XkbKeyActionsMask) {
857706f2543Smrg	free(map->key_acts);
858706f2543Smrg	map->key_acts = NULL;
859706f2543Smrg	if (map->acts!=NULL) {
860706f2543Smrg	    free(map->acts);
861706f2543Smrg	    map->num_acts= map->size_acts= 0;
862706f2543Smrg	    map->acts= NULL;
863706f2543Smrg	}
864706f2543Smrg    }
865706f2543Smrg    if ((what&XkbKeyBehaviorsMask)&&(map->behaviors!=NULL)) {
866706f2543Smrg	free(map->behaviors);
867706f2543Smrg	map->behaviors= NULL;
868706f2543Smrg    }
869706f2543Smrg    if ((what&XkbVirtualModMapMask)&&(map->vmodmap!=NULL)) {
870706f2543Smrg	free(map->vmodmap);
871706f2543Smrg	map->vmodmap= NULL;
872706f2543Smrg    }
873706f2543Smrg
874706f2543Smrg    if (freeMap) {
875706f2543Smrg	free(xkb->server);
876706f2543Smrg	xkb->server= NULL;
877706f2543Smrg    }
878706f2543Smrg    return;
879706f2543Smrg}
880