/* $Xorg: XKBGetMap.c,v 1.4 2000/08/17 19:45:02 cpqbld Exp $ */
/************************************************************
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.

********************************************************/

/* $XFree86: xc/lib/X11/XKBGetMap.c,v 1.7 2003/02/04 03:49:33 dawes Exp $ */

#define NEED_REPLIES
#define NEED_EVENTS
#define	NEED_MAP_READERS
#include "Xlibint.h"
#include <X11/extensions/XKBproto.h>
#include "XKBlibint.h"

static Status
#if NeedFunctionPrototypes
_XkbReadKeyTypes(XkbReadBufferPtr buf,XkbDescPtr xkb,xkbGetMapReply *rep)
#else
_XkbReadKeyTypes(buf,xkb,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr 		xkb;
    xkbGetMapReply *	rep;
#endif
{
int		 i,n,lastMapCount;
XkbKeyTypePtr	type;

    if ( rep->nTypes>0 ) {
	n = rep->firstType+rep->nTypes;
	if (xkb->map->num_types>=n)
	    n= xkb->map->num_types;
	else if (XkbAllocClientMap(xkb,XkbKeyTypesMask,n)!=Success)
	    return BadAlloc;

	type = &xkb->map->types[rep->firstType];
	for (i=0;i<(int)rep->nTypes;i++,type++) {
	    xkbKeyTypeWireDesc	*desc;
	    register int ndx;

	    ndx= i+rep->firstType;
	    if (ndx>=xkb->map->num_types)
		xkb->map->num_types= ndx+1;

	    desc= (xkbKeyTypeWireDesc *)_XkbGetReadBufferPtr(buf,
						SIZEOF(xkbKeyTypeWireDesc));
	    if (desc==NULL)
		return BadLength;

	    lastMapCount= type->map_count;
	    if ( desc->nMapEntries>0 ) {
		if ((type->map==NULL)||(desc->nMapEntries>type->map_count)) {
		    XkbKTMapEntryRec *prev_map = type->map;

		    type->map= _XkbTypedRealloc(type->map,desc->nMapEntries,
							      XkbKTMapEntryRec);
		    if (type->map==NULL) {
			_XkbFree(prev_map);
			return BadAlloc;
		    }
		}
	    }
	    else if (type->map!=NULL) {
		Xfree(type->map);
		type->map_count= 0;
		type->map= NULL;
	    }

	    if ( desc->preserve && (desc->nMapEntries>0) ) {
		if ((!type->preserve)||
		    (desc->nMapEntries>lastMapCount)) {
		    XkbModsRec *prev_preserve = type->preserve;

		    type->preserve= _XkbTypedRealloc(type->preserve,
							desc->nMapEntries,
							XkbModsRec);
		    if (type->preserve==NULL) {
			_XkbFree(prev_preserve);
			return BadAlloc;
		    }
		}
	    }
	    else if (type->preserve!=NULL) {
		Xfree(type->preserve);
		type->preserve= NULL;
	    }

	    type->mods.mask = desc->mask;
	    type->mods.real_mods = desc->realMods;
	    type->mods.vmods = desc->virtualMods;
	    type->num_levels = desc->numLevels;
	    type->map_count = desc->nMapEntries;
	    if (desc->nMapEntries>0) {
		register xkbKTMapEntryWireDesc *wire; 
		register XkbKTMapEntryPtr	entry;
		register int size;

		size= type->map_count*SIZEOF(xkbKTMapEntryWireDesc);
		wire= (xkbKTMapEntryWireDesc *)_XkbGetReadBufferPtr(buf,size);
		if (wire==NULL)
		    return BadLength;
		entry= type->map;
		for (n=0;n<type->map_count;n++,wire++,entry++) {
		    entry->active= wire->active;
		    entry->level= wire->level;
		    entry->mods.mask= wire->mask;
		    entry->mods.real_mods= wire->realMods;
		    entry->mods.vmods= wire->virtualMods;
		}

	 	if (desc->preserve) {
		    register xkbModsWireDesc *	pwire; 
		    register XkbModsPtr		preserve;
		    register int sz;

		    sz= desc->nMapEntries*SIZEOF(xkbModsWireDesc);
		    pwire=(xkbModsWireDesc *)_XkbGetReadBufferPtr(buf,sz);
		    if (pwire==NULL)
			return BadLength;
		    preserve= type->preserve;
		    for (n=0;n<desc->nMapEntries;n++,pwire++,preserve++) {
			preserve->mask=  pwire->mask;
			preserve->vmods=  pwire->virtualMods;
			preserve->real_mods= pwire->realMods;
		    }
		}
	    }
	}
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbReadKeySyms(XkbReadBufferPtr buf,XkbDescPtr xkb,xkbGetMapReply *rep)
#else
_XkbReadKeySyms(buf,xkb,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr 		xkb;
    xkbGetMapReply *	rep;
#endif
{
register int i;
XkbClientMapPtr	map;

    map= xkb->map;
    if (map->key_sym_map==NULL) {
	register int offset;
	XkbSymMapPtr	oldMap;
	xkbSymMapWireDesc *newMap;
	map->key_sym_map= _XkbTypedCalloc((xkb->max_key_code+1),XkbSymMapRec);
	if (map->key_sym_map==NULL)
	    return BadAlloc;
	if (map->syms==NULL) {
	    int sz;
	    sz= (rep->totalSyms*12)/10;
	    sz= ((sz+(unsigned)128)/128)*128;
	    map->syms = _XkbTypedCalloc(sz,KeySym);
	    if (map->syms==NULL)
		return BadAlloc;
	    map->size_syms = sz;
	}
	offset = 1;
	oldMap = &map->key_sym_map[rep->firstKeySym];
	for (i=0;i<(int)rep->nKeySyms;i++,oldMap++) {
	    newMap= (xkbSymMapWireDesc *)
			_XkbGetReadBufferPtr(buf,SIZEOF(xkbSymMapWireDesc));
	    if (newMap==NULL)
		return BadLength;
	    oldMap->kt_index[0]= newMap->ktIndex[0];
	    oldMap->kt_index[1]= newMap->ktIndex[1];
	    oldMap->kt_index[2]= newMap->ktIndex[2];
	    oldMap->kt_index[3]= newMap->ktIndex[3];
	    oldMap->group_info= newMap->groupInfo;
	    oldMap->width= newMap->width;
	    oldMap->offset= offset;
	    if (offset+newMap->nSyms>=map->size_syms) {
		register int sz;
		KeySym *prev_syms = map->syms;

		sz= map->size_syms+128;
		map->syms= _XkbTypedRealloc(map->syms,sz,KeySym);
		if (map->syms==NULL) {
		    _XkbFree(prev_syms);
		    map->size_syms= 0;
		    return BadAlloc;
		}
		map->size_syms= sz;
	    }
	    if (newMap->nSyms>0) {
		_XkbReadBufferCopyKeySyms(buf,(KeySym *)&map->syms[offset],
							newMap->nSyms);
		offset+= newMap->nSyms;
	    }
	    else {
		map->syms[offset]= 0;
	    }
	}
	map->num_syms= offset;
    }
    else {
	xkbSymMapWireDesc *	newMap;
	XkbSymMapPtr		oldMap;
	KeySym *		newSyms;
	int			tmp;

	oldMap = &map->key_sym_map[rep->firstKeySym];
	for (i=0;i<(int)rep->nKeySyms;i++,oldMap++) {
	    newMap= (xkbSymMapWireDesc *)
			_XkbGetReadBufferPtr(buf,SIZEOF(xkbSymMapWireDesc));
	    if (newMap==NULL)
		return BadLength;

	    if (newMap->nSyms>0)
		 tmp= newMap->nSyms;
	    else tmp= 0;

	    newSyms = XkbResizeKeySyms(xkb,i+rep->firstKeySym,tmp);
	    if (newSyms==NULL)
		return BadAlloc;
	    if (newMap->nSyms>0)
		_XkbReadBufferCopyKeySyms(buf,newSyms,newMap->nSyms);
	    else newSyms[0]= NoSymbol;
	    oldMap->kt_index[0] = newMap->ktIndex[0];
	    oldMap->kt_index[1] = newMap->ktIndex[1];
	    oldMap->kt_index[2] = newMap->ktIndex[2];
	    oldMap->kt_index[3] = newMap->ktIndex[3];
	    oldMap->group_info = newMap->groupInfo;
	    oldMap->width = newMap->width;
	}
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbReadKeyActions(XkbReadBufferPtr buf,XkbDescPtr info,xkbGetMapReply *rep)
#else
_XkbReadKeyActions(buf,info,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr		info;
    xkbGetMapReply *	rep;
#endif
{
int		i;
CARD8		numDescBuf[248];
CARD8*		numDesc = NULL;
register int	nKeyActs;
Status		ret = Success;

    if ( (nKeyActs=rep->nKeyActs)>0 ) {
	XkbSymMapPtr	symMap;

	if (nKeyActs < sizeof numDescBuf) numDesc = numDescBuf;
	else numDesc = Xmalloc (nKeyActs * sizeof(CARD8));

	if (!_XkbCopyFromReadBuffer(buf, (char *)numDesc, nKeyActs)) {
	    ret = BadLength;
	    goto done;
	}
	i= XkbPaddedSize(nKeyActs)-nKeyActs;
	if ((i>0)&&(!_XkbSkipReadBufferData(buf,i))) {
	    ret = BadLength;
	    goto done;
	}
	symMap = &info->map->key_sym_map[rep->firstKeyAct];
	for (i=0;i<(int)rep->nKeyActs;i++,symMap++) {
	    if (numDesc[i]==0) {
		info->server->key_acts[i+rep->firstKeyAct]= 0;
	    }
	    else {
		XkbAction *newActs;
		/* 8/16/93 (ef) -- XXX! Verify size here (numdesc must be */
		/*                 either zero or XkbKeyNumSyms(info,key) */
		newActs=XkbResizeKeyActions(info,i+rep->firstKeyAct,
								numDesc[i]);
		if (newActs==NULL) {
		    ret = BadAlloc;
		    goto done;
		}
		if (!_XkbCopyFromReadBuffer(buf,(char *)newActs,
					(int)(numDesc[i]*sizeof(XkbAction)))) {
		    ret = BadLength;
		    goto done;
		}
	    }
	}
    }
done:
    if (numDesc != NULL && numDesc != numDescBuf) Xfree (numDesc);
    return ret;
}

static Status
#if NeedFunctionPrototypes
_XkbReadKeyBehaviors(XkbReadBufferPtr buf,XkbDescPtr xkb,xkbGetMapReply *rep)
#else
_XkbReadKeyBehaviors(buf,xkb,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr 		xkb;
    xkbGetMapReply *	rep;
#endif
{
register int i;
xkbBehaviorWireDesc	*wire;

    if ( rep->totalKeyBehaviors>0 ) {
	if ( xkb->server->behaviors == NULL ) {
	    int size = xkb->max_key_code+1;
	    xkb->server->behaviors = _XkbTypedCalloc(size,XkbBehavior);
	    if (xkb->server->behaviors==NULL)
		return BadAlloc;
	}
	else {
	    bzero(&xkb->server->behaviors[rep->firstKeyBehavior],
	    		(rep->nKeyBehaviors*sizeof(XkbBehavior)));
	}
	for (i=0;i<rep->totalKeyBehaviors;i++) {
	    wire= (xkbBehaviorWireDesc *)_XkbGetReadBufferPtr(buf,
						SIZEOF(xkbBehaviorWireDesc));
	    if (wire==NULL)
		return BadLength;
	    xkb->server->behaviors[wire->key].type= wire->type;
	    xkb->server->behaviors[wire->key].data= wire->data;
	}
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbReadVirtualMods(XkbReadBufferPtr buf,XkbDescPtr xkb,xkbGetMapReply *rep)
#else
_XkbReadVirtualMods(buf,xkb,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr		xkb;
    xkbGetMapReply *	rep;
#endif
{
    if ( rep->virtualMods ) {
	register int i,bit,nVMods;
	register char *data;

	for (i=nVMods=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
	    if (rep->virtualMods&bit)
		nVMods++;
	}
	data= _XkbGetReadBufferPtr(buf,XkbPaddedSize(nVMods));
	if (data==NULL)
	    return BadLength;
	for (i=0,bit=1;(i<XkbNumVirtualMods)&&(nVMods>0);i++,bit<<=1) {
	    if (rep->virtualMods&bit) {
		xkb->server->vmods[i]= *data++;
		nVMods--;
	    }
	}
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbReadExplicitComponents(	XkbReadBufferPtr	buf,
				XkbDescPtr 		xkb,
				xkbGetMapReply *	rep)
#else
_XkbReadExplicitComponents(buf,xkb,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr		xkb;
    xkbGetMapReply *	rep;
#endif
{
register int i;
unsigned char *wire;

    if ( rep->totalKeyExplicit>0 ) {
	if ( xkb->server->explicit == NULL ) {
	    int size = xkb->max_key_code+1;
	    xkb->server->explicit = _XkbTypedCalloc(size,unsigned char);
	    if (xkb->server->explicit==NULL)
		return BadAlloc;
	}
	else {
	    bzero(&xkb->server->explicit[rep->firstKeyExplicit],
	    						rep->nKeyExplicit);
	}
	i= XkbPaddedSize(2*rep->totalKeyExplicit);
	wire=(unsigned char *)_XkbGetReadBufferPtr(buf,i);
	if (!wire)
	    return BadLength;
	for (i=0;i<rep->totalKeyExplicit;i++,wire+=2) {
	    xkb->server->explicit[wire[0]]= wire[1];
	}
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbReadModifierMap(XkbReadBufferPtr buf,XkbDescPtr xkb,xkbGetMapReply *rep)
#else
_XkbReadModifierMap(buf,xkb,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr		xkb;
    xkbGetMapReply *	rep;
#endif
{
register int i;
unsigned char *wire;

    if ( rep->totalModMapKeys>0 ) {
	if ((xkb->map->modmap==NULL)&&
	    (XkbAllocClientMap(xkb,XkbModifierMapMask,0)!=Success)) {
	    return BadAlloc;
	}
	else {
	    bzero(&xkb->map->modmap[rep->firstModMapKey],rep->nModMapKeys);
	}
	i= XkbPaddedSize(2*rep->totalModMapKeys);
	wire=(unsigned char *)_XkbGetReadBufferPtr(buf,i);
	if (!wire)
	    return BadLength;
	for (i=0;i<rep->totalModMapKeys;i++,wire+=2) {
	    xkb->map->modmap[wire[0]]= wire[1];
	}
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbReadVirtualModMap(XkbReadBufferPtr buf,XkbDescPtr xkb,xkbGetMapReply *rep)
#else
_XkbReadVirtualModMap(buf,xkb,rep)
    XkbReadBufferPtr	buf;
    XkbDescPtr		xkb;
    xkbGetMapReply *	rep;
#endif
{
register int 		i;
xkbVModMapWireDesc *	wire;
XkbServerMapPtr		srv;

    if ( rep->totalVModMapKeys>0 ) {
	if (((xkb->server==NULL)||(xkb->server->vmodmap==NULL))&&
	    (XkbAllocServerMap(xkb,XkbVirtualModMapMask,0)!=Success)) {
	    return BadAlloc;
	}
	else {
	    srv= xkb->server;
	    if (rep->nVModMapKeys > rep->firstVModMapKey)
		bzero((char *)&srv->vmodmap[rep->firstVModMapKey],
		      (rep->nVModMapKeys - rep->firstVModMapKey) *
		      sizeof(unsigned short));
	}
	srv= xkb->server;
	i= rep->totalVModMapKeys*SIZEOF(xkbVModMapWireDesc);
	wire=(xkbVModMapWireDesc *)_XkbGetReadBufferPtr(buf,i);
	if (!wire)
	    return BadLength;
	for (i=0;i<rep->totalVModMapKeys;i++,wire++) {
	    if ((wire->key>=xkb->min_key_code)&&(wire->key<=xkb->max_key_code))
		srv->vmodmap[wire->key]= wire->vmods;
	}
    }
    return Success;
}

static xkbGetMapReq *
#if NeedFunctionPrototypes
_XkbGetGetMapReq(Display *dpy,XkbDescPtr xkb)
#else
_XkbGetGetMapReq(dpy,xkb)
    Display *	dpy;
    XkbDescPtr	xkb;
#endif
{
xkbGetMapReq *req;

    GetReq(kbGetMap, req);
    req->reqType = dpy->xkb_info->codes->major_opcode;
    req->xkbReqType = X_kbGetMap;
    req->deviceSpec = xkb->device_spec;
    req->full = req->partial = 0;
    req->firstType = req->nTypes = 0;
    req->firstKeySym = req->nKeySyms = 0;
    req->firstKeyAct = req->nKeyActs = 0;
    req->firstKeyBehavior = req->nKeyBehaviors = 0;
    req->virtualMods = 0;
    req->firstKeyExplicit = req->nKeyExplicit = 0;
    req->firstModMapKey = req->nModMapKeys = 0;
    req->firstVModMapKey = req->nVModMapKeys = 0;
    return req;
}

Status
#if NeedFunctionPrototypes
_XkbReadGetMapReply(	Display *	dpy,
			xkbGetMapReply *rep,
			XkbDescPtr	xkb,
			int *		nread_rtrn)
#else
_XkbReadGetMapReply(dpy,rep,xkb,nread_rtrn)
    Display *		dpy;
    xkbGetMapReply *	rep;
    XkbDescPtr		xkb;
    int *		nread_rtrn;
#endif
{
int		extraData;
unsigned	mask;

    if ( xkb->device_spec == XkbUseCoreKbd )
	xkb->device_spec= rep->deviceID;
    xkb->min_key_code = rep->minKeyCode;
    xkb->max_key_code = rep->maxKeyCode;

    if (!xkb->map) {
	mask= rep->present&XkbAllClientInfoMask;
	if (mask&&(XkbAllocClientMap(xkb,mask,rep->nTypes)!=Success))
	    return BadAlloc;
    }
    if (!xkb->server) {
	mask= rep->present&XkbAllServerInfoMask;
	if (mask&&(XkbAllocServerMap(xkb,mask,rep->totalActs)!=Success))
	    return BadAlloc;
    }
    extraData= (int)(rep->length*4);
    extraData-= (SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply));
    if (rep->length) {
	XkbReadBufferRec	buf;
	int			left;
	if (_XkbInitReadBuffer(dpy,&buf,extraData)) {
	    Status status= Success;
	    if (nread_rtrn!=NULL)
		*nread_rtrn= extraData;
	    if (status==Success)
		status= _XkbReadKeyTypes(&buf,xkb,rep);
	    if (status==Success)
		status= _XkbReadKeySyms(&buf,xkb,rep);
	    if (status==Success)
		status= _XkbReadKeyActions(&buf,xkb,rep);
	    if (status==Success)
		status= _XkbReadKeyBehaviors(&buf,xkb,rep);
	    if (status==Success)
		status= _XkbReadVirtualMods(&buf,xkb,rep);
	    if (status==Success)
		status= _XkbReadExplicitComponents(&buf,xkb,rep);
	    if (status==Success)
		status= _XkbReadModifierMap(&buf,xkb,rep);
	    if (status==Success)
		status= _XkbReadVirtualModMap(&buf,xkb,rep);
	    left= _XkbFreeReadBuffer(&buf);
	    if (status!=Success)		return status;
	    else if ( left || buf.error )	return BadLength;
	}
	else return BadAlloc;
    }
    return Success;
}

static Status
#if NeedFunctionPrototypes
_XkbHandleGetMapReply(Display *dpy,XkbDescPtr xkb)
#else
_XkbHandleGetMapReply(dpy,xkb)
    Display *	dpy;
    XkbDescPtr	xkb;
#endif
{
xkbGetMapReply	rep;

    if (!_XReply(dpy, (xReply *)&rep,
    		 ( (SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply)) >> 2 ), 
		 xFalse)) {
	return BadImplementation;
    }
    return _XkbReadGetMapReply(dpy,&rep,xkb,NULL);
}

Status
#if NeedFunctionPrototypes
XkbGetUpdatedMap(Display *dpy,unsigned which,XkbDescPtr xkb)
#else
XkbGetUpdatedMap(dpy,which,xkb)
    Display *	dpy;
    unsigned 	which;
    XkbDescPtr	xkb;
#endif
{
    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;
    if (which) {
	register xkbGetMapReq *req;
	Status status;

	LockDisplay(dpy);

	req = _XkbGetGetMapReq(dpy, xkb);
	req->full = which;
	status= _XkbHandleGetMapReply(dpy, xkb);

	UnlockDisplay(dpy);
	SyncHandle();
	return status;
    }
    return Success;
}

XkbDescPtr
#if NeedFunctionPrototypes
XkbGetMap(Display *dpy,unsigned which,unsigned deviceSpec)
#else
XkbGetMap(dpy,which,deviceSpec)
    Display *dpy;
    unsigned which;
    unsigned deviceSpec;
#endif
{
XkbDescPtr xkb;

    xkb = _XkbTypedCalloc(1,XkbDescRec);
    if (xkb) {
	xkb->device_spec = deviceSpec;
	xkb->map = _XkbTypedCalloc(1,XkbClientMapRec);
	if ((xkb->map==NULL)||
	    ((which)&&(XkbGetUpdatedMap(dpy,which,xkb)!=Success))) {
	    if (xkb->map) {
		Xfree(xkb->map);
		xkb->map= NULL;
	    }
	    Xfree(xkb);
	    return NULL;
	}
	xkb->dpy= dpy;
    }
    return xkb;
}

Status
#if NeedFunctionPrototypes
XkbGetKeyTypes(Display *dpy,unsigned first,unsigned num,XkbDescPtr xkb)
#else
XkbGetKeyTypes(dpy,first,num,xkb)
    Display *dpy;
    unsigned first;
    unsigned num;
    XkbDescPtr xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;
    if ((num<1)||(num>XkbMaxKeyTypes))
	return BadValue;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->firstType = first;
    req->nTypes = num;
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetKeyActions(Display *dpy,unsigned first,unsigned num,XkbDescPtr xkb)
#else
XkbGetKeyActions(dpy,first,num,xkb)
    Display *dpy;
    unsigned first;
    unsigned num;
    XkbDescPtr xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;

    if ((num<1)||(num>XkbMaxKeyCount))
	return BadValue;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->firstKeyAct = first;
    req->nKeyActs = num;
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetKeySyms(Display *dpy,unsigned first,unsigned num,XkbDescPtr xkb)
#else
XkbGetKeySyms(dpy,first,num,xkb)
    Display *dpy;
    unsigned first;
    unsigned num;
    XkbDescPtr xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;

    if ((num<1)||(num>XkbMaxKeyCount))
	return BadValue;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->firstKeySym = first;
    req->nKeySyms = num;
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();

    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetKeyBehaviors(Display *dpy,unsigned first,unsigned num,XkbDescPtr xkb)
#else
XkbGetKeyBehaviors(dpy,first,num,xkb)
    Display *	dpy;
    unsigned 	first;
    unsigned 	num;
    XkbDescPtr	xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;

    if ((num<1)||(num>XkbMaxKeyCount))
	return BadValue;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->firstKeyBehavior = first;
    req->nKeyBehaviors = num;
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetVirtualMods(Display *dpy,unsigned which,XkbDescPtr xkb)
#else
XkbGetVirtualMods(dpy,which,xkb)
    Display *	dpy;
    unsigned 	which;
    XkbDescPtr	xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->virtualMods = which;
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetKeyExplicitComponents(	Display *	dpy,
				unsigned	first,
				unsigned 	num,
				XkbDescPtr	xkb)
#else
XkbGetKeyExplicitComponents(dpy,first,num,xkb)
    Display *dpy;
    unsigned first;
    unsigned num;
    XkbDescPtr xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;

    if ((num<1)||(num>XkbMaxKeyCount))
	return BadValue;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->firstKeyExplicit = first;
    req->nKeyExplicit = num;
    if ((xkb!=NULL) && (xkb->server!=NULL) && (xkb->server->explicit!=NULL)) {
	if ((num>0)&&(first>=xkb->min_key_code)&&(first+num<=xkb->max_key_code))
	    bzero(&xkb->server->explicit[first],num);
    }
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetKeyModifierMap(Display *dpy,unsigned first,unsigned num,XkbDescPtr xkb)
#else
XkbGetKeyModifierMap(dpy,first,num,xkb)
    Display *	dpy;
    unsigned 	first;
    unsigned 	num;
    XkbDescPtr	xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;

    if ((num<1)||(num>XkbMaxKeyCount))
	return BadValue;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->firstModMapKey = first;
    req->nModMapKeys = num;
    if ((xkb!=NULL) && (xkb->map!=NULL) && (xkb->map->modmap!=NULL)) {
	if ((num>0)&&(first>=xkb->min_key_code)&&(first+num<=xkb->max_key_code))
	    bzero(&xkb->map->modmap[first],num);
    }
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetKeyVirtualModMap(Display *dpy,unsigned first,unsigned num,XkbDescPtr xkb)
#else
XkbGetKeyVirtualModMap(dpy,first,num,xkb)
    Display *dpy;
    unsigned first;
    unsigned num;
    XkbDescPtr xkb;
#endif
{
    register xkbGetMapReq *req;
    Status status;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;

    if ((num<1)||(num>XkbMaxKeyCount))
	return BadValue;

    LockDisplay(dpy);

    req = _XkbGetGetMapReq(dpy, xkb);
    req->firstVModMapKey = first;
    req->nVModMapKeys = num;
    if ((xkb!=NULL) && (xkb->map!=NULL) && (xkb->map->modmap!=NULL)) {
	if ((num>0)&&(first>=xkb->min_key_code)&&(first+num<=xkb->max_key_code))
	    bzero(&xkb->server->vmodmap[first],num*sizeof(unsigned short));
    }
    status= _XkbHandleGetMapReply(dpy, xkb);

    UnlockDisplay(dpy);
    SyncHandle();
    return status;
}

Status
#if NeedFunctionPrototypes
XkbGetMapChanges(Display *dpy,XkbDescPtr xkb,XkbMapChangesPtr changes)
#else
XkbGetMapChanges(dpy,xkb,changes)
    Display *		dpy;
    XkbDescPtr		xkb;
    XkbMapChangesPtr	changes;
#endif
{
    xkbGetMapReq *req;

    if ((dpy->flags & XlibDisplayNoXkb) ||
	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
	return BadAccess;
    LockDisplay(dpy);
    if (changes->changed) {
	Status status= Success;
	req = _XkbGetGetMapReq(dpy, xkb);
	req->full = 0;
	req->partial = changes->changed;
	req->firstType = changes->first_type;
	req->nTypes = changes->num_types;
	req->firstKeySym = changes->first_key_sym;
	req->nKeySyms = changes->num_key_syms;
	req->firstKeyAct = changes->first_key_act;
	req->nKeyActs = changes->num_key_acts;
	req->firstKeyBehavior = changes->first_key_behavior;
	req->nKeyBehaviors = changes->num_key_behaviors;
	req->virtualMods = changes->vmods;
	req->firstKeyExplicit = changes->first_key_explicit;
	req->nKeyExplicit = changes->num_key_explicit;
	req->firstModMapKey = changes->first_modmap_key;
	req->nModMapKeys = changes->num_modmap_keys;
	req->firstVModMapKey = changes->first_vmodmap_key;
	req->nVModMapKeys = changes->num_vmodmap_keys;
	status= _XkbHandleGetMapReply(dpy, xkb);
	SyncHandle();
	UnlockDisplay(dpy);
	return status;
    }
    UnlockDisplay(dpy);
    return Success;
}

