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