text: /************************************************************
  Copyright (c) 1995 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_CONFIG_H
  #include <config.h>
  #endif
  #include <stdio.h>
  #define	NEED_MAP_READERS
  #include "Xlibint.h"
  #include <X11/extensions/XKBproto.h>
  #include "XKBlibint.h"
  #include <X11/extensions/XI.h>
  
  /***====================================================================***/
  
  extern void
  XkbNoteDeviceChanges(	XkbDeviceChangesPtr		old,
  			XkbExtensionDeviceNotifyEvent *	new,
  			unsigned int			wanted)
  {
      if ((!old)||(!new)||(!wanted)||((new->reason&wanted)==0))
  	return;
      if ((wanted&new->reason)&XkbXI_ButtonActionsMask) {
  	if (old->changed&XkbXI_ButtonActionsMask) {
  	    int first,last,newLast;
  	    if (new->first_btn<old->first_btn)
  		 first= new->first_btn;
  	    else first= old->first_btn;
  	    last= old->first_btn+old->num_btns-1;
  	    newLast= new->first_btn+new->num_btns-1;
  	    if (newLast>last)
  		last= newLast;
  	    old->first_btn= first;
  	    old->num_btns= (last-first)+1;
  	}
  	else {
  	    old->changed|= XkbXI_ButtonActionsMask;
  	    old->first_btn= new->first_btn;
  	    old->num_btns= new->num_btns;
  	}
      }
      if ((wanted&new->reason)&XkbXI_IndicatorsMask) {
  	XkbDeviceLedChangesPtr this;
  	if (old->changed&XkbXI_IndicatorsMask) {
  	    XkbDeviceLedChangesPtr found;
  	    found= NULL;
  	    for (this= &old->leds;this&&(!found);this=this->next) {
  		if ((this->led_class==new->led_class)&&
  						(this->led_id==new->led_id)) {
  		    found= this;
  		}
  	    }
  	    if (!found) {
  		found= _XkbTypedCalloc(1,XkbDeviceLedChangesRec);
  		if (!found)
  		    return;
  		found->next= old->leds.next;
  		found->led_class= new->led_class;
  		found->led_id= new->led_id;
  		old->leds.next= found;
  	    }
  	    if ((wanted&new->reason)&XkbXI_IndicatorNamesMask)
  		found->defined= new->leds_defined;
  	}
  	else {
  	    old->changed|= ((wanted&new->reason)&XkbXI_IndicatorsMask);
  	    old->leds.led_class= new->led_class;
  	    old->leds.led_id= new->led_id;
  	    old->leds.defined= new->leds_defined;
  	    if (old->leds.next) {
  		XkbDeviceLedChangesPtr next;
  		for (this=old->leds.next;this;this=next) {
  		    next= this->next;
  		    _XkbFree(this);
  		}
  		old->leds.next= NULL;
  	    }
  	}
      }
      return;
  }
  
  /***====================================================================***/
  
  static Status
  _XkbReadDeviceLedInfo(	XkbReadBufferPtr	buf,
  			unsigned 		present,
  			XkbDeviceInfoPtr 	devi)
  {
  register unsigned	i,bit;
  XkbDeviceLedInfoPtr	devli;
  xkbDeviceLedsWireDesc *	wireli;
  
      wireli= _XkbGetTypedRdBufPtr(buf,1,xkbDeviceLedsWireDesc);
      if (!wireli)
  	return BadLength;
      devli= XkbAddDeviceLedInfo(devi,wireli->ledClass,wireli->ledID);
      if (!devli)
  	return BadAlloc;
      devli->phys_indicators= 	wireli->physIndicators;
  
      if (present&XkbXI_IndicatorStateMask)
  	devli->state= wireli->state;
  
      if (present&XkbXI_IndicatorNamesMask) {
  	devli->names_present= 	wireli->namesPresent;
  	if (devli->names_present) {
  	    for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
  		if (wireli->namesPresent&bit) {
  		    if (!_XkbCopyFromReadBuffer(buf,(char *)&devli->names[i],4))
  			return BadLength;
  		}
  	    }
  	}
      }
  
      if (present&XkbXI_IndicatorMapsMask) {
  	devli->maps_present= 	wireli->mapsPresent;
  	if (devli->maps_present) {
  	    XkbIndicatorMapPtr	 	im;
  	    xkbIndicatorMapWireDesc *	wireim;
  	    for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
  		if (wireli->mapsPresent&bit) {
  		    wireim= _XkbGetTypedRdBufPtr(buf,1,xkbIndicatorMapWireDesc);
  		    if (!wireim)
  			return BadAlloc;
  		    im= &devli->maps[i];
  		    im->flags= 		wireim->flags;
  		    im->which_groups= 	wireim->whichGroups;
  		    im->groups= 	wireim->groups;
  		    im->which_mods= 	wireim->whichMods;
  		    im->mods.mask= 	wireim->mods;
  		    im->mods.real_mods= wireim->realMods;
  		    im->mods.vmods= 	wireim->virtualMods;
  		    im->ctrls= 		wireim->ctrls;
  		}
  	    }
  	}
      }
      return Success;
  }
  
  static Status
  _XkbReadGetDeviceInfoReply(	Display *		dpy,
  				xkbGetDeviceInfoReply *	rep,
  				XkbDeviceInfoPtr	devi)
  {
  XkbReadBufferRec	buf;
  XkbAction *		act;
  int			tmp;
  
      if (!_XkbInitReadBuffer(dpy,&buf,(int)rep->length*4))
  	return BadAlloc;
  
      if ((rep->totalBtns>0)&&(rep->totalBtns!=devi->num_btns)) {
  	tmp= XkbResizeDeviceButtonActions(devi,rep->totalBtns);
  	if (tmp!=Success)
  	    return tmp;
      }
      if (rep->nBtnsWanted>0) {
  	act= &devi->btn_acts[rep->firstBtnWanted];
  	bzero((char *)act,(rep->nBtnsWanted*sizeof(XkbAction)));
      }
      if (devi->name!=NULL)
  	_XkbFree(devi->name);
      if (!_XkbGetReadBufferCountedString(&buf,&devi->name))
  	goto BAILOUT;
      if (rep->nBtnsRtrn>0) {
  	int size;
  	act= &devi->btn_acts[rep->firstBtnRtrn];
  	size= rep->nBtnsRtrn*SIZEOF(xkbActionWireDesc);
  	if (!_XkbCopyFromReadBuffer(&buf,(char *)act,size))
  	    goto BAILOUT;
      }
      if (rep->nDeviceLedFBs>0) {
  	register int 		i;
  	for (i=0;i<rep->nDeviceLedFBs;i++) {
  	    if ((tmp= _XkbReadDeviceLedInfo(&buf,rep->present,devi))!=Success)
  		return tmp;
  	}
      }
      tmp= _XkbFreeReadBuffer(&buf);
      if (tmp)
  	fprintf(stderr,"GetDeviceInfo! Bad length (%d extra bytes)\n",tmp);
      if (tmp || buf.error)
  	return BadLength;
      return Success;
  BAILOUT:
      _XkbFreeReadBuffer(&buf);
      return BadLength;
  }
  
  XkbDeviceInfoPtr
  XkbGetDeviceInfo(	Display *	dpy,
  			unsigned 	which,
  			unsigned 	deviceSpec,
  			unsigned 	class,
  			unsigned 	id)
  {
      register xkbGetDeviceInfoReq *	req;
      xkbGetDeviceInfoReply	 	rep;
      Status				status;
      XkbDeviceInfoPtr			devi;
  
      if ((dpy->flags & XlibDisplayNoXkb) ||
  	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
  	return NULL;
      LockDisplay(dpy);
      GetReq(kbGetDeviceInfo, req);
      req->reqType = dpy->xkb_info->codes->major_opcode;
      req->xkbReqType = X_kbGetDeviceInfo;
      req->deviceSpec = deviceSpec;
      req->wanted= which;
      req->allBtns= ((which&XkbXI_ButtonActionsMask)!=0);
      req->firstBtn= req->nBtns= 0;
      req->ledClass= class;
      req->ledID= id;
      if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
  	UnlockDisplay(dpy);
  	SyncHandle();
  	return NULL;
      }
      devi= XkbAllocDeviceInfo(rep.deviceID,rep.totalBtns,rep.nDeviceLedFBs);
      if (devi) {
  	devi->supported= rep.supported;
  	devi->unsupported= rep.unsupported;
  	devi->type= rep.devType;
  	devi->has_own_state= rep.hasOwnState;
  	devi->dflt_kbd_fb = rep.dfltKbdFB;
  	devi->dflt_led_fb = rep.dfltLedFB;
  	status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
  	if (status!=Success) {
  	    XkbFreeDeviceInfo(devi,XkbXI_AllDeviceFeaturesMask,True);
  	    devi= NULL;
  	}
      }
      UnlockDisplay(dpy);
      SyncHandle();
      return devi;
  }
  
  Status
  XkbGetDeviceInfoChanges(	Display *		dpy,
  				XkbDeviceInfoPtr 	devi,
  				XkbDeviceChangesPtr	changes)
  {
      register xkbGetDeviceInfoReq *	req;
      xkbGetDeviceInfoReply	 	rep;
      Status				status;
  
      if ((dpy->flags & XlibDisplayNoXkb) ||
  	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
  	return BadMatch;
      if ((changes->changed&XkbXI_AllDeviceFeaturesMask)==0)
  	return Success;
      changes->changed&= ~XkbXI_AllDeviceFeaturesMask;
      status= Success;
      LockDisplay(dpy);
      while ((changes->changed)&&(status==Success)) {
  	GetReq(kbGetDeviceInfo, req);
  	req->reqType = dpy->xkb_info->codes->major_opcode;
  	req->xkbReqType = X_kbGetDeviceInfo;
  	req->deviceSpec = devi->device_spec;
  	req->wanted= changes->changed;
  	req->allBtns= False;
  	if (changes->changed&XkbXI_ButtonActionsMask) {
  	     req->firstBtn= changes->first_btn;
  	     req->nBtns= 	changes->num_btns;
  	     changes->changed&= ~XkbXI_ButtonActionsMask;
  	}
  	else req->firstBtn= req->nBtns= 0;
  	if (changes->changed&XkbXI_IndicatorsMask) {
  	    req->ledClass= changes->leds.led_class;
  	    req->ledID= changes->leds.led_id;
  	    if (changes->leds.next==NULL)
  		changes->changed&= ~XkbXI_IndicatorsMask;
  	    else {
  		XkbDeviceLedChangesPtr next;
  		next= changes->leds.next;
  		changes->leds= *next;
  		_XkbFree(next);
  	    }
  	}
  	else {
  	    req->ledClass= XkbDfltXIClass;
  	    req->ledID= XkbDfltXIId;
  	}
  	if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
  	    status= BadLength;
  	    break;
  	}
  	devi->supported|= rep.supported;
  	devi->unsupported|= rep.unsupported;
  	devi->type= rep.devType;
  	status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
      }
      UnlockDisplay(dpy);
      SyncHandle();
      return status;
  }
  
  Status
  XkbGetDeviceButtonActions(	Display *		dpy,
  				XkbDeviceInfoPtr	devi,
  				Bool			all,
  				unsigned int		first,
  				unsigned int		num)
  {
      register xkbGetDeviceInfoReq *	req;
      xkbGetDeviceInfoReply	 	rep;
      Status				status;
  
      if ((dpy->flags & XlibDisplayNoXkb) ||
  	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
  	return BadMatch;
      if (!devi)
  	return BadValue;
      LockDisplay(dpy);
      GetReq(kbGetDeviceInfo, req);
      req->reqType = dpy->xkb_info->codes->major_opcode;
      req->xkbReqType = X_kbGetDeviceInfo;
      req->deviceSpec = devi->device_spec;
      req->wanted= XkbXI_ButtonActionsMask;
      req->allBtns= all;
      req->firstBtn= first;
      req->nBtns= num;
      req->ledClass= XkbDfltXIClass;
      req->ledID= XkbDfltXIId;
      if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
  	UnlockDisplay(dpy);
  	SyncHandle();
  	return BadLength;
      }
      devi->type= rep.devType;
      devi->supported= rep.supported;
      devi->unsupported= rep.unsupported;
      status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
      UnlockDisplay(dpy);
      SyncHandle();
      return status;
  }
  
  Status
  XkbGetDeviceLedInfo(	Display *		dpy,
  			XkbDeviceInfoPtr	devi,
  			unsigned int		ledClass,
  			unsigned int		ledId,
  			unsigned int		which)
  {
      register xkbGetDeviceInfoReq *	req;
      xkbGetDeviceInfoReply	 	rep;
      Status				status;
  
      if ((dpy->flags & XlibDisplayNoXkb) ||
  	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
  	return BadMatch;
      if (((which&XkbXI_IndicatorsMask)==0)||(which&(~XkbXI_IndicatorsMask)))
  	return BadMatch;
      if (!devi)
  	return BadValue;
      LockDisplay(dpy);
      GetReq(kbGetDeviceInfo, req);
      req->reqType = dpy->xkb_info->codes->major_opcode;
      req->xkbReqType = X_kbGetDeviceInfo;
      req->deviceSpec = devi->device_spec;
      req->wanted= which;
      req->allBtns= False;
      req->firstBtn= req->nBtns= 0;
      req->ledClass= ledClass;
      req->ledID= ledId;
      if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
  	UnlockDisplay(dpy);
  	SyncHandle();
  	return BadLength;
      }
      devi->type= rep.devType;
      devi->supported= rep.supported;
      devi->unsupported= rep.unsupported;
      status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
      UnlockDisplay(dpy);
      SyncHandle();
      return status;
  }
  
  /***====================================================================***/
  
  typedef struct _LedInfoStuff {
  	Bool			used;
  	XkbDeviceLedInfoPtr	devli;
  } LedInfoStuff;
  
  typedef struct _SetLedStuff {
  	unsigned		wanted;
  	int			num_info;
  	int			dflt_class;
  	LedInfoStuff *		dflt_kbd_fb;
  	LedInfoStuff *		dflt_led_fb;
  	LedInfoStuff *		info;
  } SetLedStuff;
  
  static void
  _InitLedStuff(SetLedStuff *stuff,unsigned wanted,XkbDeviceInfoPtr devi)
  {
  int				i;
  register XkbDeviceLedInfoPtr	devli;
  
      bzero(stuff,sizeof(SetLedStuff));
      stuff->wanted= wanted;
      stuff->dflt_class=	XkbXINone;
      if ((devi->num_leds<1)||((wanted&XkbXI_IndicatorsMask)==0))
  	return;
      stuff->info= _XkbTypedCalloc(devi->num_leds,LedInfoStuff);
      if (!stuff->info)
  	return;
      stuff->num_info= devi->num_leds;
      for (devli=&devi->leds[0],i=0;i<devi->num_leds;i++,devli++) {
  	stuff->info[i].devli= devli;
  	if (devli->led_class==KbdFeedbackClass) {
  	    stuff->dflt_class= KbdFeedbackClass;
  	    if (stuff->dflt_kbd_fb==NULL)
  		stuff->dflt_kbd_fb= &stuff->info[i];
  	}
  	else if (devli->led_class==LedFeedbackClass) {
  	    if (stuff->dflt_class==XkbXINone)
  		stuff->dflt_class= LedFeedbackClass;
  	    if (stuff->dflt_led_fb==NULL)
  		stuff->dflt_led_fb= &stuff->info[i];
  	}
      }
      return;
  }
  
  static void
  _FreeLedStuff(SetLedStuff *stuff)
  {
      if ((stuff->num_info>0)&&(stuff->info!=NULL))
  	_XkbFree(stuff->info);
      bzero(stuff,sizeof(SetLedStuff));
      return;
  }
  
  static int
  _XkbSizeLedInfo(unsigned changed,XkbDeviceLedInfoPtr devli)
  {
  register int i,size;
  register unsigned bit,namesNeeded,mapsNeeded;
  
      size= SIZEOF(xkbDeviceLedsWireDesc);
      namesNeeded= mapsNeeded= 0;
      if (changed&XkbXI_IndicatorNamesMask)
  	namesNeeded= devli->names_present;
      if (changed&XkbXI_IndicatorMapsMask)
  	mapsNeeded= devli->maps_present;
      if ((namesNeeded)||(mapsNeeded)) {
  	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
  	    if (namesNeeded&bit)
  		size+= 4; /* atoms are 4 bytes on the wire */
  	    if (mapsNeeded&bit)
  		size+= SIZEOF(xkbIndicatorMapWireDesc);
  	}
      }
      return size;
  }
  
  static Bool
  _SizeMatches(	SetLedStuff *		stuff,
  		XkbDeviceLedChangesPtr 	changes,
  		int *			sz_rtrn,
  		int *			nleds_rtrn)
  {
  int		i,nMatch,class,id;
  LedInfoStuff *	linfo;
  Bool		match;
  
      nMatch= 0;
      class= changes->led_class;
      id= changes->led_id;
      if (class==XkbDfltXIClass)
  	class= stuff->dflt_class;
      for (i=0,linfo=&stuff->info[0];i<stuff->num_info;i++,linfo++) {
  	XkbDeviceLedInfoPtr	devli;
  	LedInfoStuff *		dflt;
  
  	devli= linfo->devli;
  	match= ((class==devli->led_class)||(class==XkbAllXIClasses));
  	if (devli->led_class==KbdFeedbackClass)	dflt= stuff->dflt_kbd_fb;
  	else					dflt= stuff->dflt_led_fb;
  	match = (match && (id == devli->led_id)) ||
  	  (id == XkbAllXIIds) ||
  	  ((id == XkbDfltXIId) &&
  	   (linfo == dflt));
  	if (match) {
  	    if (!linfo->used) {
  		*sz_rtrn+= _XkbSizeLedInfo(stuff->wanted,devli);
  		*nleds_rtrn+= 1;
  		linfo->used= True;
  		if ((class!=XkbAllXIClasses)&&(id!=XkbAllXIIds))
  		    return True;
  	    }
  	    nMatch++;
  	    linfo->used= True;
  	}
      }
      return (nMatch>0);
  }
  
  /***====================================================================***/
  
  
  static Status
  _XkbSetDeviceInfoSize(	XkbDeviceInfoPtr	devi,
  			XkbDeviceChangesPtr	changes,
  			SetLedStuff *		stuff,
  			int *			sz_rtrn,
  			int *			num_leds_rtrn)
  {
      *sz_rtrn= 0;
      if ((changes->changed&XkbXI_ButtonActionsMask)&&(changes->num_btns>0)) {
  	if (!XkbXI_LegalDevBtn(devi,(changes->first_btn+changes->num_btns-1)))
  	    return BadMatch;
  	*sz_rtrn+= changes->num_btns*SIZEOF(xkbActionWireDesc);
      }
      else {
  	changes->changed&= ~XkbXI_ButtonActionsMask;
  	changes->first_btn= changes->num_btns= 0;
      }
      if ((changes->changed&XkbXI_IndicatorsMask)&&
  				XkbLegalXILedClass(changes->leds.led_class)) {
  	XkbDeviceLedChangesPtr	leds;
  
  	for (leds=&changes->leds;leds!=NULL;leds= leds->next) {
  	    if (!_SizeMatches(stuff,leds,sz_rtrn,num_leds_rtrn))
  		return BadMatch;
  	}
      }
      else {
  	changes->changed&= ~XkbXI_IndicatorsMask;
  	*num_leds_rtrn= 0;
      }
      return Success;
  }
  
  static char *
  _XkbWriteLedInfo(char *wire,unsigned changed,XkbDeviceLedInfoPtr devli)
  {
  register int 		i;
  register unsigned 	bit,namesNeeded,mapsNeeded;
  xkbDeviceLedsWireDesc *	lwire;
  
      namesNeeded= mapsNeeded= 0;
      if (changed&XkbXI_IndicatorNamesMask)
  	namesNeeded= devli->names_present;
      if (changed&XkbXI_IndicatorMapsMask)
  	mapsNeeded= devli->maps_present;
  
      lwire= (xkbDeviceLedsWireDesc *)wire;
      lwire->ledClass= devli->led_class;
      lwire->ledID= devli->led_id;
      lwire->namesPresent= namesNeeded;
      lwire->mapsPresent=  mapsNeeded;
      lwire->physIndicators= devli->phys_indicators;
      lwire->state= devli->state;
      wire= (char *)&lwire[1];
      if (namesNeeded) {
  	CARD32 *awire;
  	awire= (CARD32 *)wire;
  	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
  	    if (namesNeeded&bit) {
  		*awire= (CARD32)devli->names[i];
  		awire++;
  	    }
  	}
  	wire= (char *)awire;
      }
      if (mapsNeeded) {
  	xkbIndicatorMapWireDesc *mwire;
  
  	mwire= (xkbIndicatorMapWireDesc *)wire;
  	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
  	    if (mapsNeeded&bit) {
  		XkbIndicatorMapPtr	map;
  		map= 			&devli->maps[i];
  		mwire->flags= 		map->flags;
  		mwire->whichGroups=	map->which_groups;
  		mwire->groups=		map->groups;
  		mwire->whichMods=	map->which_mods;
  		mwire->mods=		map->mods.mask;
  		mwire->realMods=	map->mods.real_mods;
  		mwire->virtualMods=	map->mods.vmods;
  		mwire->ctrls=		map->ctrls;
  		mwire++;
  	    }
  	}
  	wire= (char *)mwire;
      }
      return wire;
  }
  
  
  static int
  _XkbWriteSetDeviceInfo(	char *			wire,
  			XkbDeviceChangesPtr	changes,
  			SetLedStuff *		stuff,
  			XkbDeviceInfoPtr	devi)
  {
  char *start;
  
      start= wire;
      if (changes->changed&XkbXI_ButtonActionsMask) {
  	int			size;
  	size= changes->num_btns*SIZEOF(xkbActionWireDesc);
  	memcpy(wire,(char *)&devi->btn_acts[changes->first_btn],size);
  	wire+= size;
      }
      if (changes->changed&XkbXI_IndicatorsMask) {
  	register int i;
  	register LedInfoStuff *linfo;
  
  	for (i=0,linfo=&stuff->info[0];i<stuff->num_info;i++,linfo++) {
  	    if (linfo->used) {
  		register char *new_wire;
  		new_wire= _XkbWriteLedInfo(wire,stuff->wanted,linfo->devli);
  		if (!new_wire)
  		    return wire-start;
  		wire= new_wire;
  	    }
  	}
      }
      return wire-start;
  }
  
  Bool
  XkbSetDeviceInfo(	Display *		dpy,
  			unsigned 		which,
  			XkbDeviceInfoPtr	devi)
  {
      register xkbSetDeviceInfoReq *req;
      Status		     	ok = 0;
      int				size,nLeds;
      XkbInfoPtr 			xkbi;
      XkbDeviceChangesRec		changes;
      SetLedStuff			lstuff;
  
      if ((dpy->flags & XlibDisplayNoXkb) ||
  	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
  	return False;
      if ((!devi) || (which&(~XkbXI_AllDeviceFeaturesMask)) ||
  	((which&XkbXI_ButtonActionsMask)&&(!XkbXI_DevHasBtnActs(devi)))||
  	((which&XkbXI_IndicatorsMask)&&(!XkbXI_DevHasLeds(devi))))
  	return False;
  
      bzero((char *)&changes,sizeof(XkbDeviceChangesRec));
      changes.changed= which;
      changes.first_btn=		0;
      changes.num_btns=		devi->num_btns;
      changes.leds.led_class=	XkbAllXIClasses;
      changes.leds.led_id=	XkbAllXIIds;
      changes.leds.defined=	0;
      size= nLeds= 		0;
      _InitLedStuff(&lstuff,changes.changed,devi);
      if (_XkbSetDeviceInfoSize(devi,&changes,&lstuff,&size,&nLeds)!=Success)
  	return False;
      LockDisplay(dpy);
      xkbi = dpy->xkb_info;
      GetReq(kbSetDeviceInfo, req);
      req->length+=	size/4;
      req->reqType= 	xkbi->codes->major_opcode;
      req->xkbReqType= 	X_kbSetDeviceInfo;
      req->deviceSpec= 	devi->device_spec;
      req->firstBtn=	changes.first_btn;
      req->nBtns=		changes.num_btns;
      req->change=	changes.changed;
      req->nDeviceLedFBs=	nLeds;
      if (size>0) {
  	char * 	wire;
  	BufAlloc(char *,wire,size);
  	ok= (wire!=NULL)&&
  		(_XkbWriteSetDeviceInfo(wire,&changes,&lstuff,devi)==size);
      }
      UnlockDisplay(dpy);
      SyncHandle();
      _FreeLedStuff(&lstuff);
      /* 12/11/95 (ef) -- XXX!! should clear changes here */
      return ok;
  }
  
  Bool
  XkbChangeDeviceInfo(	Display *		dpy,
  			XkbDeviceInfoPtr	devi,
  			XkbDeviceChangesPtr	changes)
  {
      register xkbSetDeviceInfoReq *req;
      Status		     	ok = 0;
      int				size,nLeds;
      XkbInfoPtr 			xkbi;
      SetLedStuff			lstuff;
  
      if ((dpy->flags & XlibDisplayNoXkb) ||
  	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
  	return False;
      if ((!devi) || (changes->changed&(~XkbXI_AllDeviceFeaturesMask)) ||
  	((changes->changed&XkbXI_ButtonActionsMask)&&
  					(!XkbXI_DevHasBtnActs(devi)))||
  	((changes->changed&XkbXI_IndicatorsMask)&&(!XkbXI_DevHasLeds(devi))))
  	return False;
  
      size= nLeds= 0;
      _InitLedStuff(&lstuff,changes->changed,devi);
      if (_XkbSetDeviceInfoSize(devi,changes,&lstuff,&size,&nLeds)!=Success)
  	return False;
      LockDisplay(dpy);
      xkbi = dpy->xkb_info;
      GetReq(kbSetDeviceInfo, req);
      req->length+=	size/4;
      req->reqType= 	xkbi->codes->major_opcode;
      req->xkbReqType= 	X_kbSetDeviceInfo;
      req->deviceSpec= 	devi->device_spec;
      req->firstBtn=	changes->first_btn;
      req->nBtns=		changes->num_btns;
      req->change=	changes->changed;
      req->nDeviceLedFBs=	nLeds;
      if (size>0) {
  	char * 	wire;
  	BufAlloc(char *,wire,size);
  	ok= (wire!=NULL)&&
  		(_XkbWriteSetDeviceInfo(wire,changes,&lstuff,devi)==size);
      }
      UnlockDisplay(dpy);
      SyncHandle();
      _FreeLedStuff(&lstuff);
      /* 12/11/95 (ef) -- XXX!! should clear changes here */
      return ok;
  }
  
  Bool
  XkbSetDeviceLedInfo(	Display *		dpy,
  			XkbDeviceInfoPtr	devi,
  			unsigned 		ledClass,
  			unsigned		ledID,
  			unsigned		which)
  {
      return False;
  }
  
  Bool
  XkbSetDeviceButtonActions(	Display *		dpy,
  				XkbDeviceInfoPtr 	devi,
  				unsigned int		first,
  				unsigned int		nBtns)
  {
      register xkbSetDeviceInfoReq *req;
      Status		     	ok = 0;
      int				size,nLeds;
      XkbInfoPtr 			xkbi;
      XkbDeviceChangesRec		changes;
      SetLedStuff			lstuff;
  
      if ((dpy->flags & XlibDisplayNoXkb) ||
  	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
  	return False;
      if ((!devi)||(!XkbXI_DevHasBtnActs(devi))||(first+nBtns>devi->num_btns))
  	return False;
      if (nBtns==0)
  	return True;
  
      bzero((char *)&changes,sizeof(XkbDeviceChangesRec));
      changes.changed= 		XkbXI_ButtonActionsMask;
      changes.first_btn=		first;
      changes.num_btns=		nBtns;
      changes.leds.led_class=	XkbXINone;
      changes.leds.led_id=	XkbXINone;
      changes.leds.defined=	0;
      size= nLeds= 		0;
      if (_XkbSetDeviceInfoSize(devi,&changes,NULL,&size,&nLeds)!=Success)
  	return False;
      LockDisplay(dpy);
      xkbi = dpy->xkb_info;
      GetReq(kbSetDeviceInfo, req);
      req->length+=	size/4;
      req->reqType= 	xkbi->codes->major_opcode;
      req->xkbReqType= 	X_kbSetDeviceInfo;
      req->deviceSpec= 	devi->device_spec;
      req->firstBtn=	changes.first_btn;
      req->nBtns=		changes.num_btns;
      req->change=	changes.changed;
      req->nDeviceLedFBs=	nLeds;
      if (size>0) {
  	char * 	wire;
  	BufAlloc(char *,wire,size);
  	ok= (wire!=NULL)&&
  		(_XkbWriteSetDeviceInfo(wire,&changes,&lstuff,devi)==size);
      }
      UnlockDisplay(dpy);
      SyncHandle();
      return ok;
  }
  