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