xkb/gkve: copy XKB map, not pointer-assign

Write a new function to copy an XKB map (does everything but geometry at
the moment), and use that instead of nasty pointer assignments.
This commit is contained in:
Daniel Stone 2006-08-23 14:33:41 +03:00 committed by Daniel Stone
parent a56b98bb04
commit 8f8487ff99
4 changed files with 410 additions and 18 deletions

View File

@ -260,16 +260,6 @@ CoreKeyboardProc(DeviceIntPtr pDev, int what)
break;
case DEVICE_CLOSE:
/* This, uh, probably requires some explanation.
* Press a key on another keyboard.
* Watch its xkbInfo get pivoted into core's.
* Kill the server.
* Watch the first device's xkbInfo get freed.
* Try to free ours, which points to same.
*
* ... yeah.
*/
pDev->key->xkbInfo = NULL;
pDev->devPrivates[CoreDevicePrivatesIndex].ptr = NULL;
break;

View File

@ -4802,14 +4802,8 @@ int GetKeyboardValuatorEvents(xEvent *events, DeviceIntPtr pDev, int type,
mn.virtualMods = ~0; /* ??? */
mn.changed = XkbAllMapComponentsMask;
/* If this is still the map we set at DEVICE_INIT, free it so
* it doesn't just get lost. (Shameful hack, sorry.) */
if (!inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr &&
ckeyc->xkbInfo)
XkbFreeInfo(ckeyc->xkbInfo);
/* FIXME we really need a map copy here. */
ckeyc->xkbInfo = pDev->key->xkbInfo;
XkbSendMapNotify(inputInfo.keyboard, &mn);
if (!XkbCopyKeymap(pDev->key->xkbInfo, ckeyc->xkbInfo))
FatalError("Couldn't pivot keymap from device to core!\n");
}
#endif
SendMappingNotify(MappingKeyboard, ckeyc->curKeySyms.minKeyCode,

View File

@ -72,3 +72,7 @@ extern Bool XkbDDXCompileKeymapByNames(
unsigned need,
char * nameRtrn,
int nameRtrnLen);
extern Bool XkbCopyKeymap(
XkbDescPtr src,
XkbDescPtr dst);

View File

@ -969,3 +969,407 @@ XkbConvertCase(register KeySym sym, KeySym *lower, KeySym *upper)
break;
}
}
/**
* Copy an XKB map from src to dst, reallocating when necessary: if some
* map components are present in one, but not in the other, the destination
* components will be allocated or freed as necessary.
*
* Basic map consistency is assumed on both sides, so maps with random
* uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19)
* _will_ cause failures. You've been warned.
*
* Returns TRUE on success, or FALSE on failure. If this function fails,
* dst may be in an inconsistent state: all its pointers are guaranteed
* to remain valid, but part of the map may be from src and part from dst.
*/
Bool
XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst)
{
int i = 0, j = 0;
void *tmp = NULL;
XkbKeyTypePtr stype = NULL, dtype = NULL;
if (!src || !dst)
return FALSE;
/* client map */
if (src->map) {
if (!dst->map) {
tmp = xcalloc(1, sizeof(XkbClientMapRec));
if (!tmp)
return FALSE;
dst->map = tmp;
}
if (src->map->syms) {
if (src->map->size_syms != dst->map->size_syms) {
if (dst->map->syms)
tmp = xrealloc(dst->map->syms, src->map->size_syms);
else
tmp = xalloc(src->map->size_syms);
if (!tmp)
return FALSE;
dst->map->syms = tmp;
}
memcpy(dst->map->syms, src->map->syms, src->map->size_syms);
memcpy(dst->map->key_sym_map, src->map->key_sym_map,
src->map->size_syms);
}
else {
if (dst->map->syms) {
xfree(dst->map->syms);
dst->map->syms = NULL;
}
}
dst->map->num_syms = src->map->num_syms;
dst->map->size_syms = src->map->size_syms;
if (src->map->types) {
if (src->map->size_types != dst->map->size_types) {
XkbKeyTypePtr stype = src->map->types;
if (dst->map->types)
tmp = xrealloc(dst->map->types, src->map->size_types);
else
tmp = xalloc(src->map->size_types);
if (!tmp)
return FALSE;
dst->map->types = tmp;
}
memcpy(dst->map->types, src->map->types, src->map->size_types);
stype = src->map->types;
dtype = dst->map->types;
for (i = 0; i < dst->map->num_types; i++, dtype++, stype++) {
dtype->level_names = xalloc(dtype->num_levels * sizeof(Atom));
if (!dtype->level_names)
continue; /* don't return FALSE here, try to whack all the
pointers we can, so we don't double-free when
going down. */
memcpy(dtype->level_names, stype->level_names,
dtype->num_levels * sizeof(Atom));
}
}
else {
if (dst->map->types) {
for (i = 0, dtype = dst->map->types; i < dst->map->num_types;
i++, dtype++)
xfree(dtype->level_names);
xfree(dst->map->types);
dst->map->types = NULL;
}
}
dst->map->size_types = src->map->size_types;
dst->map->num_types = src->map->num_types;
if (src->map->modmap) {
if (src->max_key_code != dst->max_key_code) {
if (dst->map->modmap)
tmp = xrealloc(dst->map->modmap, src->max_key_code + 1);
else
tmp = xalloc(src->max_key_code + 1);
if (!tmp)
return FALSE;
dst->map->syms = tmp;
}
memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1);
}
else {
if (dst->map->modmap) {
xfree(dst->map->modmap);
dst->map->modmap = NULL;
}
}
}
else {
if (dst->map)
XkbFreeClientMap(dst, XkbAllClientInfoMask, True);
}
/* server map */
if (src->server) {
if (!dst->server) {
tmp = xcalloc(1, sizeof(XkbServerMapRec));
if (!tmp)
return FALSE;
dst->server = tmp;
}
if (src->server->explicit) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->explicit)
tmp = xrealloc(dst->server->explicit, src->max_key_code + 1);
else
tmp = xalloc(src->max_key_code + 1);
if (!tmp)
return FALSE;
dst->server->explicit = tmp;
}
memcpy(dst->server->explicit, src->server->explicit,
src->max_key_code + 1);
}
else {
if (dst->server->explicit) {
xfree(dst->server->explicit);
dst->server->explicit = NULL;
}
}
if (src->server->acts) {
if (src->server->size_acts != dst->server->size_acts) {
if (dst->server->acts)
tmp = xrealloc(dst->server->acts, src->server->size_acts);
else
tmp = xalloc(src->server->size_acts);
if (!tmp)
return FALSE;
dst->server->acts = tmp;
}
memcpy(dst->server->acts, src->server->acts,
src->server->size_acts);
}
else {
if (dst->server->acts) {
xfree(dst->server->acts);
dst->server->acts = NULL;
}
}
dst->server->size_acts = src->server->size_acts;
if (src->server->key_acts) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->key_acts)
tmp = xrealloc(dst->server->key_acts, src->max_key_code + 1);
else
tmp = xalloc(src->max_key_code + 1);
if (!tmp)
return FALSE;
dst->server->key_acts = tmp;
}
memcpy(dst->server->key_acts, src->server->key_acts,
src->max_key_code + 1);
}
else {
if (dst->server->key_acts) {
xfree(dst->server->key_acts);
dst->server->key_acts = NULL;
}
}
if (src->server->behaviors) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->behaviors)
tmp = xrealloc(dst->server->behaviors,
(src->max_key_code + 1) *
sizeof(XkbBehavior));
else
tmp = xalloc((src->max_key_code + 1) *
sizeof(XkbBehavior));
if (!tmp)
return FALSE;
dst->server->behaviors = tmp;
}
memcpy(dst->server->behaviors, src->server->behaviors,
(src->max_key_code + 1) * sizeof(XkbBehavior));
}
else {
if (dst->server->behaviors) {
xfree(dst->server->behaviors);
dst->server->behaviors = NULL;
}
}
if (src->server->vmodmap) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->vmodmap)
tmp = xrealloc(dst->server->vmodmap,
src->max_key_code + 1);
else
tmp = xalloc(src->max_key_code + 1);
if (!tmp)
return FALSE;
dst->server->vmodmap = tmp;
}
memcpy(dst->server->vmodmap, src->server->vmodmap,
src->max_key_code + 1);
}
else {
if (dst->server->vmodmap) {
xfree(dst->server->vmodmap);
dst->server->vmodmap = NULL;
}
}
}
else {
if (dst->server)
XkbFreeServerMap(dst, XkbAllServerInfoMask, True);
}
/* indicators */
if (src->indicators) {
if (!dst->indicators) {
dst->indicators = xalloc(sizeof(XkbIndicatorRec));
if (!dst->indicators)
return FALSE;
}
memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec));
}
else {
if (dst->indicators) {
xfree(dst->indicators);
dst->indicators = NULL;
}
}
/* controls */
if (src->ctrls) {
if (!dst->ctrls) {
dst->ctrls = xalloc(sizeof(XkbControlsRec));
if (!dst->ctrls)
return FALSE;
}
memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec));
}
else {
if (dst->ctrls) {
xfree(dst->ctrls);
dst->ctrls = NULL;
}
}
/* names */
if (src->names) {
if (!dst->names) {
dst->names = xcalloc(1, sizeof(XkbNamesRec));
if (!dst->names)
return FALSE;
}
if (src->names->keys) {
if (src->max_key_code != dst->max_key_code) {
if (dst->names->keys)
tmp = xrealloc(dst->names->keys, (src->max_key_code + 1) *
sizeof(XkbKeyNameRec));
else
tmp = xalloc((src->max_key_code + 1) *
sizeof(XkbKeyNameRec));
if (!tmp)
return FALSE;
dst->names->keys = tmp;
}
memcpy(dst->names->keys, src->names->keys,
(src->max_key_code + 1) * sizeof(XkbKeyNameRec));
}
else {
if (dst->names->keys) {
xfree(dst->names->keys);
dst->names->keys = NULL;
}
}
if (src->names->num_key_aliases) {
if (src->names->num_key_aliases != dst->names->num_key_aliases) {
if (dst->names->key_aliases)
tmp = xrealloc(dst->names->key_aliases,
src->names->num_key_aliases *
sizeof(XkbKeyAliasRec));
else
tmp = xalloc(src->names->num_key_aliases *
sizeof(XkbKeyAliasRec));
if (!tmp)
return FALSE;
dst->names->key_aliases = tmp;
}
memcpy(dst->names->key_aliases, src->names->key_aliases,
src->names->num_key_aliases * sizeof(XkbKeyAliasRec));
}
else {
if (dst->names->key_aliases) {
xfree(dst->names->key_aliases);
dst->names->key_aliases = NULL;
}
}
dst->names->num_key_aliases = src->names->num_key_aliases;
if (src->names->num_rg) {
if (src->names->num_rg != dst->names->num_rg) {
if (dst->names->radio_groups)
tmp = xrealloc(dst->names->radio_groups,
src->names->num_rg * sizeof(Atom));
else
tmp = xalloc(src->names->num_rg * sizeof(Atom));
if (!tmp)
return FALSE;
dst->names->radio_groups = tmp;
}
memcpy(dst->names->radio_groups, src->names->radio_groups,
src->names->num_rg * sizeof(Atom));
}
else {
if (dst->names->radio_groups)
xfree(dst->names->radio_groups);
}
dst->names->num_rg = src->names->num_rg;
}
else {
if (dst->names)
XkbFreeNames(dst, XkbAllNamesMask, True);
}
/* compat */
if (src->compat) {
if (src->compat->sym_interpret) {
if (src->compat->num_si != dst->compat->num_si) {
if (dst->compat->sym_interpret)
tmp = xrealloc(dst->compat->sym_interpret,
src->compat->num_si *
sizeof(XkbSymInterpretRec));
else
tmp = xalloc(src->compat->num_si *
sizeof(XkbSymInterpretRec));
if (!tmp)
return FALSE;
dst->compat->sym_interpret = tmp;
}
memcpy(dst->compat->sym_interpret, src->compat->sym_interpret,
src->compat->num_si * sizeof(XkbSymInterpretRec));
}
else {
if (dst->compat->sym_interpret) {
xfree(dst->compat->sym_interpret);
dst->compat->sym_interpret = NULL;
}
}
dst->compat->num_si = src->compat->num_si;
memcpy(dst->compat->groups, src->compat->groups,
XkbNumKbdGroups * sizeof(XkbModsRec));
}
else {
if (dst->compat)
XkbFreeCompatMap(dst, XkbAllCompatMask, True);
}
/* geometry */
if (src->geom) {
/* properties */
/* colors */
/* shapes */
/* sections */
/* doodads */
/* key aliases */
/* font?!? */
}
else {
if (dst->geom) {
XkbFreeGeometry(dst->geom, XkbGeomAllMask, True);
}
}
dst->min_key_code = src->min_key_code;
dst->max_key_code = src->max_key_code;
return TRUE;
}