XKBMAlloc.c revision cf2acdde
11ab64890Smrg/************************************************************
21ab64890SmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
31ab64890Smrg
41ab64890SmrgPermission to use, copy, modify, and distribute this
51ab64890Smrgsoftware and its documentation for any purpose and without
61ab64890Smrgfee is hereby granted, provided that the above copyright
71ab64890Smrgnotice appear in all copies and that both that copyright
81ab64890Smrgnotice and this permission notice appear in supporting
961b2299dSmrgdocumentation, and that the name of Silicon Graphics not be
1061b2299dSmrgused in advertising or publicity pertaining to distribution
111ab64890Smrgof the software without specific prior written permission.
1261b2299dSmrgSilicon Graphics makes no representation about the suitability
131ab64890Smrgof this software for any purpose. It is provided "as is"
141ab64890Smrgwithout any express or implied warranty.
151ab64890Smrg
1661b2299dSmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1761b2299dSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
181ab64890SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
1961b2299dSmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2061b2299dSmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2161b2299dSmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
221ab64890SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
231ab64890SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
241ab64890Smrg
251ab64890Smrg********************************************************/
261ab64890Smrg
27818534a1Smrg#ifdef HAVE_CONFIG_H
281ab64890Smrg#include <config.h>
291ab64890Smrg#endif
301ab64890Smrg
311ab64890Smrg
321ab64890Smrg#include <stdio.h>
331ab64890Smrg#include "Xlibint.h"
341ab64890Smrg#include <X11/extensions/XKBproto.h>
351ab64890Smrg#include <X11/keysym.h>
361ab64890Smrg#include "XKBlibint.h"
371ab64890Smrg
381ab64890Smrg
391ab64890Smrg/***====================================================================***/
401ab64890Smrg
411ab64890SmrgStatus
42818534a1SmrgXkbAllocClientMap(XkbDescPtr xkb, unsigned which, unsigned nTotalTypes)
431ab64890Smrg{
44818534a1Smrg    register int i;
45818534a1Smrg    XkbClientMapPtr map;
46818534a1Smrg
47818534a1Smrg    if ((xkb == NULL) ||
48818534a1Smrg        ((nTotalTypes > 0) && (nTotalTypes < XkbNumRequiredTypes)))
49818534a1Smrg        return BadValue;
50818534a1Smrg    if ((which & XkbKeySymsMask) &&
51818534a1Smrg        ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
52818534a1Smrg         (!XkbIsLegalKeycode(xkb->max_key_code)) ||
53818534a1Smrg         (xkb->max_key_code < xkb->min_key_code))) {
541ab64890Smrg#ifdef DEBUG
55818534a1Smrg        fprintf(stderr, "bad keycode (%d,%d) in XkbAllocClientMap\n",
56818534a1Smrg                xkb->min_key_code, xkb->max_key_code);
571ab64890Smrg#endif
58818534a1Smrg        return BadValue;
59818534a1Smrg    }
60818534a1Smrg
61818534a1Smrg    if (xkb->map == NULL) {
62818534a1Smrg        map = _XkbTypedCalloc(1, XkbClientMapRec);
63818534a1Smrg        if (map == NULL)
64818534a1Smrg            return BadAlloc;
65818534a1Smrg        xkb->map = map;
66818534a1Smrg    }
67818534a1Smrg    else
68818534a1Smrg        map = xkb->map;
69818534a1Smrg
70818534a1Smrg    if ((which & XkbKeyTypesMask) && (nTotalTypes > 0)) {
71818534a1Smrg        if (map->types == NULL) {
72818534a1Smrg            map->types = _XkbTypedCalloc(nTotalTypes, XkbKeyTypeRec);
73818534a1Smrg            if (map->types == NULL)
74818534a1Smrg                return BadAlloc;
75818534a1Smrg            map->num_types = 0;
76818534a1Smrg            map->size_types = nTotalTypes;
77818534a1Smrg        }
78818534a1Smrg        else if (map->size_types < nTotalTypes) {
79818534a1Smrg            XkbKeyTypeRec *prev_types = map->types;
80818534a1Smrg
81818534a1Smrg            map->types =
82818534a1Smrg                _XkbTypedRealloc(map->types, nTotalTypes, XkbKeyTypeRec);
83818534a1Smrg            if (map->types == NULL) {
84818534a1Smrg                _XkbFree(prev_types);
85818534a1Smrg                map->num_types = map->size_types = 0;
86818534a1Smrg                return BadAlloc;
87818534a1Smrg            }
88818534a1Smrg            map->size_types = nTotalTypes;
89818534a1Smrg            bzero(&map->types[map->num_types],
90818534a1Smrg                  ((map->size_types - map->num_types) * sizeof(XkbKeyTypeRec)));
91818534a1Smrg        }
92818534a1Smrg    }
93818534a1Smrg    if (which & XkbKeySymsMask) {
94818534a1Smrg        int nKeys = XkbNumKeys(xkb);
95818534a1Smrg
96818534a1Smrg        if (map->syms == NULL) {
97818534a1Smrg            map->size_syms = (nKeys * 15) / 10;
98818534a1Smrg            map->syms = _XkbTypedCalloc(map->size_syms, KeySym);
99818534a1Smrg            if (!map->syms) {
100818534a1Smrg                map->size_syms = 0;
101818534a1Smrg                return BadAlloc;
102818534a1Smrg            }
103818534a1Smrg            map->num_syms = 1;
104818534a1Smrg            map->syms[0] = NoSymbol;
105818534a1Smrg        }
106818534a1Smrg        if (map->key_sym_map == NULL) {
107818534a1Smrg            i = xkb->max_key_code + 1;
108818534a1Smrg            map->key_sym_map = _XkbTypedCalloc(i, XkbSymMapRec);
109818534a1Smrg            if (map->key_sym_map == NULL)
110818534a1Smrg                return BadAlloc;
111818534a1Smrg        }
112818534a1Smrg    }
113818534a1Smrg    if (which & XkbModifierMapMask) {
114818534a1Smrg        if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
115818534a1Smrg            (!XkbIsLegalKeycode(xkb->max_key_code)) ||
116818534a1Smrg            (xkb->max_key_code < xkb->min_key_code))
117818534a1Smrg            return BadMatch;
118818534a1Smrg        if (map->modmap == NULL) {
119818534a1Smrg            i = xkb->max_key_code + 1;
120818534a1Smrg            map->modmap = _XkbTypedCalloc(i, unsigned char);
121818534a1Smrg            if (map->modmap == NULL)
122818534a1Smrg                return BadAlloc;
123818534a1Smrg        }
1241ab64890Smrg    }
1251ab64890Smrg    return Success;
1261ab64890Smrg}
1271ab64890Smrg
1281ab64890SmrgStatus
129818534a1SmrgXkbAllocServerMap(XkbDescPtr xkb, unsigned which, unsigned nNewActions)
1301ab64890Smrg{
131818534a1Smrg    register int i;
132818534a1Smrg    XkbServerMapPtr map;
133818534a1Smrg
134818534a1Smrg    if (xkb == NULL)
135818534a1Smrg        return BadMatch;
136818534a1Smrg    if (xkb->server == NULL) {
137818534a1Smrg        map = _XkbTypedCalloc(1, XkbServerMapRec);
138818534a1Smrg        if (map == NULL)
139818534a1Smrg            return BadAlloc;
140818534a1Smrg        for (i = 0; i < XkbNumVirtualMods; i++) {
141818534a1Smrg            map->vmods[i] = XkbNoModifierMask;
142818534a1Smrg        }
143818534a1Smrg        xkb->server = map;
144818534a1Smrg    }
145818534a1Smrg    else
146818534a1Smrg        map = xkb->server;
147818534a1Smrg    if (which & XkbExplicitComponentsMask) {
148818534a1Smrg        if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
149818534a1Smrg            (!XkbIsLegalKeycode(xkb->max_key_code)) ||
150818534a1Smrg            (xkb->max_key_code < xkb->min_key_code))
151818534a1Smrg            return BadMatch;
152818534a1Smrg        if (map->explicit == NULL) {
153818534a1Smrg            i = xkb->max_key_code + 1;
154818534a1Smrg            map->explicit = _XkbTypedCalloc(i, unsigned char);
155818534a1Smrg            if (map->explicit == NULL)
156818534a1Smrg                return BadAlloc;
157818534a1Smrg        }
158818534a1Smrg    }
159818534a1Smrg    if (which & XkbKeyActionsMask) {
160818534a1Smrg        if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
161818534a1Smrg            (!XkbIsLegalKeycode(xkb->max_key_code)) ||
162818534a1Smrg            (xkb->max_key_code < xkb->min_key_code))
163818534a1Smrg            return BadMatch;
164818534a1Smrg        if (nNewActions < 1)
165818534a1Smrg            nNewActions = 1;
166818534a1Smrg        if (map->acts == NULL) {
167818534a1Smrg            map->acts = _XkbTypedCalloc((nNewActions + 1), XkbAction);
168818534a1Smrg            if (map->acts == NULL)
169818534a1Smrg                return BadAlloc;
170818534a1Smrg            map->num_acts = 1;
171818534a1Smrg            map->size_acts = nNewActions + 1;
172818534a1Smrg        }
173818534a1Smrg        else if ((map->size_acts - map->num_acts) < nNewActions) {
174818534a1Smrg            unsigned need;
175818534a1Smrg            XkbAction *prev_acts = map->acts;
176818534a1Smrg
177818534a1Smrg            need = map->num_acts + nNewActions;
178818534a1Smrg            map->acts = _XkbTypedRealloc(map->acts, need, XkbAction);
179818534a1Smrg            if (map->acts == NULL) {
180818534a1Smrg                _XkbFree(prev_acts);
181818534a1Smrg                map->num_acts = map->size_acts = 0;
182818534a1Smrg                return BadAlloc;
183818534a1Smrg            }
184818534a1Smrg            map->size_acts = need;
185818534a1Smrg            bzero(&map->acts[map->num_acts],
186818534a1Smrg                  ((map->size_acts - map->num_acts) * sizeof(XkbAction)));
187818534a1Smrg        }
188818534a1Smrg        if (map->key_acts == NULL) {
189818534a1Smrg            i = xkb->max_key_code + 1;
190818534a1Smrg            map->key_acts = _XkbTypedCalloc(i, unsigned short);
191818534a1Smrg            if (map->key_acts == NULL)
192818534a1Smrg                return BadAlloc;
193818534a1Smrg        }
194818534a1Smrg    }
195818534a1Smrg    if (which & XkbKeyBehaviorsMask) {
196818534a1Smrg        if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
197818534a1Smrg            (!XkbIsLegalKeycode(xkb->max_key_code)) ||
198818534a1Smrg            (xkb->max_key_code < xkb->min_key_code))
199818534a1Smrg            return BadMatch;
200818534a1Smrg        if (map->behaviors == NULL) {
201818534a1Smrg            i = xkb->max_key_code + 1;
202818534a1Smrg            map->behaviors = _XkbTypedCalloc(i, XkbBehavior);
203818534a1Smrg            if (map->behaviors == NULL)
204818534a1Smrg                return BadAlloc;
205818534a1Smrg        }
206818534a1Smrg    }
207818534a1Smrg    if (which & XkbVirtualModMapMask) {
208818534a1Smrg        if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
209818534a1Smrg            (!XkbIsLegalKeycode(xkb->max_key_code)) ||
210818534a1Smrg            (xkb->max_key_code < xkb->min_key_code))
211818534a1Smrg            return BadMatch;
212818534a1Smrg        if (map->vmodmap == NULL) {
213818534a1Smrg            i = xkb->max_key_code + 1;
214818534a1Smrg            map->vmodmap = _XkbTypedCalloc(i, unsigned short);
215818534a1Smrg            if (map->vmodmap == NULL)
216818534a1Smrg                return BadAlloc;
217818534a1Smrg        }
2181ab64890Smrg    }
2191ab64890Smrg    return Success;
2201ab64890Smrg}
2211ab64890Smrg
2221ab64890Smrg/***====================================================================***/
2231ab64890Smrg
2241ab64890SmrgStatus
225818534a1SmrgXkbCopyKeyType(XkbKeyTypePtr from, XkbKeyTypePtr into)
2261ab64890Smrg{
227818534a1Smrg    if ((!from) || (!into))
228818534a1Smrg        return BadMatch;
229cf2acddeSmrg
230cf2acddeSmrg    _XkbFree(into->map);
231cf2acddeSmrg    into->map = NULL;
232cf2acddeSmrg
233cf2acddeSmrg    _XkbFree(into->preserve);
234cf2acddeSmrg    into->preserve = NULL;
235cf2acddeSmrg
236cf2acddeSmrg    _XkbFree(into->level_names);
237cf2acddeSmrg    into->level_names = NULL;
238cf2acddeSmrg
239818534a1Smrg    *into = *from;
240818534a1Smrg    if ((from->map) && (into->map_count > 0)) {
241818534a1Smrg        into->map = _XkbTypedCalloc(into->map_count, XkbKTMapEntryRec);
242818534a1Smrg        if (!into->map)
243818534a1Smrg            return BadAlloc;
244818534a1Smrg        memcpy(into->map, from->map,
245818534a1Smrg               into->map_count * sizeof(XkbKTMapEntryRec));
246818534a1Smrg    }
247818534a1Smrg    if ((from->preserve) && (into->map_count > 0)) {
248818534a1Smrg        into->preserve = _XkbTypedCalloc(into->map_count, XkbModsRec);
249818534a1Smrg        if (!into->preserve)
250818534a1Smrg            return BadAlloc;
251818534a1Smrg        memcpy(into->preserve, from->preserve,
252818534a1Smrg               into->map_count * sizeof(XkbModsRec));
253818534a1Smrg    }
254818534a1Smrg    if ((from->level_names) && (into->num_levels > 0)) {
255818534a1Smrg        into->level_names = _XkbTypedCalloc(into->num_levels, Atom);
256818534a1Smrg        if (!into->level_names)
257818534a1Smrg            return BadAlloc;
258818534a1Smrg        memcpy(into->level_names, from->level_names,
259818534a1Smrg               into->num_levels * sizeof(Atom));
2601ab64890Smrg    }
2611ab64890Smrg    return Success;
2621ab64890Smrg}
2631ab64890Smrg
2641ab64890SmrgStatus
265818534a1SmrgXkbCopyKeyTypes(XkbKeyTypePtr from, XkbKeyTypePtr into, int num_types)
2661ab64890Smrg{
267818534a1Smrg    register int i, rtrn;
2681ab64890Smrg
269818534a1Smrg    if ((!from) || (!into) || (num_types < 0))
270818534a1Smrg        return BadMatch;
271818534a1Smrg    for (i = 0; i < num_types; i++) {
272818534a1Smrg        if ((rtrn = XkbCopyKeyType(from++, into++)) != Success)
273818534a1Smrg            return rtrn;
2741ab64890Smrg    }
2751ab64890Smrg    return Success;
2761ab64890Smrg}
2771ab64890Smrg
2781ab64890SmrgXkbKeyTypePtr
279818534a1SmrgXkbAddKeyType(XkbDescPtr xkb,
280818534a1Smrg              Atom name,
281818534a1Smrg              int map_count,
282818534a1Smrg              Bool want_preserve,
283818534a1Smrg              int num_lvls)
2841ab64890Smrg{
285818534a1Smrg    register int i;
286818534a1Smrg    unsigned tmp;
287818534a1Smrg    XkbKeyTypePtr type;
288818534a1Smrg    XkbClientMapPtr map;
289818534a1Smrg
290818534a1Smrg    if ((!xkb) || (num_lvls < 1))
291818534a1Smrg        return NULL;
292818534a1Smrg    map = xkb->map;
293818534a1Smrg    if ((map) && (map->types)) {
294818534a1Smrg        for (i = 0; i < map->num_types; i++) {
295818534a1Smrg            if (map->types[i].name == name) {
296818534a1Smrg                Status status =
297818534a1Smrg                    XkbResizeKeyType(xkb, i, map_count, want_preserve,
298818534a1Smrg                                     num_lvls);
299818534a1Smrg                return (status == Success ? &map->types[i] : NULL);
300818534a1Smrg            }
301818534a1Smrg        }
302818534a1Smrg    }
303cf2acddeSmrg    if ((!map) || (!map->types) || (map->num_types < XkbNumRequiredTypes)) {
304818534a1Smrg        tmp = XkbNumRequiredTypes + 1;
305818534a1Smrg        if (XkbAllocClientMap(xkb, XkbKeyTypesMask, tmp) != Success)
306818534a1Smrg            return NULL;
3071ab64890Smrg        if (!map)
3081ab64890Smrg            map = xkb->map;
309818534a1Smrg        tmp = 0;
310818534a1Smrg        if (map->num_types <= XkbKeypadIndex)
311818534a1Smrg            tmp |= XkbKeypadMask;
312818534a1Smrg        if (map->num_types <= XkbAlphabeticIndex)
313818534a1Smrg            tmp |= XkbAlphabeticMask;
314818534a1Smrg        if (map->num_types <= XkbTwoLevelIndex)
315818534a1Smrg            tmp |= XkbTwoLevelMask;
316818534a1Smrg        if (map->num_types <= XkbOneLevelIndex)
317818534a1Smrg            tmp |= XkbOneLevelMask;
318818534a1Smrg        if (XkbInitCanonicalKeyTypes(xkb, tmp, XkbNoModifier) == Success) {
319818534a1Smrg            for (i = 0; i < map->num_types; i++) {
320818534a1Smrg                Status status;
321818534a1Smrg
322818534a1Smrg                if (map->types[i].name != name)
323818534a1Smrg                    continue;
324818534a1Smrg                status = XkbResizeKeyType(xkb, i, map_count, want_preserve,
325818534a1Smrg                                          num_lvls);
326818534a1Smrg                return (status == Success ? &map->types[i] : NULL);
327818534a1Smrg            }
328818534a1Smrg        }
329818534a1Smrg    }
330818534a1Smrg    if ((map->num_types <= map->size_types) &&
331818534a1Smrg        (XkbAllocClientMap(xkb, XkbKeyTypesMask, map->num_types + 1) !=
332818534a1Smrg         Success)) {
333818534a1Smrg        return NULL;
334818534a1Smrg    }
335818534a1Smrg    type = &map->types[map->num_types];
3361ab64890Smrg    map->num_types++;
337818534a1Smrg    bzero((char *) type, sizeof(XkbKeyTypeRec));
338818534a1Smrg    type->num_levels = num_lvls;
339818534a1Smrg    type->map_count = map_count;
340818534a1Smrg    type->name = name;
341818534a1Smrg    if (map_count > 0) {
342818534a1Smrg        type->map = _XkbTypedCalloc(map_count, XkbKTMapEntryRec);
343818534a1Smrg        if (!type->map) {
344818534a1Smrg            map->num_types--;
345818534a1Smrg            return NULL;
346818534a1Smrg        }
347818534a1Smrg        if (want_preserve) {
348818534a1Smrg            type->preserve = _XkbTypedCalloc(map_count, XkbModsRec);
349818534a1Smrg            if (!type->preserve) {
350818534a1Smrg                _XkbFree(type->map);
351818534a1Smrg                map->num_types--;
352818534a1Smrg                return NULL;
353818534a1Smrg            }
354818534a1Smrg        }
3551ab64890Smrg    }
3561ab64890Smrg    return type;
3571ab64890Smrg}
3581ab64890Smrg
3591ab64890SmrgStatus
360818534a1SmrgXkbResizeKeyType(XkbDescPtr xkb,
361818534a1Smrg                 int type_ndx,
362818534a1Smrg                 int map_count,
363818534a1Smrg                 Bool want_preserve,
364818534a1Smrg                 int new_num_lvls)
3651ab64890Smrg{
366818534a1Smrg    XkbKeyTypePtr type;
367818534a1Smrg    KeyCode matchingKeys[XkbMaxKeyCount], nMatchingKeys;
3681ab64890Smrg
369818534a1Smrg    if ((type_ndx < 0) || (type_ndx >= xkb->map->num_types) || (map_count < 0)
370818534a1Smrg        || (new_num_lvls < 1))
371818534a1Smrg        return BadValue;
3721ab64890Smrg    switch (type_ndx) {
373818534a1Smrg    case XkbOneLevelIndex:
374818534a1Smrg        if (new_num_lvls != 1)
375818534a1Smrg            return BadMatch;
376818534a1Smrg        break;
377818534a1Smrg    case XkbTwoLevelIndex:
378818534a1Smrg    case XkbAlphabeticIndex:
379818534a1Smrg    case XkbKeypadIndex:
380818534a1Smrg        if (new_num_lvls != 2)
381818534a1Smrg            return BadMatch;
382818534a1Smrg        break;
383818534a1Smrg    }
384818534a1Smrg    type = &xkb->map->types[type_ndx];
385818534a1Smrg    if (map_count == 0) {
386cf2acddeSmrg        _XkbFree(type->map);
387818534a1Smrg        type->map = NULL;
388cf2acddeSmrg        _XkbFree(type->preserve);
389818534a1Smrg        type->preserve = NULL;
390818534a1Smrg        type->map_count = 0;
3911ab64890Smrg    }
3921ab64890Smrg    else {
393818534a1Smrg        XkbKTMapEntryRec *prev_map = type->map;
394818534a1Smrg
395818534a1Smrg        if ((map_count > type->map_count) || (type->map == NULL))
396818534a1Smrg            type->map =
397818534a1Smrg                _XkbTypedRealloc(type->map, map_count, XkbKTMapEntryRec);
398818534a1Smrg        if (!type->map) {
399cf2acddeSmrg            _XkbFree(prev_map);
400818534a1Smrg            return BadAlloc;
401818534a1Smrg        }
402818534a1Smrg        if (want_preserve) {
403818534a1Smrg            XkbModsRec *prev_preserve = type->preserve;
404818534a1Smrg
405818534a1Smrg            if ((map_count > type->map_count) || (type->preserve == NULL)) {
406818534a1Smrg                type->preserve = _XkbTypedRealloc(type->preserve, map_count,
407818534a1Smrg                                                  XkbModsRec);
408818534a1Smrg            }
409818534a1Smrg            if (!type->preserve) {
410cf2acddeSmrg                _XkbFree(prev_preserve);
411818534a1Smrg                return BadAlloc;
412818534a1Smrg            }
413818534a1Smrg        }
414cf2acddeSmrg        else {
415818534a1Smrg            _XkbFree(type->preserve);
416818534a1Smrg            type->preserve = NULL;
417818534a1Smrg        }
418818534a1Smrg        type->map_count = map_count;
419818534a1Smrg    }
420818534a1Smrg
421818534a1Smrg    if ((new_num_lvls > type->num_levels) || (type->level_names == NULL)) {
422818534a1Smrg        Atom *prev_level_names = type->level_names;
423818534a1Smrg
424818534a1Smrg        type->level_names =
425818534a1Smrg            _XkbTypedRealloc(type->level_names, new_num_lvls, Atom);
426818534a1Smrg        if (!type->level_names) {
427cf2acddeSmrg            _XkbFree(prev_level_names);
428818534a1Smrg            return BadAlloc;
429818534a1Smrg        }
4301ab64890Smrg    }
4311ab64890Smrg    /*
4321ab64890Smrg     * Here's the theory:
4331ab64890Smrg     *    If the width of the type changed, we might have to resize the symbol
4341ab64890Smrg     * maps for any keys that use the type for one or more groups.  This is
4351ab64890Smrg     * expensive, so we'll try to cull out any keys that are obviously okay:
4361ab64890Smrg     * In any case:
4371ab64890Smrg     *    - keys that have a group width <= the old width are okay (because
4381ab64890Smrg     *      they could not possibly have been associated with the old type)
4391ab64890Smrg     * If the key type increased in size:
4401ab64890Smrg     *    - keys that already have a group width >= to the new width are okay
4411ab64890Smrg     *    + keys that have a group width >= the old width but < the new width
4421ab64890Smrg     *      might have to be enlarged.
4431ab64890Smrg     * If the key type decreased in size:
4441ab64890Smrg     *    - keys that have a group width > the old width don't have to be
44561b2299dSmrg     *      resized (because they must have some other wider type associated
4461ab64890Smrg     *      with some group).
4471ab64890Smrg     *    + keys that have a group width == the old width might have to be
4481ab64890Smrg     *      shrunk.
4491ab64890Smrg     * The possibilities marked with '+' require us to examine the key types
4501ab64890Smrg     * associated with each group for the key.
4511ab64890Smrg     */
452818534a1Smrg    bzero(matchingKeys, XkbMaxKeyCount * sizeof(KeyCode));
453818534a1Smrg    nMatchingKeys = 0;
454818534a1Smrg    if (new_num_lvls > type->num_levels) {
455818534a1Smrg        int nTotal;
456818534a1Smrg        KeySym *newSyms;
457818534a1Smrg        int width, match, nResize;
458818534a1Smrg        register int i, g, nSyms;
459818534a1Smrg
460818534a1Smrg        nResize = 0;
461818534a1Smrg        for (nTotal = 1, i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
462818534a1Smrg            width = XkbKeyGroupsWidth(xkb, i);
463818534a1Smrg            if (width < type->num_levels)
464818534a1Smrg                continue;
465818534a1Smrg            for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
466818534a1Smrg                 (g >= 0) && (!match); g--) {
467818534a1Smrg                if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
468818534a1Smrg                    matchingKeys[nMatchingKeys++] = i;
469818534a1Smrg                    match = 1;
470818534a1Smrg                }
471818534a1Smrg            }
472818534a1Smrg            if ((!match) || (width >= new_num_lvls))
473818534a1Smrg                nTotal += XkbKeyNumSyms(xkb, i);
474818534a1Smrg            else {
475818534a1Smrg                nTotal += XkbKeyNumGroups(xkb, i) * new_num_lvls;
476818534a1Smrg                nResize++;
477818534a1Smrg            }
478818534a1Smrg        }
479818534a1Smrg        if (nResize > 0) {
480818534a1Smrg            int nextMatch;
481818534a1Smrg
482818534a1Smrg            xkb->map->size_syms = (nTotal * 12) / 10;
483818534a1Smrg            newSyms = _XkbTypedCalloc(xkb->map->size_syms, KeySym);
484818534a1Smrg            if (newSyms == NULL)
485818534a1Smrg                return BadAlloc;
486818534a1Smrg            nextMatch = 0;
487818534a1Smrg            nSyms = 1;
488818534a1Smrg            for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
489818534a1Smrg                if (matchingKeys[nextMatch] == i) {
490818534a1Smrg                    KeySym *pOld;
491818534a1Smrg
492818534a1Smrg                    nextMatch++;
493818534a1Smrg                    width = XkbKeyGroupsWidth(xkb, i);
494818534a1Smrg                    pOld = XkbKeySymsPtr(xkb, i);
495818534a1Smrg                    for (g = XkbKeyNumGroups(xkb, i) - 1; g >= 0; g--) {
496818534a1Smrg                        memcpy(&newSyms[nSyms + (new_num_lvls * g)],
497818534a1Smrg                               &pOld[width * g], width * sizeof(KeySym));
498818534a1Smrg                    }
499818534a1Smrg                    xkb->map->key_sym_map[i].offset = nSyms;
500818534a1Smrg                    nSyms += XkbKeyNumGroups(xkb, i) * new_num_lvls;
501818534a1Smrg                }
502818534a1Smrg                else {
503818534a1Smrg                    memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
504818534a1Smrg                           XkbKeyNumSyms(xkb, i) * sizeof(KeySym));
505818534a1Smrg                    xkb->map->key_sym_map[i].offset = nSyms;
506818534a1Smrg                    nSyms += XkbKeyNumSyms(xkb, i);
507818534a1Smrg                }
508818534a1Smrg            }
509818534a1Smrg            type->num_levels = new_num_lvls;
510818534a1Smrg            _XkbFree(xkb->map->syms);
511818534a1Smrg            xkb->map->syms = newSyms;
512818534a1Smrg            xkb->map->num_syms = nSyms;
513818534a1Smrg            return Success;
514818534a1Smrg        }
515818534a1Smrg    }
516818534a1Smrg    else if (new_num_lvls < type->num_levels) {
517818534a1Smrg        int width, match;
518818534a1Smrg        register int g, i;
519818534a1Smrg
520818534a1Smrg        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
521818534a1Smrg            width = XkbKeyGroupsWidth(xkb, i);
522818534a1Smrg            if (width < type->num_levels)
523818534a1Smrg                continue;
524818534a1Smrg            for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
525818534a1Smrg                 (g >= 0) && (!match); g--) {
526818534a1Smrg                if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
527818534a1Smrg                    matchingKeys[nMatchingKeys++] = i;
528818534a1Smrg                    match = 1;
529818534a1Smrg                }
530818534a1Smrg            }
531818534a1Smrg        }
532818534a1Smrg    }
533818534a1Smrg    if (nMatchingKeys > 0) {
534818534a1Smrg        int key, firstClear;
535818534a1Smrg        register int i, g;
536818534a1Smrg
537818534a1Smrg        if (new_num_lvls > type->num_levels)
538818534a1Smrg            firstClear = type->num_levels;
539818534a1Smrg        else
540818534a1Smrg            firstClear = new_num_lvls;
541818534a1Smrg        for (i = 0; i < nMatchingKeys; i++) {
542818534a1Smrg            KeySym *pSyms;
543818534a1Smrg            int width, nClear;
544818534a1Smrg
545818534a1Smrg            key = matchingKeys[i];
546818534a1Smrg            width = XkbKeyGroupsWidth(xkb, key);
547818534a1Smrg            nClear = width - firstClear;
548818534a1Smrg            pSyms = XkbKeySymsPtr(xkb, key);
549818534a1Smrg            for (g = XkbKeyNumGroups(xkb, key) - 1; g >= 0; g--) {
550818534a1Smrg                if (XkbKeyKeyTypeIndex(xkb, key, g) == type_ndx) {
551818534a1Smrg                    if (nClear > 0)
552818534a1Smrg                        bzero(&pSyms[g * width + firstClear],
553818534a1Smrg                              nClear * sizeof(KeySym));
554818534a1Smrg                }
555818534a1Smrg            }
556818534a1Smrg        }
557818534a1Smrg    }
558818534a1Smrg    type->num_levels = new_num_lvls;
5591ab64890Smrg    return Success;
5601ab64890Smrg}
5611ab64890Smrg
5621ab64890SmrgKeySym *
563818534a1SmrgXkbResizeKeySyms(XkbDescPtr xkb, int key, int needed)
5641ab64890Smrg{
565818534a1Smrg    register int i, nSyms, nKeySyms;
566818534a1Smrg    unsigned nOldSyms;
567818534a1Smrg    KeySym *newSyms;
568818534a1Smrg
569818534a1Smrg    if (needed == 0) {
570818534a1Smrg        xkb->map->key_sym_map[key].offset = 0;
571818534a1Smrg        return xkb->map->syms;
572818534a1Smrg    }
573818534a1Smrg    nOldSyms = XkbKeyNumSyms(xkb, key);
574818534a1Smrg    if (nOldSyms >= (unsigned) needed) {
575818534a1Smrg        return XkbKeySymsPtr(xkb, key);
576818534a1Smrg    }
577818534a1Smrg    if (xkb->map->size_syms - xkb->map->num_syms >= (unsigned) needed) {
578818534a1Smrg        if (nOldSyms > 0) {
579818534a1Smrg            memcpy(&xkb->map->syms[xkb->map->num_syms], XkbKeySymsPtr(xkb, key),
580818534a1Smrg                   nOldSyms * sizeof(KeySym));
581818534a1Smrg        }
582818534a1Smrg        if ((needed - nOldSyms) > 0) {
583818534a1Smrg            bzero(&xkb->map->syms[xkb->map->num_syms + XkbKeyNumSyms(xkb, key)],
584818534a1Smrg                  (needed - nOldSyms) * sizeof(KeySym));
585818534a1Smrg        }
586818534a1Smrg        xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
587818534a1Smrg        xkb->map->num_syms += needed;
588818534a1Smrg        return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
589818534a1Smrg    }
590818534a1Smrg    xkb->map->size_syms += (needed > 32 ? needed : 32);
591818534a1Smrg    newSyms = _XkbTypedCalloc(xkb->map->size_syms, KeySym);
592818534a1Smrg    if (newSyms == NULL)
593818534a1Smrg        return NULL;
594818534a1Smrg    newSyms[0] = NoSymbol;
5951ab64890Smrg    nSyms = 1;
596818534a1Smrg    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
597818534a1Smrg        int nCopy;
598818534a1Smrg
599818534a1Smrg        nCopy = nKeySyms = XkbKeyNumSyms(xkb, i);
600818534a1Smrg        if ((nKeySyms == 0) && (i != key))
601818534a1Smrg            continue;
602818534a1Smrg        if (i == key)
603818534a1Smrg            nKeySyms = needed;
604818534a1Smrg        if (nCopy != 0)
605818534a1Smrg            memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
606818534a1Smrg                   nCopy * sizeof(KeySym));
607818534a1Smrg        if (nKeySyms > nCopy)
608818534a1Smrg            bzero(&newSyms[nSyms + nCopy], (nKeySyms - nCopy) * sizeof(KeySym));
609818534a1Smrg        xkb->map->key_sym_map[i].offset = nSyms;
610818534a1Smrg        nSyms += nKeySyms;
6111ab64890Smrg    }
6121ab64890Smrg    _XkbFree(xkb->map->syms);
6131ab64890Smrg    xkb->map->syms = newSyms;
6141ab64890Smrg    xkb->map->num_syms = nSyms;
6151ab64890Smrg    return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
6161ab64890Smrg}
6171ab64890Smrg
6181ab64890Smrgstatic unsigned
619818534a1Smrg_ExtendRange(unsigned int old_flags,
620818534a1Smrg             unsigned int flag,
621818534a1Smrg             KeyCode newKC,
622818534a1Smrg             KeyCode *old_min,
623818534a1Smrg             unsigned char *old_num)
6241ab64890Smrg{
625818534a1Smrg    if ((old_flags & flag) == 0) {
626818534a1Smrg        old_flags |= flag;
627818534a1Smrg        *old_min = newKC;
628818534a1Smrg        *old_num = 1;
6291ab64890Smrg    }
6301ab64890Smrg    else {
631818534a1Smrg        int last = (*old_min) + (*old_num) - 1;
632818534a1Smrg
633818534a1Smrg        if (newKC < *old_min) {
634818534a1Smrg            *old_min = newKC;
635818534a1Smrg            *old_num = (last - newKC) + 1;
636818534a1Smrg        }
637818534a1Smrg        else if (newKC > last) {
638818534a1Smrg            *old_num = (newKC - (*old_min)) + 1;
639818534a1Smrg        }
6401ab64890Smrg    }
6411ab64890Smrg    return old_flags;
6421ab64890Smrg}
6431ab64890Smrg
6441ab64890SmrgStatus
645818534a1SmrgXkbChangeKeycodeRange(XkbDescPtr xkb,
646818534a1Smrg                      int minKC,
647818534a1Smrg                      int maxKC,
648818534a1Smrg                      XkbChangesPtr changes)
6491ab64890Smrg{
650818534a1Smrg    int tmp;
651818534a1Smrg
652818534a1Smrg    if ((!xkb) || (minKC < XkbMinLegalKeyCode) || (maxKC > XkbMaxLegalKeyCode))
653818534a1Smrg        return BadValue;
654818534a1Smrg    if (minKC > maxKC)
655818534a1Smrg        return BadMatch;
656818534a1Smrg    if (minKC < xkb->min_key_code) {
657818534a1Smrg        if (changes)
658818534a1Smrg            changes->map.min_key_code = minKC;
659818534a1Smrg        tmp = xkb->min_key_code - minKC;
660818534a1Smrg        if (xkb->map) {
661818534a1Smrg            if (xkb->map->key_sym_map) {
662818534a1Smrg                bzero((char *) &xkb->map->key_sym_map[minKC],
663818534a1Smrg                      tmp * sizeof(XkbSymMapRec));
664818534a1Smrg                if (changes) {
665818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
666818534a1Smrg                                                XkbKeySymsMask, minKC,
667818534a1Smrg                                                &changes->map.first_key_sym,
668818534a1Smrg                                                &changes->map.num_key_syms);
669818534a1Smrg                }
670818534a1Smrg            }
671818534a1Smrg            if (xkb->map->modmap) {
672818534a1Smrg                bzero((char *) &xkb->map->modmap[minKC], tmp);
673818534a1Smrg                if (changes) {
674818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
675818534a1Smrg                                                XkbModifierMapMask, minKC,
676818534a1Smrg                                                &changes->map.first_modmap_key,
677818534a1Smrg                                                &changes->map.num_modmap_keys);
678818534a1Smrg                }
679818534a1Smrg            }
680818534a1Smrg        }
681818534a1Smrg        if (xkb->server) {
682818534a1Smrg            if (xkb->server->behaviors) {
683818534a1Smrg                bzero((char *) &xkb->server->behaviors[minKC],
684818534a1Smrg                      tmp * sizeof(XkbBehavior));
685818534a1Smrg                if (changes) {
686818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
687818534a1Smrg                                              XkbKeyBehaviorsMask, minKC,
688818534a1Smrg                                              &changes->map.first_key_behavior,
689818534a1Smrg                                              &changes->map.num_key_behaviors);
690818534a1Smrg                }
691818534a1Smrg            }
692818534a1Smrg            if (xkb->server->key_acts) {
693818534a1Smrg                bzero((char *) &xkb->server->key_acts[minKC],
694818534a1Smrg                      tmp * sizeof(unsigned short));
695818534a1Smrg                if (changes) {
696818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
697818534a1Smrg                                                XkbKeyActionsMask, minKC,
698818534a1Smrg                                                &changes->map.first_key_act,
699818534a1Smrg                                                &changes->map.num_key_acts);
700818534a1Smrg                }
701818534a1Smrg            }
702818534a1Smrg            if (xkb->server->vmodmap) {
703818534a1Smrg                bzero((char *) &xkb->server->vmodmap[minKC],
704818534a1Smrg                      tmp * sizeof(unsigned short));
705818534a1Smrg                if (changes) {
706818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
707818534a1Smrg                                                XkbVirtualModMapMask, minKC,
708818534a1Smrg                                                &changes->map.first_modmap_key,
709818534a1Smrg                                                &changes->map.num_vmodmap_keys);
710818534a1Smrg                }
711818534a1Smrg            }
712818534a1Smrg        }
713818534a1Smrg        if ((xkb->names) && (xkb->names->keys)) {
714818534a1Smrg            bzero((char *) &xkb->names->keys[minKC],
715818534a1Smrg                  tmp * sizeof(XkbKeyNameRec));
716818534a1Smrg            if (changes) {
717818534a1Smrg                changes->names.changed = _ExtendRange(changes->names.changed,
718818534a1Smrg                                                      XkbKeyNamesMask, minKC,
719818534a1Smrg                                                      &changes->names.first_key,
720818534a1Smrg                                                      &changes->names.num_keys);
721818534a1Smrg            }
722818534a1Smrg        }
723818534a1Smrg        xkb->min_key_code = minKC;
724818534a1Smrg    }
725818534a1Smrg    if (maxKC > xkb->max_key_code) {
726818534a1Smrg        if (changes)
727818534a1Smrg            changes->map.max_key_code = maxKC;
728818534a1Smrg        tmp = maxKC - xkb->max_key_code;
729818534a1Smrg        if (xkb->map) {
730818534a1Smrg            if (xkb->map->key_sym_map) {
731818534a1Smrg                XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
732818534a1Smrg
733818534a1Smrg                xkb->map->key_sym_map = _XkbTypedRealloc(xkb->map->key_sym_map,
734818534a1Smrg                                                    (maxKC + 1), XkbSymMapRec);
735818534a1Smrg                if (!xkb->map->key_sym_map) {
736818534a1Smrg                    _XkbFree(prev_key_sym_map);
737818534a1Smrg                    return BadAlloc;
738818534a1Smrg                }
739818534a1Smrg                bzero((char *) &xkb->map->key_sym_map[xkb->max_key_code],
740818534a1Smrg                      tmp * sizeof(XkbSymMapRec));
741818534a1Smrg                if (changes) {
742818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
743818534a1Smrg                                                XkbKeySymsMask, maxKC,
744818534a1Smrg                                                &changes->map.first_key_sym,
745818534a1Smrg                                                &changes->map.num_key_syms);
746818534a1Smrg                }
747818534a1Smrg            }
748818534a1Smrg            if (xkb->map->modmap) {
749818534a1Smrg                unsigned char *prev_modmap = xkb->map->modmap;
750818534a1Smrg
751818534a1Smrg                xkb->map->modmap = _XkbTypedRealloc(xkb->map->modmap,
752818534a1Smrg                                                    (maxKC + 1), unsigned char);
753818534a1Smrg                if (!xkb->map->modmap) {
754818534a1Smrg                    _XkbFree(prev_modmap);
755818534a1Smrg                    return BadAlloc;
756818534a1Smrg                }
757818534a1Smrg                bzero((char *) &xkb->map->modmap[xkb->max_key_code], tmp);
758818534a1Smrg                if (changes) {
759818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
760818534a1Smrg                                                XkbModifierMapMask, maxKC,
761818534a1Smrg                                                &changes->map.first_modmap_key,
762818534a1Smrg                                                &changes->map.num_modmap_keys);
763818534a1Smrg                }
764818534a1Smrg            }
765818534a1Smrg        }
766818534a1Smrg        if (xkb->server) {
767818534a1Smrg            if (xkb->server->behaviors) {
768818534a1Smrg                XkbBehavior *prev_behaviors = xkb->server->behaviors;
769818534a1Smrg
770818534a1Smrg                xkb->server->behaviors =
771818534a1Smrg                    _XkbTypedRealloc(xkb->server->behaviors, (maxKC + 1),
772818534a1Smrg                                     XkbBehavior);
773818534a1Smrg                if (!xkb->server->behaviors) {
774818534a1Smrg                    _XkbFree(prev_behaviors);
775818534a1Smrg                    return BadAlloc;
776818534a1Smrg                }
777818534a1Smrg                bzero((char *) &xkb->server->behaviors[xkb->max_key_code],
778818534a1Smrg                      tmp * sizeof(XkbBehavior));
779818534a1Smrg                if (changes) {
780818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
781818534a1Smrg                                                XkbKeyBehaviorsMask, maxKC,
782818534a1Smrg                                                &changes->map.first_key_behavior,
783818534a1Smrg                                                &changes->map.num_key_behaviors);
784818534a1Smrg                }
785818534a1Smrg            }
786818534a1Smrg            if (xkb->server->key_acts) {
787818534a1Smrg                unsigned short *prev_key_acts = xkb->server->key_acts;
788818534a1Smrg
789818534a1Smrg                xkb->server->key_acts = _XkbTypedRealloc(xkb->server->key_acts,
790818534a1Smrg                                                (maxKC + 1), unsigned short);
791818534a1Smrg                if (!xkb->server->key_acts) {
792818534a1Smrg                    _XkbFree(prev_key_acts);
793818534a1Smrg                    return BadAlloc;
794818534a1Smrg                }
795818534a1Smrg                bzero((char *) &xkb->server->key_acts[xkb->max_key_code],
796818534a1Smrg                      tmp * sizeof(unsigned short));
797818534a1Smrg                if (changes) {
798818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
799818534a1Smrg                                                XkbKeyActionsMask, maxKC,
800818534a1Smrg                                                &changes->map.first_key_act,
801818534a1Smrg                                                &changes->map.num_key_acts);
802818534a1Smrg                }
803818534a1Smrg            }
804818534a1Smrg            if (xkb->server->vmodmap) {
805818534a1Smrg                unsigned short *prev_vmodmap = xkb->server->vmodmap;
806818534a1Smrg
807818534a1Smrg                xkb->server->vmodmap = _XkbTypedRealloc(xkb->server->vmodmap,
808818534a1Smrg                                                (maxKC + 1), unsigned short);
809818534a1Smrg                if (!xkb->server->vmodmap) {
810818534a1Smrg                    _XkbFree(prev_vmodmap);
811818534a1Smrg                    return BadAlloc;
812818534a1Smrg                }
813818534a1Smrg                bzero((char *) &xkb->server->vmodmap[xkb->max_key_code],
814818534a1Smrg                      tmp * sizeof(unsigned short));
815818534a1Smrg                if (changes) {
816818534a1Smrg                    changes->map.changed = _ExtendRange(changes->map.changed,
817818534a1Smrg                                                XkbVirtualModMapMask, maxKC,
818818534a1Smrg                                                &changes->map.first_modmap_key,
819818534a1Smrg                                                &changes->map.num_vmodmap_keys);
820818534a1Smrg                }
821818534a1Smrg            }
822818534a1Smrg        }
823818534a1Smrg        if ((xkb->names) && (xkb->names->keys)) {
824818534a1Smrg            XkbKeyNameRec *prev_keys = xkb->names->keys;
825818534a1Smrg
826818534a1Smrg            xkb->names->keys = _XkbTypedRealloc(xkb->names->keys,
827818534a1Smrg                                                (maxKC + 1), XkbKeyNameRec);
828818534a1Smrg            if (!xkb->names->keys) {
829818534a1Smrg                _XkbFree(prev_keys);
830818534a1Smrg                return BadAlloc;
831818534a1Smrg            }
832818534a1Smrg            bzero((char *) &xkb->names->keys[xkb->max_key_code],
833818534a1Smrg                  tmp * sizeof(XkbKeyNameRec));
834818534a1Smrg            if (changes) {
835818534a1Smrg                changes->names.changed = _ExtendRange(changes->names.changed,
836818534a1Smrg                                                      XkbKeyNamesMask, maxKC,
837818534a1Smrg                                                      &changes->names.first_key,
838818534a1Smrg                                                      &changes->names.num_keys);
839818534a1Smrg            }
840818534a1Smrg        }
841818534a1Smrg        xkb->max_key_code = maxKC;
8421ab64890Smrg    }
8431ab64890Smrg    return Success;
8441ab64890Smrg}
8451ab64890Smrg
8461ab64890SmrgXkbAction *
847818534a1SmrgXkbResizeKeyActions(XkbDescPtr xkb, int key, int needed)
8481ab64890Smrg{
849818534a1Smrg    register int i, nActs;
850818534a1Smrg    XkbAction *newActs;
851818534a1Smrg
852818534a1Smrg    if (needed == 0) {
853818534a1Smrg        xkb->server->key_acts[key] = 0;
854818534a1Smrg        return NULL;
855818534a1Smrg    }
856818534a1Smrg    if (XkbKeyHasActions(xkb, key) &&
857818534a1Smrg        (XkbKeyNumSyms(xkb, key) >= (unsigned) needed))
858818534a1Smrg        return XkbKeyActionsPtr(xkb, key);
859818534a1Smrg    if (xkb->server->size_acts - xkb->server->num_acts >= (unsigned) needed) {
860818534a1Smrg        xkb->server->key_acts[key] = xkb->server->num_acts;
861818534a1Smrg        xkb->server->num_acts += needed;
862818534a1Smrg        return &xkb->server->acts[xkb->server->key_acts[key]];
863818534a1Smrg    }
864818534a1Smrg    xkb->server->size_acts = xkb->server->num_acts + needed + 8;
865818534a1Smrg    newActs = _XkbTypedCalloc(xkb->server->size_acts, XkbAction);
866818534a1Smrg    if (newActs == NULL)
867818534a1Smrg        return NULL;
8681ab64890Smrg    newActs[0].type = XkbSA_NoAction;
8691ab64890Smrg    nActs = 1;
870818534a1Smrg    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
871818534a1Smrg        int nKeyActs, nCopy;
872818534a1Smrg
873818534a1Smrg        if ((xkb->server->key_acts[i] == 0) && (i != key))
874818534a1Smrg            continue;
875818534a1Smrg
876818534a1Smrg        nCopy = nKeyActs = XkbKeyNumActions(xkb, i);
877818534a1Smrg        if (i == key) {
878818534a1Smrg            nKeyActs = needed;
879818534a1Smrg            if (needed < nCopy)
880818534a1Smrg                nCopy = needed;
881818534a1Smrg        }
882818534a1Smrg
883818534a1Smrg        if (nCopy > 0)
884818534a1Smrg            memcpy(&newActs[nActs], XkbKeyActionsPtr(xkb, i),
885818534a1Smrg                   nCopy * sizeof(XkbAction));
886818534a1Smrg        if (nCopy < nKeyActs)
887818534a1Smrg            bzero(&newActs[nActs + nCopy],
888818534a1Smrg                  (nKeyActs - nCopy) * sizeof(XkbAction));
889818534a1Smrg        xkb->server->key_acts[i] = nActs;
890818534a1Smrg        nActs += nKeyActs;
8911ab64890Smrg    }
8921ab64890Smrg    _XkbFree(xkb->server->acts);
8931ab64890Smrg    xkb->server->acts = newActs;
894818534a1Smrg    xkb->server->num_acts = nActs;
8951ab64890Smrg    return &xkb->server->acts[xkb->server->key_acts[key]];
8961ab64890Smrg}
8971ab64890Smrg
8981ab64890Smrgvoid
899818534a1SmrgXkbFreeClientMap(XkbDescPtr xkb, unsigned what, Bool freeMap)
9001ab64890Smrg{
901818534a1Smrg    XkbClientMapPtr map;
9021ab64890Smrg
903818534a1Smrg    if ((xkb == NULL) || (xkb->map == NULL))
904818534a1Smrg        return;
9051ab64890Smrg    if (freeMap)
906818534a1Smrg        what = XkbAllClientInfoMask;
907818534a1Smrg    map = xkb->map;
908818534a1Smrg    if (what & XkbKeyTypesMask) {
909818534a1Smrg        if (map->types != NULL) {
910818534a1Smrg            if (map->num_types > 0) {
911818534a1Smrg                register int i;
912818534a1Smrg                XkbKeyTypePtr type;
913818534a1Smrg
914818534a1Smrg                for (i = 0, type = map->types; i < map->num_types; i++, type++) {
915cf2acddeSmrg                    _XkbFree(type->map);
916cf2acddeSmrg                    type->map = NULL;
917cf2acddeSmrg
918cf2acddeSmrg                    _XkbFree(type->preserve);
919cf2acddeSmrg                    type->preserve = NULL;
920cf2acddeSmrg
921818534a1Smrg                    type->map_count = 0;
922cf2acddeSmrg
923cf2acddeSmrg                    _XkbFree(type->level_names);
924cf2acddeSmrg                    type->level_names = NULL;
925818534a1Smrg                }
926818534a1Smrg            }
927818534a1Smrg            _XkbFree(map->types);
928818534a1Smrg            map->num_types = map->size_types = 0;
929818534a1Smrg            map->types = NULL;
930818534a1Smrg        }
931818534a1Smrg    }
932818534a1Smrg    if (what & XkbKeySymsMask) {
933cf2acddeSmrg        _XkbFree(map->key_sym_map);
934cf2acddeSmrg        map->key_sym_map = NULL;
935cf2acddeSmrg
936cf2acddeSmrg        _XkbFree(map->syms);
937cf2acddeSmrg        map->size_syms = map->num_syms = 0;
938cf2acddeSmrg        map->syms = NULL;
939818534a1Smrg    }
940cf2acddeSmrg    if (what & XkbModifierMapMask) {
941818534a1Smrg        _XkbFree(map->modmap);
942818534a1Smrg        map->modmap = NULL;
9431ab64890Smrg    }
9441ab64890Smrg    if (freeMap) {
945818534a1Smrg        _XkbFree(xkb->map);
946818534a1Smrg        xkb->map = NULL;
9471ab64890Smrg    }
9481ab64890Smrg    return;
9491ab64890Smrg}
9501ab64890Smrg
9511ab64890Smrgvoid
952818534a1SmrgXkbFreeServerMap(XkbDescPtr xkb, unsigned what, Bool freeMap)
9531ab64890Smrg{
954818534a1Smrg    XkbServerMapPtr map;
9551ab64890Smrg
956818534a1Smrg    if ((xkb == NULL) || (xkb->server == NULL))
957818534a1Smrg        return;
9581ab64890Smrg    if (freeMap)
959818534a1Smrg        what = XkbAllServerInfoMask;
960818534a1Smrg    map = xkb->server;
961cf2acddeSmrg    if (what & XkbExplicitComponentsMask) {
962818534a1Smrg        _XkbFree(map->explicit);
963818534a1Smrg        map->explicit = NULL;
964818534a1Smrg    }
965818534a1Smrg    if (what & XkbKeyActionsMask) {
966cf2acddeSmrg           _XkbFree(map->key_acts);
967818534a1Smrg            map->key_acts = NULL;
968cf2acddeSmrg
969cf2acddeSmrg           _XkbFree(map->acts);
970818534a1Smrg            map->num_acts = map->size_acts = 0;
971818534a1Smrg            map->acts = NULL;
972818534a1Smrg    }
973cf2acddeSmrg    if (what & XkbKeyBehaviorsMask) {
974818534a1Smrg        _XkbFree(map->behaviors);
975818534a1Smrg        map->behaviors = NULL;
976818534a1Smrg    }
977cf2acddeSmrg    if (what & XkbVirtualModMapMask)  {
978818534a1Smrg        _XkbFree(map->vmodmap);
979818534a1Smrg        map->vmodmap = NULL;
9801ab64890Smrg    }
9811ab64890Smrg
9821ab64890Smrg    if (freeMap) {
983818534a1Smrg        _XkbFree(xkb->server);
984818534a1Smrg        xkb->server = NULL;
9851ab64890Smrg    }
9861ab64890Smrg    return;
9871ab64890Smrg}
988