933 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			933 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
| /************************************************************
 | |
| Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this
 | |
| software and its documentation for any purpose and without
 | |
| fee is hereby granted, provided that the above copyright
 | |
| notice appear in all copies and that both that copyright
 | |
| notice and this permission notice appear in supporting
 | |
| documentation, and that the name of Silicon Graphics not be
 | |
| used in advertising or publicity pertaining to distribution
 | |
| of the software without specific prior written permission.
 | |
| Silicon Graphics makes no representation about the suitability
 | |
| of this software for any purpose. It is provided "as is"
 | |
| without any express or implied warranty.
 | |
| 
 | |
| SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 | |
| SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 | |
| AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
 | |
| GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 | |
| DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
| DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 | |
| OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
 | |
| THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
| ********************************************************/
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #elif defined(HAVE_CONFIG_H)
 | |
| #include <config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include "misc.h"
 | |
| #include "inputstr.h"
 | |
| #include <X11/keysym.h>
 | |
| #define	XKBSRV_NEED_FILE_FUNCS
 | |
| #include <xkbsrv.h>
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| Status
 | |
| XkbAllocClientMap(XkbDescPtr xkb, unsigned which, unsigned nTotalTypes)
 | |
| {
 | |
|     register int i;
 | |
|     XkbClientMapPtr map;
 | |
| 
 | |
|     if ((xkb == NULL) ||
 | |
|         ((nTotalTypes > 0) && (nTotalTypes < XkbNumRequiredTypes)))
 | |
|         return BadValue;
 | |
|     if ((which & XkbKeySymsMask) &&
 | |
|         ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
 | |
|          (!XkbIsLegalKeycode(xkb->max_key_code)) ||
 | |
|          (xkb->max_key_code < xkb->min_key_code))) {
 | |
|         DebugF("bad keycode (%d,%d) in XkbAllocClientMap\n",
 | |
|                xkb->min_key_code, xkb->max_key_code);
 | |
|         return BadValue;
 | |
|     }
 | |
| 
 | |
|     if (xkb->map == NULL) {
 | |
|         map = calloc(1, sizeof(XkbClientMapRec));
 | |
|         if (map == NULL)
 | |
|             return BadAlloc;
 | |
|         xkb->map = map;
 | |
|     }
 | |
|     else
 | |
|         map = xkb->map;
 | |
| 
 | |
|     if ((which & XkbKeyTypesMask) && (nTotalTypes > 0)) {
 | |
|         if (map->types == NULL) {
 | |
|             map->types = calloc(nTotalTypes, sizeof(XkbKeyTypeRec));
 | |
|             if (map->types == NULL)
 | |
|                 return BadAlloc;
 | |
|             map->num_types = 0;
 | |
|             map->size_types = nTotalTypes;
 | |
|         }
 | |
|         else if (map->size_types < nTotalTypes) {
 | |
|             XkbKeyTypeRec *prev_types = map->types;
 | |
| 
 | |
|             map->types =
 | |
|                 realloc(map->types, nTotalTypes * sizeof(XkbKeyTypeRec));
 | |
|             if (map->types == NULL) {
 | |
|                 free(prev_types);
 | |
|                 map->num_types = map->size_types = 0;
 | |
|                 return BadAlloc;
 | |
|             }
 | |
|             map->size_types = nTotalTypes;
 | |
|             memset(&map->types[map->num_types], 0,
 | |
|                    ((map->size_types -
 | |
|                      map->num_types) * sizeof(XkbKeyTypeRec)));
 | |
|         }
 | |
|     }
 | |
|     if (which & XkbKeySymsMask) {
 | |
|         int nKeys = XkbNumKeys(xkb);
 | |
| 
 | |
|         if (map->syms == NULL) {
 | |
|             map->size_syms = (nKeys * 15) / 10;
 | |
|             map->syms = calloc(map->size_syms, sizeof(KeySym));
 | |
|             if (!map->syms) {
 | |
|                 map->size_syms = 0;
 | |
|                 return BadAlloc;
 | |
|             }
 | |
|             map->num_syms = 1;
 | |
|             map->syms[0] = NoSymbol;
 | |
|         }
 | |
|         if (map->key_sym_map == NULL) {
 | |
|             i = xkb->max_key_code + 1;
 | |
|             map->key_sym_map = calloc(i, sizeof(XkbSymMapRec));
 | |
|             if (map->key_sym_map == NULL)
 | |
|                 return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     if (which & XkbModifierMapMask) {
 | |
|         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
 | |
|             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
 | |
|             (xkb->max_key_code < xkb->min_key_code))
 | |
|             return BadMatch;
 | |
|         if (map->modmap == NULL) {
 | |
|             i = xkb->max_key_code + 1;
 | |
|             map->modmap = calloc(i, sizeof(unsigned char));
 | |
|             if (map->modmap == NULL)
 | |
|                 return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| Status
 | |
| XkbAllocServerMap(XkbDescPtr xkb, unsigned which, unsigned nNewActions)
 | |
| {
 | |
|     register int i;
 | |
|     XkbServerMapPtr map;
 | |
| 
 | |
|     if (xkb == NULL)
 | |
|         return BadMatch;
 | |
|     if (xkb->server == NULL) {
 | |
|         map = calloc(1, sizeof(XkbServerMapRec));
 | |
|         if (map == NULL)
 | |
|             return BadAlloc;
 | |
|         for (i = 0; i < XkbNumVirtualMods; i++) {
 | |
|             map->vmods[i] = XkbNoModifierMask;
 | |
|         }
 | |
|         xkb->server = map;
 | |
|     }
 | |
|     else
 | |
|         map = xkb->server;
 | |
|     if (which & XkbExplicitComponentsMask) {
 | |
|         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
 | |
|             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
 | |
|             (xkb->max_key_code < xkb->min_key_code))
 | |
|             return BadMatch;
 | |
|         if (map->explicit == NULL) {
 | |
|             i = xkb->max_key_code + 1;
 | |
|             map->explicit = calloc(i, sizeof(unsigned char));
 | |
|             if (map->explicit == NULL)
 | |
|                 return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     if (which & XkbKeyActionsMask) {
 | |
|         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
 | |
|             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
 | |
|             (xkb->max_key_code < xkb->min_key_code))
 | |
|             return BadMatch;
 | |
|         if (nNewActions < 1)
 | |
|             nNewActions = 1;
 | |
|         if (map->acts == NULL) {
 | |
|             map->acts = calloc((nNewActions + 1), sizeof(XkbAction));
 | |
|             if (map->acts == NULL)
 | |
|                 return BadAlloc;
 | |
|             map->num_acts = 1;
 | |
|             map->size_acts = nNewActions + 1;
 | |
|         }
 | |
|         else if ((map->size_acts - map->num_acts) < nNewActions) {
 | |
|             unsigned need;
 | |
|             XkbAction *prev_acts = map->acts;
 | |
| 
 | |
|             need = map->num_acts + nNewActions;
 | |
|             map->acts = realloc(map->acts, need * sizeof(XkbAction));
 | |
|             if (map->acts == NULL) {
 | |
|                 free(prev_acts);
 | |
|                 map->num_acts = map->size_acts = 0;
 | |
|                 return BadAlloc;
 | |
|             }
 | |
|             map->size_acts = need;
 | |
|             memset(&map->acts[map->num_acts], 0,
 | |
|                    ((map->size_acts - map->num_acts) * sizeof(XkbAction)));
 | |
|         }
 | |
|         if (map->key_acts == NULL) {
 | |
|             i = xkb->max_key_code + 1;
 | |
|             map->key_acts = calloc(i, sizeof(unsigned short));
 | |
|             if (map->key_acts == NULL)
 | |
|                 return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     if (which & XkbKeyBehaviorsMask) {
 | |
|         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
 | |
|             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
 | |
|             (xkb->max_key_code < xkb->min_key_code))
 | |
|             return BadMatch;
 | |
|         if (map->behaviors == NULL) {
 | |
|             i = xkb->max_key_code + 1;
 | |
|             map->behaviors = calloc(i, sizeof(XkbBehavior));
 | |
|             if (map->behaviors == NULL)
 | |
|                 return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     if (which & XkbVirtualModMapMask) {
 | |
|         if ((!XkbIsLegalKeycode(xkb->min_key_code)) ||
 | |
|             (!XkbIsLegalKeycode(xkb->max_key_code)) ||
 | |
|             (xkb->max_key_code < xkb->min_key_code))
 | |
|             return BadMatch;
 | |
|         if (map->vmodmap == NULL) {
 | |
|             i = xkb->max_key_code + 1;
 | |
|             map->vmodmap = calloc(i, sizeof(unsigned short));
 | |
|             if (map->vmodmap == NULL)
 | |
|                 return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| static Status
 | |
| XkbCopyKeyType(XkbKeyTypePtr from, XkbKeyTypePtr into)
 | |
| {
 | |
|     if ((!from) || (!into))
 | |
|         return BadMatch;
 | |
|     free(into->map);
 | |
|     into->map = NULL;
 | |
|     free(into->preserve);
 | |
|     into->preserve = NULL;
 | |
|     free(into->level_names);
 | |
|     into->level_names = NULL;
 | |
|     *into = *from;
 | |
|     if ((from->map) && (into->map_count > 0)) {
 | |
|         into->map = calloc(into->map_count, sizeof(XkbKTMapEntryRec));
 | |
|         if (!into->map)
 | |
|             return BadAlloc;
 | |
|         memcpy(into->map, from->map,
 | |
|                into->map_count * sizeof(XkbKTMapEntryRec));
 | |
|     }
 | |
|     if ((from->preserve) && (into->map_count > 0)) {
 | |
|         into->preserve = calloc(into->map_count, sizeof(XkbModsRec));
 | |
|         if (!into->preserve)
 | |
|             return BadAlloc;
 | |
|         memcpy(into->preserve, from->preserve,
 | |
|                into->map_count * sizeof(XkbModsRec));
 | |
|     }
 | |
|     if ((from->level_names) && (into->num_levels > 0)) {
 | |
|         into->level_names = calloc(into->num_levels, sizeof(Atom));
 | |
|         if (!into->level_names)
 | |
|             return BadAlloc;
 | |
|         memcpy(into->level_names, from->level_names,
 | |
|                into->num_levels * sizeof(Atom));
 | |
|     }
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| Status
 | |
| XkbCopyKeyTypes(XkbKeyTypePtr from, XkbKeyTypePtr into, int num_types)
 | |
| {
 | |
|     register int i, rtrn;
 | |
| 
 | |
|     if ((!from) || (!into) || (num_types < 0))
 | |
|         return BadMatch;
 | |
|     for (i = 0; i < num_types; i++) {
 | |
|         if ((rtrn = XkbCopyKeyType(from++, into++)) != Success)
 | |
|             return rtrn;
 | |
|     }
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| Status
 | |
| XkbResizeKeyType(XkbDescPtr xkb,
 | |
|                  int type_ndx,
 | |
|                  int map_count, Bool want_preserve, int new_num_lvls)
 | |
| {
 | |
|     XkbKeyTypePtr type;
 | |
|     KeyCode matchingKeys[XkbMaxKeyCount], nMatchingKeys;
 | |
| 
 | |
|     if ((type_ndx < 0) || (type_ndx >= xkb->map->num_types) || (map_count < 0)
 | |
|         || (new_num_lvls < 1))
 | |
|         return BadValue;
 | |
|     switch (type_ndx) {
 | |
|     case XkbOneLevelIndex:
 | |
|         if (new_num_lvls != 1)
 | |
|             return BadMatch;
 | |
|         break;
 | |
|     case XkbTwoLevelIndex:
 | |
|     case XkbAlphabeticIndex:
 | |
|     case XkbKeypadIndex:
 | |
|         if (new_num_lvls != 2)
 | |
|             return BadMatch;
 | |
|         break;
 | |
|     }
 | |
|     type = &xkb->map->types[type_ndx];
 | |
|     if (map_count == 0) {
 | |
|         free(type->map);
 | |
|         type->map = NULL;
 | |
|         free(type->preserve);
 | |
|         type->preserve = NULL;
 | |
|         type->map_count = 0;
 | |
|     }
 | |
|     else {
 | |
|         XkbKTMapEntryRec *prev_map = type->map;
 | |
| 
 | |
|         if ((map_count > type->map_count) || (type->map == NULL))
 | |
|             type->map =
 | |
|                 realloc(type->map, map_count * sizeof(XkbKTMapEntryRec));
 | |
|         if (!type->map) {
 | |
|             free(prev_map);
 | |
|             return BadAlloc;
 | |
|         }
 | |
|         if (want_preserve) {
 | |
|             XkbModsRec *prev_preserve = type->preserve;
 | |
| 
 | |
|             if ((map_count > type->map_count) || (type->preserve == NULL)) {
 | |
|                 type->preserve = realloc(type->preserve,
 | |
|                                          map_count * sizeof(XkbModsRec));
 | |
|             }
 | |
|             if (!type->preserve) {
 | |
|                 free(prev_preserve);
 | |
|                 return BadAlloc;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             free(type->preserve);
 | |
|             type->preserve = NULL;
 | |
|         }
 | |
|         type->map_count = map_count;
 | |
|     }
 | |
| 
 | |
|     if ((new_num_lvls > type->num_levels) || (type->level_names == NULL)) {
 | |
|         Atom *prev_level_names = type->level_names;
 | |
| 
 | |
|         type->level_names = realloc(type->level_names,
 | |
|                                     new_num_lvls * sizeof(Atom));
 | |
|         if (!type->level_names) {
 | |
|             free(prev_level_names);
 | |
|             return BadAlloc;
 | |
|         }
 | |
|     }
 | |
|     /*
 | |
|      * Here's the theory:
 | |
|      *    If the width of the type changed, we might have to resize the symbol
 | |
|      * maps for any keys that use the type for one or more groups.  This is
 | |
|      * expensive, so we'll try to cull out any keys that are obviously okay:
 | |
|      * In any case:
 | |
|      *    - keys that have a group width <= the old width are okay (because
 | |
|      *      they could not possibly have been associated with the old type)
 | |
|      * If the key type increased in size:
 | |
|      *    - keys that already have a group width >= to the new width are okay
 | |
|      *    + keys that have a group width >= the old width but < the new width
 | |
|      *      might have to be enlarged.
 | |
|      * If the key type decreased in size:
 | |
|      *    - keys that have a group width > the old width don't have to be
 | |
|      *      resized (because they must have some other wider type associated
 | |
|      *      with some group).
 | |
|      *    + keys that have a group width == the old width might have to be
 | |
|      *      shrunk.
 | |
|      * The possibilities marked with '+' require us to examine the key types
 | |
|      * associated with each group for the key.
 | |
|      */
 | |
|     memset(matchingKeys, 0, XkbMaxKeyCount * sizeof(KeyCode));
 | |
|     nMatchingKeys = 0;
 | |
|     if (new_num_lvls > type->num_levels) {
 | |
|         int nTotal;
 | |
|         KeySym *newSyms;
 | |
|         int width, match, nResize;
 | |
|         register int i, g, nSyms;
 | |
| 
 | |
|         nResize = 0;
 | |
|         for (nTotal = 1, i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
 | |
|             width = XkbKeyGroupsWidth(xkb, i);
 | |
|             if (width < type->num_levels || width >= new_num_lvls) {
 | |
|                 nTotal += XkbKeyNumSyms(xkb,i);
 | |
|                 continue;
 | |
|             }
 | |
|             for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
 | |
|                  (g >= 0) && (!match); g--) {
 | |
|                 if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
 | |
|                     matchingKeys[nMatchingKeys++] = i;
 | |
|                     match = 1;
 | |
|                 }
 | |
|             }
 | |
|             if (!match)
 | |
|                 nTotal += XkbKeyNumSyms(xkb, i);
 | |
|             else {
 | |
|                 nTotal += XkbKeyNumGroups(xkb, i) * new_num_lvls;
 | |
|                 nResize++;
 | |
|             }
 | |
|         }
 | |
|         if (nResize > 0) {
 | |
|             int nextMatch;
 | |
| 
 | |
|             xkb->map->size_syms = (nTotal * 15) / 10;
 | |
|             newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
 | |
|             if (newSyms == NULL)
 | |
|                 return BadAlloc;
 | |
|             nextMatch = 0;
 | |
|             nSyms = 1;
 | |
|             for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
 | |
|                 if (matchingKeys[nextMatch] == i) {
 | |
|                     KeySym *pOld;
 | |
| 
 | |
|                     nextMatch++;
 | |
|                     width = XkbKeyGroupsWidth(xkb, i);
 | |
|                     pOld = XkbKeySymsPtr(xkb, i);
 | |
|                     for (g = XkbKeyNumGroups(xkb, i) - 1; g >= 0; g--) {
 | |
|                         memcpy(&newSyms[nSyms + (new_num_lvls * g)],
 | |
|                                &pOld[width * g], width * sizeof(KeySym));
 | |
|                     }
 | |
|                     xkb->map->key_sym_map[i].offset = nSyms;
 | |
|                     nSyms += XkbKeyNumGroups(xkb, i) * new_num_lvls;
 | |
|                 }
 | |
|                 else {
 | |
|                     memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
 | |
|                            XkbKeyNumSyms(xkb, i) * sizeof(KeySym));
 | |
|                     xkb->map->key_sym_map[i].offset = nSyms;
 | |
|                     nSyms += XkbKeyNumSyms(xkb, i);
 | |
|                 }
 | |
|             }
 | |
|             type->num_levels = new_num_lvls;
 | |
|             free(xkb->map->syms);
 | |
|             xkb->map->syms = newSyms;
 | |
|             xkb->map->num_syms = nSyms;
 | |
|             return Success;
 | |
|         }
 | |
|     }
 | |
|     else if (new_num_lvls < type->num_levels) {
 | |
|         int width, match;
 | |
|         register int g, i;
 | |
| 
 | |
|         for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
 | |
|             width = XkbKeyGroupsWidth(xkb, i);
 | |
|             if (width < type->num_levels)
 | |
|                 continue;
 | |
|             for (match = 0, g = XkbKeyNumGroups(xkb, i) - 1;
 | |
|                  (g >= 0) && (!match); g--) {
 | |
|                 if (XkbKeyKeyTypeIndex(xkb, i, g) == type_ndx) {
 | |
|                     matchingKeys[nMatchingKeys++] = i;
 | |
|                     match = 1;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if (nMatchingKeys > 0) {
 | |
|         int key, firstClear;
 | |
|         register int i, g;
 | |
| 
 | |
|         if (new_num_lvls > type->num_levels)
 | |
|             firstClear = type->num_levels;
 | |
|         else
 | |
|             firstClear = new_num_lvls;
 | |
|         for (i = 0; i < nMatchingKeys; i++) {
 | |
|             KeySym *pSyms;
 | |
|             int width, nClear;
 | |
| 
 | |
|             key = matchingKeys[i];
 | |
|             width = XkbKeyGroupsWidth(xkb, key);
 | |
|             nClear = width - firstClear;
 | |
|             pSyms = XkbKeySymsPtr(xkb, key);
 | |
|             for (g = XkbKeyNumGroups(xkb, key) - 1; g >= 0; g--) {
 | |
|                 if (XkbKeyKeyTypeIndex(xkb, key, g) == type_ndx) {
 | |
|                     if (nClear > 0)
 | |
|                         memset(&pSyms[g * width + firstClear], 0,
 | |
|                                nClear * sizeof(KeySym));
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     type->num_levels = new_num_lvls;
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| KeySym *
 | |
| XkbResizeKeySyms(XkbDescPtr xkb, int key, int needed)
 | |
| {
 | |
|     register int i, nSyms, nKeySyms;
 | |
|     unsigned nOldSyms;
 | |
|     KeySym *newSyms;
 | |
| 
 | |
|     if (needed == 0) {
 | |
|         xkb->map->key_sym_map[key].offset = 0;
 | |
|         return xkb->map->syms;
 | |
|     }
 | |
|     nOldSyms = XkbKeyNumSyms(xkb, key);
 | |
|     if (nOldSyms >= (unsigned) needed) {
 | |
|         return XkbKeySymsPtr(xkb, key);
 | |
|     }
 | |
|     if (xkb->map->size_syms - xkb->map->num_syms >= (unsigned) needed) {
 | |
|         if (nOldSyms > 0) {
 | |
|             memcpy(&xkb->map->syms[xkb->map->num_syms], XkbKeySymsPtr(xkb, key),
 | |
|                    nOldSyms * sizeof(KeySym));
 | |
|         }
 | |
|         if ((needed - nOldSyms) > 0) {
 | |
|             memset(&xkb->map->
 | |
|                    syms[xkb->map->num_syms + XkbKeyNumSyms(xkb, key)], 0,
 | |
|                    (needed - nOldSyms) * sizeof(KeySym));
 | |
|         }
 | |
|         xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
 | |
|         xkb->map->num_syms += needed;
 | |
|         return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
 | |
|     }
 | |
|     xkb->map->size_syms += (needed > 32 ? needed : 32);
 | |
|     newSyms = calloc(xkb->map->size_syms, sizeof(KeySym));
 | |
|     if (newSyms == NULL)
 | |
|         return NULL;
 | |
|     newSyms[0] = NoSymbol;
 | |
|     nSyms = 1;
 | |
|     for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
 | |
|         int nCopy;
 | |
| 
 | |
|         nCopy = nKeySyms = XkbKeyNumSyms(xkb, i);
 | |
|         if ((nKeySyms == 0) && (i != key))
 | |
|             continue;
 | |
|         if (i == key)
 | |
|             nKeySyms = needed;
 | |
|         if (nCopy != 0)
 | |
|             memcpy(&newSyms[nSyms], XkbKeySymsPtr(xkb, i),
 | |
|                    nCopy * sizeof(KeySym));
 | |
|         if (nKeySyms > nCopy)
 | |
|             memset(&newSyms[nSyms + nCopy], 0,
 | |
|                    (nKeySyms - nCopy) * sizeof(KeySym));
 | |
|         xkb->map->key_sym_map[i].offset = nSyms;
 | |
|         nSyms += nKeySyms;
 | |
|     }
 | |
|     free(xkb->map->syms);
 | |
|     xkb->map->syms = newSyms;
 | |
|     xkb->map->num_syms = nSyms;
 | |
|     return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
 | |
| }
 | |
| 
 | |
| static unsigned
 | |
| _ExtendRange(unsigned int old_flags,
 | |
|              unsigned int flag,
 | |
|              KeyCode newKC, KeyCode *old_min, unsigned char *old_num)
 | |
| {
 | |
|     if ((old_flags & flag) == 0) {
 | |
|         old_flags |= flag;
 | |
|         *old_min = newKC;
 | |
|         *old_num = 1;
 | |
|     }
 | |
|     else {
 | |
|         int last = (*old_min) + (*old_num) - 1;
 | |
| 
 | |
|         if (newKC < *old_min) {
 | |
|             *old_min = newKC;
 | |
|             *old_num = (last - newKC) + 1;
 | |
|         }
 | |
|         else if (newKC > last) {
 | |
|             *old_num = (newKC - (*old_min)) + 1;
 | |
|         }
 | |
|     }
 | |
|     return old_flags;
 | |
| }
 | |
| 
 | |
| Status
 | |
| XkbChangeKeycodeRange(XkbDescPtr xkb,
 | |
|                       int minKC, int maxKC, XkbChangesPtr changes)
 | |
| {
 | |
|     int tmp;
 | |
| 
 | |
|     if ((!xkb) || (minKC < XkbMinLegalKeyCode) || (maxKC > XkbMaxLegalKeyCode))
 | |
|         return BadValue;
 | |
|     if (minKC > maxKC)
 | |
|         return BadMatch;
 | |
|     if (minKC < xkb->min_key_code) {
 | |
|         if (changes)
 | |
|             changes->map.min_key_code = minKC;
 | |
|         tmp = xkb->min_key_code - minKC;
 | |
|         if (xkb->map) {
 | |
|             if (xkb->map->key_sym_map) {
 | |
|                 memset((char *) &xkb->map->key_sym_map[minKC], 0,
 | |
|                        tmp * sizeof(XkbSymMapRec));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbKeySymsMask, minKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_key_sym,
 | |
|                                                         &changes->map.
 | |
|                                                         num_key_syms);
 | |
|                 }
 | |
|             }
 | |
|             if (xkb->map->modmap) {
 | |
|                 memset((char *) &xkb->map->modmap[minKC], 0, tmp);
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbModifierMapMask,
 | |
|                                                         minKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_modmap_key,
 | |
|                                                         &changes->map.
 | |
|                                                         num_modmap_keys);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if (xkb->server) {
 | |
|             if (xkb->server->behaviors) {
 | |
|                 memset((char *) &xkb->server->behaviors[minKC], 0,
 | |
|                        tmp * sizeof(XkbBehavior));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbKeyBehaviorsMask,
 | |
|                                                         minKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_key_behavior,
 | |
|                                                         &changes->map.
 | |
|                                                         num_key_behaviors);
 | |
|                 }
 | |
|             }
 | |
|             if (xkb->server->key_acts) {
 | |
|                 memset((char *) &xkb->server->key_acts[minKC], 0,
 | |
|                        tmp * sizeof(unsigned short));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbKeyActionsMask,
 | |
|                                                         minKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_key_act,
 | |
|                                                         &changes->map.
 | |
|                                                         num_key_acts);
 | |
|                 }
 | |
|             }
 | |
|             if (xkb->server->vmodmap) {
 | |
|                 memset((char *) &xkb->server->vmodmap[minKC], 0,
 | |
|                        tmp * sizeof(unsigned short));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbVirtualModMapMask,
 | |
|                                                         minKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_modmap_key,
 | |
|                                                         &changes->map.
 | |
|                                                         num_vmodmap_keys);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if ((xkb->names) && (xkb->names->keys)) {
 | |
|             memset((char *) &xkb->names->keys[minKC], 0,
 | |
|                    tmp * sizeof(XkbKeyNameRec));
 | |
|             if (changes) {
 | |
|                 changes->names.changed = _ExtendRange(changes->names.changed,
 | |
|                                                       XkbKeyNamesMask, minKC,
 | |
|                                                       &changes->names.first_key,
 | |
|                                                       &changes->names.num_keys);
 | |
|             }
 | |
|         }
 | |
|         xkb->min_key_code = minKC;
 | |
|     }
 | |
|     if (maxKC > xkb->max_key_code) {
 | |
|         if (changes)
 | |
|             changes->map.max_key_code = maxKC;
 | |
|         tmp = maxKC - xkb->max_key_code;
 | |
|         if (xkb->map) {
 | |
|             if (xkb->map->key_sym_map) {
 | |
|                 XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
 | |
| 
 | |
|                 xkb->map->key_sym_map = realloc(xkb->map->key_sym_map,
 | |
|                                                 (maxKC +
 | |
|                                                  1) * sizeof(XkbSymMapRec));
 | |
|                 if (!xkb->map->key_sym_map) {
 | |
|                     free(prev_key_sym_map);
 | |
|                     return BadAlloc;
 | |
|                 }
 | |
|                 memset((char *) &xkb->map->key_sym_map[xkb->max_key_code], 0,
 | |
|                        tmp * sizeof(XkbSymMapRec));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbKeySymsMask, maxKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_key_sym,
 | |
|                                                         &changes->map.
 | |
|                                                         num_key_syms);
 | |
|                 }
 | |
|             }
 | |
|             if (xkb->map->modmap) {
 | |
|                 unsigned char *prev_modmap = xkb->map->modmap;
 | |
| 
 | |
|                 xkb->map->modmap = realloc(xkb->map->modmap,
 | |
|                                            (maxKC + 1) * sizeof(unsigned char));
 | |
|                 if (!xkb->map->modmap) {
 | |
|                     free(prev_modmap);
 | |
|                     return BadAlloc;
 | |
|                 }
 | |
|                 memset((char *) &xkb->map->modmap[xkb->max_key_code], 0, tmp);
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbModifierMapMask,
 | |
|                                                         maxKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_modmap_key,
 | |
|                                                         &changes->map.
 | |
|                                                         num_modmap_keys);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if (xkb->server) {
 | |
|             if (xkb->server->behaviors) {
 | |
|                 XkbBehavior *prev_behaviors = xkb->server->behaviors;
 | |
| 
 | |
|                 xkb->server->behaviors = realloc(xkb->server->behaviors,
 | |
|                                                  (maxKC +
 | |
|                                                   1) * sizeof(XkbBehavior));
 | |
|                 if (!xkb->server->behaviors) {
 | |
|                     free(prev_behaviors);
 | |
|                     return BadAlloc;
 | |
|                 }
 | |
|                 memset((char *) &xkb->server->behaviors[xkb->max_key_code], 0,
 | |
|                        tmp * sizeof(XkbBehavior));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbKeyBehaviorsMask,
 | |
|                                                         maxKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_key_behavior,
 | |
|                                                         &changes->map.
 | |
|                                                         num_key_behaviors);
 | |
|                 }
 | |
|             }
 | |
|             if (xkb->server->key_acts) {
 | |
|                 unsigned short *prev_key_acts = xkb->server->key_acts;
 | |
| 
 | |
|                 xkb->server->key_acts = realloc(xkb->server->key_acts,
 | |
|                                                 (maxKC +
 | |
|                                                  1) * sizeof(unsigned short));
 | |
|                 if (!xkb->server->key_acts) {
 | |
|                     free(prev_key_acts);
 | |
|                     return BadAlloc;
 | |
|                 }
 | |
|                 memset((char *) &xkb->server->key_acts[xkb->max_key_code], 0,
 | |
|                        tmp * sizeof(unsigned short));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbKeyActionsMask,
 | |
|                                                         maxKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_key_act,
 | |
|                                                         &changes->map.
 | |
|                                                         num_key_acts);
 | |
|                 }
 | |
|             }
 | |
|             if (xkb->server->vmodmap) {
 | |
|                 unsigned short *prev_vmodmap = xkb->server->vmodmap;
 | |
| 
 | |
|                 xkb->server->vmodmap = realloc(xkb->server->vmodmap,
 | |
|                                                (maxKC +
 | |
|                                                 1) * sizeof(unsigned short));
 | |
|                 if (!xkb->server->vmodmap) {
 | |
|                     free(prev_vmodmap);
 | |
|                     return BadAlloc;
 | |
|                 }
 | |
|                 memset((char *) &xkb->server->vmodmap[xkb->max_key_code], 0,
 | |
|                        tmp * sizeof(unsigned short));
 | |
|                 if (changes) {
 | |
|                     changes->map.changed = _ExtendRange(changes->map.changed,
 | |
|                                                         XkbVirtualModMapMask,
 | |
|                                                         maxKC,
 | |
|                                                         &changes->map.
 | |
|                                                         first_modmap_key,
 | |
|                                                         &changes->map.
 | |
|                                                         num_vmodmap_keys);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if ((xkb->names) && (xkb->names->keys)) {
 | |
|             XkbKeyNameRec *prev_keys = xkb->names->keys;
 | |
| 
 | |
|             xkb->names->keys = realloc(xkb->names->keys,
 | |
|                                        (maxKC + 1) * sizeof(XkbKeyNameRec));
 | |
|             if (!xkb->names->keys) {
 | |
|                 free(prev_keys);
 | |
|                 return BadAlloc;
 | |
|             }
 | |
|             memset((char *) &xkb->names->keys[xkb->max_key_code], 0,
 | |
|                    tmp * sizeof(XkbKeyNameRec));
 | |
|             if (changes) {
 | |
|                 changes->names.changed = _ExtendRange(changes->names.changed,
 | |
|                                                       XkbKeyNamesMask, maxKC,
 | |
|                                                       &changes->names.first_key,
 | |
|                                                       &changes->names.num_keys);
 | |
|             }
 | |
|         }
 | |
|         xkb->max_key_code = maxKC;
 | |
|     }
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| XkbAction *
 | |
| XkbResizeKeyActions(XkbDescPtr xkb, int key, int needed)
 | |
| {
 | |
|     register int i, nActs;
 | |
|     XkbAction *newActs;
 | |
| 
 | |
|     if (needed == 0) {
 | |
|         xkb->server->key_acts[key] = 0;
 | |
|         return NULL;
 | |
|     }
 | |
|     if (XkbKeyHasActions(xkb, key) &&
 | |
|         (XkbKeyNumSyms(xkb, key) >= (unsigned) needed))
 | |
|         return XkbKeyActionsPtr(xkb, key);
 | |
|     if (xkb->server->size_acts - xkb->server->num_acts >= (unsigned) needed) {
 | |
|         xkb->server->key_acts[key] = xkb->server->num_acts;
 | |
|         xkb->server->num_acts += needed;
 | |
|         return &xkb->server->acts[xkb->server->key_acts[key]];
 | |
|     }
 | |
|     xkb->server->size_acts = xkb->server->num_acts + needed + 8;
 | |
|     newActs = calloc(xkb->server->size_acts, sizeof(XkbAction));
 | |
|     if (newActs == NULL)
 | |
|         return NULL;
 | |
|     newActs[0].type = XkbSA_NoAction;
 | |
|     nActs = 1;
 | |
|     for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
 | |
|         int nKeyActs, nCopy;
 | |
| 
 | |
|         if ((xkb->server->key_acts[i] == 0) && (i != key))
 | |
|             continue;
 | |
| 
 | |
|         nCopy = nKeyActs = XkbKeyNumActions(xkb, i);
 | |
|         if (i == key) {
 | |
|             nKeyActs = needed;
 | |
|             if (needed < nCopy)
 | |
|                 nCopy = needed;
 | |
|         }
 | |
| 
 | |
|         if (nCopy > 0)
 | |
|             memcpy(&newActs[nActs], XkbKeyActionsPtr(xkb, i),
 | |
|                    nCopy * sizeof(XkbAction));
 | |
|         if (nCopy < nKeyActs)
 | |
|             memset(&newActs[nActs + nCopy], 0,
 | |
|                    (nKeyActs - nCopy) * sizeof(XkbAction));
 | |
|         xkb->server->key_acts[i] = nActs;
 | |
|         nActs += nKeyActs;
 | |
|     }
 | |
|     free(xkb->server->acts);
 | |
|     xkb->server->acts = newActs;
 | |
|     xkb->server->num_acts = nActs;
 | |
|     return &xkb->server->acts[xkb->server->key_acts[key]];
 | |
| }
 | |
| 
 | |
| void
 | |
| XkbFreeClientMap(XkbDescPtr xkb, unsigned what, Bool freeMap)
 | |
| {
 | |
|     XkbClientMapPtr map;
 | |
| 
 | |
|     if ((xkb == NULL) || (xkb->map == NULL))
 | |
|         return;
 | |
|     if (freeMap)
 | |
|         what = XkbAllClientInfoMask;
 | |
|     map = xkb->map;
 | |
|     if (what & XkbKeyTypesMask) {
 | |
|         if (map->types != NULL) {
 | |
|             if (map->num_types > 0) {
 | |
|                 register int i;
 | |
|                 XkbKeyTypePtr type;
 | |
| 
 | |
|                 for (i = 0, type = map->types; i < map->num_types; i++, type++) {
 | |
|                     free(type->map);
 | |
|                     type->map = NULL;
 | |
|                     free(type->preserve);
 | |
|                     type->preserve = NULL;
 | |
|                     type->map_count = 0;
 | |
|                     free(type->level_names);
 | |
|                     type->level_names = NULL;
 | |
|                 }
 | |
|             }
 | |
|             free(map->types);
 | |
|             map->num_types = map->size_types = 0;
 | |
|             map->types = NULL;
 | |
|         }
 | |
|     }
 | |
|     if (what & XkbKeySymsMask) {
 | |
|         free(map->key_sym_map);
 | |
|         map->key_sym_map = NULL;
 | |
|         if (map->syms != NULL) {
 | |
|             free(map->syms);
 | |
|             map->size_syms = map->num_syms = 0;
 | |
|             map->syms = NULL;
 | |
|         }
 | |
|     }
 | |
|     if ((what & XkbModifierMapMask) && (map->modmap != NULL)) {
 | |
|         free(map->modmap);
 | |
|         map->modmap = NULL;
 | |
|     }
 | |
|     if (freeMap) {
 | |
|         free(xkb->map);
 | |
|         xkb->map = NULL;
 | |
|     }
 | |
|     return;
 | |
| }
 | |
| 
 | |
| void
 | |
| XkbFreeServerMap(XkbDescPtr xkb, unsigned what, Bool freeMap)
 | |
| {
 | |
|     XkbServerMapPtr map;
 | |
| 
 | |
|     if ((xkb == NULL) || (xkb->server == NULL))
 | |
|         return;
 | |
|     if (freeMap)
 | |
|         what = XkbAllServerInfoMask;
 | |
|     map = xkb->server;
 | |
|     if ((what & XkbExplicitComponentsMask) && (map->explicit != NULL)) {
 | |
|         free(map->explicit);
 | |
|         map->explicit = NULL;
 | |
|     }
 | |
|     if (what & XkbKeyActionsMask) {
 | |
|         free(map->key_acts);
 | |
|         map->key_acts = NULL;
 | |
|         if (map->acts != NULL) {
 | |
|             free(map->acts);
 | |
|             map->num_acts = map->size_acts = 0;
 | |
|             map->acts = NULL;
 | |
|         }
 | |
|     }
 | |
|     if ((what & XkbKeyBehaviorsMask) && (map->behaviors != NULL)) {
 | |
|         free(map->behaviors);
 | |
|         map->behaviors = NULL;
 | |
|     }
 | |
|     if ((what & XkbVirtualModMapMask) && (map->vmodmap != NULL)) {
 | |
|         free(map->vmodmap);
 | |
|         map->vmodmap = NULL;
 | |
|     }
 | |
| 
 | |
|     if (freeMap) {
 | |
|         free(xkb->server);
 | |
|         xkb->server = NULL;
 | |
|     }
 | |
|     return;
 | |
| }
 |