XKBExtDev.c revision 61b2299d
1/* $Xorg: XKBExtDev.c,v 1.3 2000/08/17 19:45:01 cpqbld Exp $ */
2/************************************************************
3Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
4
5Permission to use, copy, modify, and distribute this
6software and its documentation for any purpose and without
7fee is hereby granted, provided that the above copyright
8notice appear in all copies and that both that copyright
9notice and this permission notice appear in supporting
10documentation, and that the name of Silicon Graphics not be
11used in advertising or publicity pertaining to distribution
12of the software without specific prior written permission.
13Silicon Graphics makes no representation about the suitability
14of this software for any purpose. It is provided "as is"
15without any express or implied warranty.
16
17SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
19AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
20GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
23OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
24THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
26********************************************************/
27/* $XFree86: xc/lib/X11/XKBExtDev.c,v 3.4 2001/10/28 03:32:33 tsi Exp $ */
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <stdio.h>
33#define NEED_REPLIES
34#define NEED_EVENTS
35#define	NEED_MAP_READERS
36#include "Xlibint.h"
37#include <X11/extensions/XKBproto.h>
38#include "XKBlibint.h"
39#include <X11/extensions/XI.h>
40
41/***====================================================================***/
42
43extern void
44XkbNoteDeviceChanges(	XkbDeviceChangesPtr		old,
45			XkbExtensionDeviceNotifyEvent *	new,
46			unsigned int			wanted)
47{
48    if ((!old)||(!new)||(!wanted)||((new->reason&wanted)==0))
49	return;
50    if ((wanted&new->reason)&XkbXI_ButtonActionsMask) {
51	if (old->changed&XkbXI_ButtonActionsMask) {
52	    int first,last,newLast;
53	    if (new->first_btn<old->first_btn)
54		 first= new->first_btn;
55	    else first= old->first_btn;
56	    last= old->first_btn+old->num_btns-1;
57	    newLast= new->first_btn+new->num_btns-1;
58	    if (newLast>last)
59		last= newLast;
60	    old->first_btn= first;
61	    old->num_btns= (last-first)+1;
62	}
63	else {
64	    old->changed|= XkbXI_ButtonActionsMask;
65	    old->first_btn= new->first_btn;
66	    old->num_btns= new->num_btns;
67	}
68    }
69    if ((wanted&new->reason)&XkbXI_IndicatorsMask) {
70	XkbDeviceLedChangesPtr this;
71	if (old->changed&XkbXI_IndicatorsMask) {
72	    XkbDeviceLedChangesPtr found;
73	    found= NULL;
74	    for (this= &old->leds;this&&(!found);this=this->next) {
75		if ((this->led_class==new->led_class)&&
76						(this->led_id==new->led_id)) {
77		    found= this;
78		}
79	    }
80	    if (!found) {
81		found= _XkbTypedCalloc(1,XkbDeviceLedChangesRec);
82		if (!found)
83		    return;
84		found->next= old->leds.next;
85		found->led_class= new->led_class;
86		found->led_id= new->led_id;
87		old->leds.next= found;
88	    }
89	    if ((wanted&new->reason)&XkbXI_IndicatorNamesMask)
90		found->defined= new->leds_defined;
91	}
92	else {
93	    old->changed|= ((wanted&new->reason)&XkbXI_IndicatorsMask);
94	    old->leds.led_class= new->led_class;
95	    old->leds.led_id= new->led_id;
96	    old->leds.defined= new->leds_defined;
97	    if (old->leds.next) {
98		XkbDeviceLedChangesPtr next;
99		for (this=old->leds.next;this;this=next) {
100		    next= this->next;
101		    _XkbFree(this);
102		}
103		old->leds.next= NULL;
104	    }
105	}
106    }
107    return;
108}
109
110/***====================================================================***/
111
112static Status
113_XkbReadDeviceLedInfo(	XkbReadBufferPtr	buf,
114			unsigned 		present,
115			XkbDeviceInfoPtr 	devi)
116{
117register unsigned	i,bit;
118XkbDeviceLedInfoPtr	devli;
119xkbDeviceLedsWireDesc *	wireli;
120
121    wireli= _XkbGetTypedRdBufPtr(buf,1,xkbDeviceLedsWireDesc);
122    if (!wireli)
123	return BadLength;
124    devli= XkbAddDeviceLedInfo(devi,wireli->ledClass,wireli->ledID);
125    if (!devli)
126	return BadAlloc;
127    devli->phys_indicators= 	wireli->physIndicators;
128
129    if (present&XkbXI_IndicatorStateMask)
130	devli->state= wireli->state;
131
132    if (present&XkbXI_IndicatorNamesMask) {
133	devli->names_present= 	wireli->namesPresent;
134	if (devli->names_present) {
135	    for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
136		if (wireli->namesPresent&bit) {
137		    if (!_XkbCopyFromReadBuffer(buf,(char *)&devli->names[i],4))
138			return BadLength;
139		}
140	    }
141	}
142    }
143
144    if (present&XkbXI_IndicatorMapsMask) {
145	devli->maps_present= 	wireli->mapsPresent;
146	if (devli->maps_present) {
147	    XkbIndicatorMapPtr	 	im;
148	    xkbIndicatorMapWireDesc *	wireim;
149	    for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
150		if (wireli->mapsPresent&bit) {
151		    wireim= _XkbGetTypedRdBufPtr(buf,1,xkbIndicatorMapWireDesc);
152		    if (!wireim)
153			return BadAlloc;
154		    im= &devli->maps[i];
155		    im->flags= 		wireim->flags;
156		    im->which_groups= 	wireim->whichGroups;
157		    im->groups= 	wireim->groups;
158		    im->which_mods= 	wireim->whichMods;
159		    im->mods.mask= 	wireim->mods;
160		    im->mods.real_mods= wireim->realMods;
161		    im->mods.vmods= 	wireim->virtualMods;
162		    im->ctrls= 		wireim->ctrls;
163		}
164	    }
165	}
166    }
167    return Success;
168}
169
170static Status
171_XkbReadGetDeviceInfoReply(	Display *		dpy,
172				xkbGetDeviceInfoReply *	rep,
173				XkbDeviceInfoPtr	devi)
174{
175XkbReadBufferRec	buf;
176XkbAction *		act;
177int			tmp;
178
179    if (!_XkbInitReadBuffer(dpy,&buf,(int)rep->length*4))
180	return BadAlloc;
181
182    if ((rep->totalBtns>0)&&(rep->totalBtns!=devi->num_btns)) {
183	tmp= XkbResizeDeviceButtonActions(devi,rep->totalBtns);
184	if (tmp!=Success)
185	    return tmp;
186    }
187    if (rep->nBtnsWanted>0) {
188	act= &devi->btn_acts[rep->firstBtnWanted];
189	bzero((char *)act,(rep->nBtnsWanted*sizeof(XkbAction)));
190    }
191    if (devi->name!=NULL)
192	_XkbFree(devi->name);
193    if (!_XkbGetReadBufferCountedString(&buf,&devi->name))
194	goto BAILOUT;
195    if (rep->nBtnsRtrn>0) {
196	int size;
197	act= &devi->btn_acts[rep->firstBtnRtrn];
198	size= rep->nBtnsRtrn*SIZEOF(xkbActionWireDesc);
199	if (!_XkbCopyFromReadBuffer(&buf,(char *)act,size))
200	    goto BAILOUT;
201    }
202    if (rep->nDeviceLedFBs>0) {
203	register int 		i;
204	for (i=0;i<rep->nDeviceLedFBs;i++) {
205	    if ((tmp= _XkbReadDeviceLedInfo(&buf,rep->present,devi))!=Success)
206		return tmp;
207	}
208    }
209    tmp= _XkbFreeReadBuffer(&buf);
210    if (tmp)
211	fprintf(stderr,"GetDeviceInfo! Bad length (%d extra bytes)\n",tmp);
212    if (tmp || buf.error)
213	return BadLength;
214    return Success;
215BAILOUT:
216    _XkbFreeReadBuffer(&buf);
217    return BadLength;
218}
219
220XkbDeviceInfoPtr
221XkbGetDeviceInfo(	Display *	dpy,
222			unsigned 	which,
223			unsigned 	deviceSpec,
224			unsigned 	class,
225			unsigned 	id)
226{
227    register xkbGetDeviceInfoReq *	req;
228    xkbGetDeviceInfoReply	 	rep;
229    Status				status;
230    XkbDeviceInfoPtr			devi;
231
232    if ((dpy->flags & XlibDisplayNoXkb) ||
233	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
234	return NULL;
235    LockDisplay(dpy);
236    GetReq(kbGetDeviceInfo, req);
237    req->reqType = dpy->xkb_info->codes->major_opcode;
238    req->xkbReqType = X_kbGetDeviceInfo;
239    req->deviceSpec = deviceSpec;
240    req->wanted= which;
241    req->allBtns= ((which&XkbXI_ButtonActionsMask)!=0);
242    req->firstBtn= req->nBtns= 0;
243    req->ledClass= class;
244    req->ledID= id;
245    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
246	UnlockDisplay(dpy);
247	SyncHandle();
248	return NULL;
249    }
250    devi= XkbAllocDeviceInfo(rep.deviceID,rep.totalBtns,rep.nDeviceLedFBs);
251    if (devi) {
252	devi->supported= rep.supported;
253	devi->unsupported= rep.unsupported;
254	devi->type= rep.devType;
255	devi->has_own_state= rep.hasOwnState;
256	devi->dflt_kbd_fb = rep.dfltKbdFB;
257	devi->dflt_led_fb = rep.dfltLedFB;
258	status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
259	if (status!=Success) {
260	    XkbFreeDeviceInfo(devi,XkbXI_AllDeviceFeaturesMask,True);
261	    devi= NULL;
262	}
263    }
264    UnlockDisplay(dpy);
265    SyncHandle();
266    return devi;
267}
268
269Status
270XkbGetDeviceInfoChanges(	Display *		dpy,
271				XkbDeviceInfoPtr 	devi,
272				XkbDeviceChangesPtr	changes)
273{
274    register xkbGetDeviceInfoReq *	req;
275    xkbGetDeviceInfoReply	 	rep;
276    Status				status;
277
278    if ((dpy->flags & XlibDisplayNoXkb) ||
279	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
280	return BadMatch;
281    if ((changes->changed&XkbXI_AllDeviceFeaturesMask)==0)
282	return Success;
283    changes->changed&= ~XkbXI_AllDeviceFeaturesMask;
284    status= Success;
285    LockDisplay(dpy);
286    while ((changes->changed)&&(status==Success)) {
287	GetReq(kbGetDeviceInfo, req);
288	req->reqType = dpy->xkb_info->codes->major_opcode;
289	req->xkbReqType = X_kbGetDeviceInfo;
290	req->deviceSpec = devi->device_spec;
291	req->wanted= changes->changed;
292	req->allBtns= False;
293	if (changes->changed&XkbXI_ButtonActionsMask) {
294	     req->firstBtn= changes->first_btn;
295	     req->nBtns= 	changes->num_btns;
296	     changes->changed&= ~XkbXI_ButtonActionsMask;
297	}
298	else req->firstBtn= req->nBtns= 0;
299	if (changes->changed&XkbXI_IndicatorsMask) {
300	    req->ledClass= changes->leds.led_class;
301	    req->ledID= changes->leds.led_id;
302	    if (changes->leds.next==NULL)
303		changes->changed&= ~XkbXI_IndicatorsMask;
304	    else {
305		XkbDeviceLedChangesPtr next;
306		next= changes->leds.next;
307		changes->leds= *next;
308		_XkbFree(next);
309	    }
310	}
311	else {
312	    req->ledClass= XkbDfltXIClass;
313	    req->ledID= XkbDfltXIId;
314	}
315	if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
316	    status= BadLength;
317	    break;
318	}
319	devi->supported|= rep.supported;
320	devi->unsupported|= rep.unsupported;
321	devi->type= rep.devType;
322	status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
323    }
324    UnlockDisplay(dpy);
325    SyncHandle();
326    return status;
327}
328
329Status
330XkbGetDeviceButtonActions(	Display *		dpy,
331				XkbDeviceInfoPtr	devi,
332				Bool			all,
333				unsigned int		first,
334				unsigned int		num)
335{
336    register xkbGetDeviceInfoReq *	req;
337    xkbGetDeviceInfoReply	 	rep;
338    Status				status;
339
340    if ((dpy->flags & XlibDisplayNoXkb) ||
341	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
342	return BadMatch;
343    if (!devi)
344	return BadValue;
345    LockDisplay(dpy);
346    GetReq(kbGetDeviceInfo, req);
347    req->reqType = dpy->xkb_info->codes->major_opcode;
348    req->xkbReqType = X_kbGetDeviceInfo;
349    req->deviceSpec = devi->device_spec;
350    req->wanted= XkbXI_ButtonActionsMask;
351    req->allBtns= all;
352    req->firstBtn= first;
353    req->nBtns= num;
354    req->ledClass= XkbDfltXIClass;
355    req->ledID= XkbDfltXIId;
356    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
357	UnlockDisplay(dpy);
358	SyncHandle();
359	return BadLength;
360    }
361    devi->type= rep.devType;
362    devi->supported= rep.supported;
363    devi->unsupported= rep.unsupported;
364    status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
365    UnlockDisplay(dpy);
366    SyncHandle();
367    return status;
368}
369
370Status
371XkbGetDeviceLedInfo(	Display *		dpy,
372			XkbDeviceInfoPtr	devi,
373			unsigned int		ledClass,
374			unsigned int		ledId,
375			unsigned int		which)
376{
377    register xkbGetDeviceInfoReq *	req;
378    xkbGetDeviceInfoReply	 	rep;
379    Status				status;
380
381    if ((dpy->flags & XlibDisplayNoXkb) ||
382	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
383	return BadMatch;
384    if (((which&XkbXI_IndicatorsMask)==0)||(which&(~XkbXI_IndicatorsMask)))
385	return BadMatch;
386    if (!devi)
387	return BadValue;
388    LockDisplay(dpy);
389    GetReq(kbGetDeviceInfo, req);
390    req->reqType = dpy->xkb_info->codes->major_opcode;
391    req->xkbReqType = X_kbGetDeviceInfo;
392    req->deviceSpec = devi->device_spec;
393    req->wanted= which;
394    req->allBtns= False;
395    req->firstBtn= req->nBtns= 0;
396    req->ledClass= ledClass;
397    req->ledID= ledId;
398    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
399	UnlockDisplay(dpy);
400	SyncHandle();
401	return BadLength;
402    }
403    devi->type= rep.devType;
404    devi->supported= rep.supported;
405    devi->unsupported= rep.unsupported;
406    status= _XkbReadGetDeviceInfoReply(dpy,&rep,devi);
407    UnlockDisplay(dpy);
408    SyncHandle();
409    return status;
410}
411
412/***====================================================================***/
413
414typedef struct _LedInfoStuff {
415	Bool			used;
416	XkbDeviceLedInfoPtr	devli;
417} LedInfoStuff;
418
419typedef struct _SetLedStuff {
420	unsigned		wanted;
421	int			num_info;
422	int			dflt_class;
423	LedInfoStuff *		dflt_kbd_fb;
424	LedInfoStuff *		dflt_led_fb;
425	LedInfoStuff *		info;
426} SetLedStuff;
427
428static void
429_InitLedStuff(SetLedStuff *stuff,unsigned wanted,XkbDeviceInfoPtr devi)
430{
431int				i;
432register XkbDeviceLedInfoPtr	devli;
433
434    bzero(stuff,sizeof(SetLedStuff));
435    stuff->wanted= wanted;
436    stuff->dflt_class=	XkbXINone;
437    if ((devi->num_leds<1)||((wanted&XkbXI_IndicatorsMask)==0))
438	return;
439    stuff->info= _XkbTypedCalloc(devi->num_leds,LedInfoStuff);
440    if (!stuff->info)
441	return;
442    stuff->num_info= devi->num_leds;
443    for (devli=&devi->leds[0],i=0;i<devi->num_leds;i++,devli++) {
444	stuff->info[i].devli= devli;
445	if (devli->led_class==KbdFeedbackClass) {
446	    stuff->dflt_class= KbdFeedbackClass;
447	    if (stuff->dflt_kbd_fb==NULL)
448		stuff->dflt_kbd_fb= &stuff->info[i];
449	}
450	else if (devli->led_class==LedFeedbackClass) {
451	    if (stuff->dflt_class==XkbXINone)
452		stuff->dflt_class= LedFeedbackClass;
453	    if (stuff->dflt_led_fb==NULL)
454		stuff->dflt_led_fb= &stuff->info[i];
455	}
456    }
457    return;
458}
459
460static void
461_FreeLedStuff(SetLedStuff *stuff)
462{
463    if ((stuff->num_info>0)&&(stuff->info!=NULL))
464	_XkbFree(stuff->info);
465    bzero(stuff,sizeof(SetLedStuff));
466    return;
467}
468
469static int
470_XkbSizeLedInfo(unsigned changed,XkbDeviceLedInfoPtr devli)
471{
472register int i,size;
473register unsigned bit,namesNeeded,mapsNeeded;
474
475    size= SIZEOF(xkbDeviceLedsWireDesc);
476    namesNeeded= mapsNeeded= 0;
477    if (changed&XkbXI_IndicatorNamesMask)
478	namesNeeded= devli->names_present;
479    if (changed&XkbXI_IndicatorMapsMask)
480	mapsNeeded= devli->maps_present;
481    if ((namesNeeded)||(mapsNeeded)) {
482	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
483	    if (namesNeeded&bit)
484		size+= 4; /* atoms are 4 bytes on the wire */
485	    if (mapsNeeded&bit)
486		size+= SIZEOF(xkbIndicatorMapWireDesc);
487	}
488    }
489    return size;
490}
491
492static Bool
493_SizeMatches(	SetLedStuff *		stuff,
494		XkbDeviceLedChangesPtr 	changes,
495		int *			sz_rtrn,
496		int *			nleds_rtrn)
497{
498int		i,nMatch,class,id;
499LedInfoStuff *	linfo;
500Bool		match;
501
502    nMatch= 0;
503    class= changes->led_class;
504    id= changes->led_id;
505    if (class==XkbDfltXIClass)
506	class= stuff->dflt_class;
507    for (i=0,linfo=&stuff->info[0];i<stuff->num_info;i++,linfo++) {
508	XkbDeviceLedInfoPtr	devli;
509	LedInfoStuff *		dflt;
510
511	devli= linfo->devli;
512	match= ((class==devli->led_class)||(class==XkbAllXIClasses));
513	if (devli->led_class==KbdFeedbackClass)	dflt= stuff->dflt_kbd_fb;
514	else					dflt= stuff->dflt_led_fb;
515	match = (match && (id == devli->led_id)) ||
516	  (id == XkbAllXIIds) ||
517	  ((id == XkbDfltXIId) &&
518	   (linfo == dflt));
519	if (match) {
520	    if (!linfo->used) {
521		*sz_rtrn+= _XkbSizeLedInfo(stuff->wanted,devli);
522		*nleds_rtrn+= 1;
523		linfo->used= True;
524		if ((class!=XkbAllXIClasses)&&(id!=XkbAllXIIds))
525		    return True;
526	    }
527	    nMatch++;
528	    linfo->used= True;
529	}
530    }
531    return (nMatch>0);
532}
533
534/***====================================================================***/
535
536
537static Status
538_XkbSetDeviceInfoSize(	XkbDeviceInfoPtr	devi,
539			XkbDeviceChangesPtr	changes,
540			SetLedStuff *		stuff,
541			int *			sz_rtrn,
542			int *			num_leds_rtrn)
543{
544    *sz_rtrn= 0;
545    if ((changes->changed&XkbXI_ButtonActionsMask)&&(changes->num_btns>0)) {
546	if (!XkbXI_LegalDevBtn(devi,(changes->first_btn+changes->num_btns-1)))
547	    return BadMatch;
548	*sz_rtrn+= changes->num_btns*SIZEOF(xkbActionWireDesc);
549    }
550    else {
551	changes->changed&= ~XkbXI_ButtonActionsMask;
552	changes->first_btn= changes->num_btns= 0;
553    }
554    if ((changes->changed&XkbXI_IndicatorsMask)&&
555				XkbLegalXILedClass(changes->leds.led_class)) {
556	XkbDeviceLedChangesPtr	leds;
557
558	for (leds=&changes->leds;leds!=NULL;leds= leds->next) {
559	    if (!_SizeMatches(stuff,leds,sz_rtrn,num_leds_rtrn))
560		return BadMatch;
561	}
562    }
563    else {
564	changes->changed&= ~XkbXI_IndicatorsMask;
565	*num_leds_rtrn= 0;
566    }
567    return Success;
568}
569
570static char *
571_XkbWriteLedInfo(char *wire,unsigned changed,XkbDeviceLedInfoPtr devli)
572{
573register int 		i;
574register unsigned 	bit,namesNeeded,mapsNeeded;
575xkbDeviceLedsWireDesc *	lwire;
576
577    namesNeeded= mapsNeeded= 0;
578    if (changed&XkbXI_IndicatorNamesMask)
579	namesNeeded= devli->names_present;
580    if (changed&XkbXI_IndicatorMapsMask)
581	mapsNeeded= devli->maps_present;
582
583    lwire= (xkbDeviceLedsWireDesc *)wire;
584    lwire->ledClass= devli->led_class;
585    lwire->ledID= devli->led_id;
586    lwire->namesPresent= namesNeeded;
587    lwire->mapsPresent=  mapsNeeded;
588    lwire->physIndicators= devli->phys_indicators;
589    lwire->state= devli->state;
590    wire= (char *)&lwire[1];
591    if (namesNeeded) {
592	CARD32 *awire;
593	awire= (CARD32 *)wire;
594	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
595	    if (namesNeeded&bit) {
596		*awire= (CARD32)devli->names[i];
597		awire++;
598	    }
599	}
600	wire= (char *)awire;
601    }
602    if (mapsNeeded) {
603	xkbIndicatorMapWireDesc *mwire;
604
605	mwire= (xkbIndicatorMapWireDesc *)wire;
606	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
607	    if (mapsNeeded&bit) {
608		XkbIndicatorMapPtr	map;
609		map= 			&devli->maps[i];
610		mwire->flags= 		map->flags;
611		mwire->whichGroups=	map->which_groups;
612		mwire->groups=		map->groups;
613		mwire->whichMods=	map->which_mods;
614		mwire->mods=		map->mods.mask;
615		mwire->realMods=	map->mods.real_mods;
616		mwire->virtualMods=	map->mods.vmods;
617		mwire->ctrls=		map->ctrls;
618		mwire++;
619	    }
620	}
621	wire= (char *)mwire;
622    }
623    return wire;
624}
625
626
627static int
628_XkbWriteSetDeviceInfo(	char *			wire,
629			XkbDeviceChangesPtr	changes,
630			SetLedStuff *		stuff,
631			XkbDeviceInfoPtr	devi)
632{
633char *start;
634
635    start= wire;
636    if (changes->changed&XkbXI_ButtonActionsMask) {
637	int			size;
638	size= changes->num_btns*SIZEOF(xkbActionWireDesc);
639	memcpy(wire,(char *)&devi->btn_acts[changes->first_btn],size);
640	wire+= size;
641    }
642    if (changes->changed&XkbXI_IndicatorsMask) {
643	register int i;
644	register LedInfoStuff *linfo;
645
646	for (i=0,linfo=&stuff->info[0];i<stuff->num_info;i++,linfo++) {
647	    if (linfo->used) {
648		register char *new_wire;
649		new_wire= _XkbWriteLedInfo(wire,stuff->wanted,linfo->devli);
650		if (!new_wire)
651		    return wire-start;
652		wire= new_wire;
653	    }
654	}
655    }
656    return wire-start;
657}
658
659Bool
660XkbSetDeviceInfo(	Display *		dpy,
661			unsigned 		which,
662			XkbDeviceInfoPtr	devi)
663{
664    register xkbSetDeviceInfoReq *req;
665    Status		     	ok = 0;
666    int				size,nLeds;
667    XkbInfoPtr 			xkbi;
668    XkbDeviceChangesRec		changes;
669    SetLedStuff			lstuff;
670
671    if ((dpy->flags & XlibDisplayNoXkb) ||
672	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
673	return False;
674    if ((!devi) || (which&(~XkbXI_AllDeviceFeaturesMask)) ||
675	((which&XkbXI_ButtonActionsMask)&&(!XkbXI_DevHasBtnActs(devi)))||
676	((which&XkbXI_IndicatorsMask)&&(!XkbXI_DevHasLeds(devi))))
677	return False;
678
679    bzero((char *)&changes,sizeof(XkbDeviceChangesRec));
680    changes.changed= which;
681    changes.first_btn=		0;
682    changes.num_btns=		devi->num_btns;
683    changes.leds.led_class=	XkbAllXIClasses;
684    changes.leds.led_id=	XkbAllXIIds;
685    changes.leds.defined=	0;
686    size= nLeds= 		0;
687    _InitLedStuff(&lstuff,changes.changed,devi);
688    if (_XkbSetDeviceInfoSize(devi,&changes,&lstuff,&size,&nLeds)!=Success)
689	return False;
690    LockDisplay(dpy);
691    xkbi = dpy->xkb_info;
692    GetReq(kbSetDeviceInfo, req);
693    req->length+=	size/4;
694    req->reqType= 	xkbi->codes->major_opcode;
695    req->xkbReqType= 	X_kbSetDeviceInfo;
696    req->deviceSpec= 	devi->device_spec;
697    req->firstBtn=	changes.first_btn;
698    req->nBtns=		changes.num_btns;
699    req->change=	changes.changed;
700    req->nDeviceLedFBs=	nLeds;
701    if (size>0) {
702	char * 	wire;
703	BufAlloc(char *,wire,size);
704	ok= (wire!=NULL)&&
705		(_XkbWriteSetDeviceInfo(wire,&changes,&lstuff,devi)==size);
706    }
707    UnlockDisplay(dpy);
708    SyncHandle();
709    _FreeLedStuff(&lstuff);
710    /* 12/11/95 (ef) -- XXX!! should clear changes here */
711    return ok;
712}
713
714Bool
715XkbChangeDeviceInfo(	Display *		dpy,
716			XkbDeviceInfoPtr	devi,
717			XkbDeviceChangesPtr	changes)
718{
719    register xkbSetDeviceInfoReq *req;
720    Status		     	ok = 0;
721    int				size,nLeds;
722    XkbInfoPtr 			xkbi;
723    SetLedStuff			lstuff;
724
725    if ((dpy->flags & XlibDisplayNoXkb) ||
726	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
727	return False;
728    if ((!devi) || (changes->changed&(~XkbXI_AllDeviceFeaturesMask)) ||
729	((changes->changed&XkbXI_ButtonActionsMask)&&
730					(!XkbXI_DevHasBtnActs(devi)))||
731	((changes->changed&XkbXI_IndicatorsMask)&&(!XkbXI_DevHasLeds(devi))))
732	return False;
733
734    size= nLeds= 0;
735    _InitLedStuff(&lstuff,changes->changed,devi);
736    if (_XkbSetDeviceInfoSize(devi,changes,&lstuff,&size,&nLeds)!=Success)
737	return False;
738    LockDisplay(dpy);
739    xkbi = dpy->xkb_info;
740    GetReq(kbSetDeviceInfo, req);
741    req->length+=	size/4;
742    req->reqType= 	xkbi->codes->major_opcode;
743    req->xkbReqType= 	X_kbSetDeviceInfo;
744    req->deviceSpec= 	devi->device_spec;
745    req->firstBtn=	changes->first_btn;
746    req->nBtns=		changes->num_btns;
747    req->change=	changes->changed;
748    req->nDeviceLedFBs=	nLeds;
749    if (size>0) {
750	char * 	wire;
751	BufAlloc(char *,wire,size);
752	ok= (wire!=NULL)&&
753		(_XkbWriteSetDeviceInfo(wire,changes,&lstuff,devi)==size);
754    }
755    UnlockDisplay(dpy);
756    SyncHandle();
757    _FreeLedStuff(&lstuff);
758    /* 12/11/95 (ef) -- XXX!! should clear changes here */
759    return ok;
760}
761
762Bool
763XkbSetDeviceLedInfo(	Display *		dpy,
764			XkbDeviceInfoPtr	devi,
765			unsigned 		ledClass,
766			unsigned		ledID,
767			unsigned		which)
768{
769    return False;
770}
771
772Bool
773XkbSetDeviceButtonActions(	Display *		dpy,
774				XkbDeviceInfoPtr 	devi,
775				unsigned int		first,
776				unsigned int		nBtns)
777{
778    register xkbSetDeviceInfoReq *req;
779    Status		     	ok = 0;
780    int				size,nLeds;
781    XkbInfoPtr 			xkbi;
782    XkbDeviceChangesRec		changes;
783    SetLedStuff			lstuff;
784
785    if ((dpy->flags & XlibDisplayNoXkb) ||
786	(!dpy->xkb_info && !XkbUseExtension(dpy,NULL,NULL)))
787	return False;
788    if ((!devi)||(!XkbXI_DevHasBtnActs(devi))||(first+nBtns>devi->num_btns))
789	return False;
790    if (nBtns==0)
791	return True;
792
793    bzero((char *)&changes,sizeof(XkbDeviceChangesRec));
794    changes.changed= 		XkbXI_ButtonActionsMask;
795    changes.first_btn=		first;
796    changes.num_btns=		nBtns;
797    changes.leds.led_class=	XkbXINone;
798    changes.leds.led_id=	XkbXINone;
799    changes.leds.defined=	0;
800    size= nLeds= 		0;
801    if (_XkbSetDeviceInfoSize(devi,&changes,NULL,&size,&nLeds)!=Success)
802	return False;
803    LockDisplay(dpy);
804    xkbi = dpy->xkb_info;
805    GetReq(kbSetDeviceInfo, req);
806    req->length+=	size/4;
807    req->reqType= 	xkbi->codes->major_opcode;
808    req->xkbReqType= 	X_kbSetDeviceInfo;
809    req->deviceSpec= 	devi->device_spec;
810    req->firstBtn=	changes.first_btn;
811    req->nBtns=		changes.num_btns;
812    req->change=	changes.changed;
813    req->nDeviceLedFBs=	nLeds;
814    if (size>0) {
815	char * 	wire;
816	BufAlloc(char *,wire,size);
817	ok= (wire!=NULL)&&
818		(_XkbWriteSetDeviceInfo(wire,&changes,&lstuff,devi)==size);
819    }
820    UnlockDisplay(dpy);
821    SyncHandle();
822    return ok;
823}
824