xkbLEDs.c revision 05b261ec
1/************************************************************
2Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32#include <ctype.h>
33#include <math.h>
34#define NEED_EVENTS 1
35#include <X11/X.h>
36#include <X11/Xproto.h>
37#include "misc.h"
38#include "inputstr.h"
39
40#include <X11/extensions/XI.h>
41#include <xkbsrv.h>
42#include "xkb.h"
43
44/***====================================================================***/
45
46	/*
47	 * unsigned
48	 * XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn)
49	 *
50	 * Given a keyboard and a set of state components that have changed,
51	 * this function returns the indicators on the default keyboard
52	 * feedback that might be affected.   It also reports whether or not
53	 * any extension devices might be affected in check_devs_rtrn.
54	 */
55
56unsigned
57XkbIndicatorsToUpdate(	DeviceIntPtr	dev,
58			unsigned long 	state_changes,
59			Bool		enable_changes)
60{
61register unsigned	update=	0;
62XkbSrvLedInfoPtr	sli;
63
64    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
65
66    if (!sli)
67        return update;
68
69    if (state_changes&(XkbModifierStateMask|XkbGroupStateMask))
70	update|= sli->usesEffective;
71    if (state_changes&(XkbModifierBaseMask|XkbGroupBaseMask))
72	update|= sli->usesBase;
73    if (state_changes&(XkbModifierLatchMask|XkbGroupLatchMask))
74	update|= sli->usesLatched;
75    if (state_changes&(XkbModifierLockMask|XkbGroupLockMask))
76	update|= sli->usesLocked;
77    if (state_changes&XkbCompatStateMask)
78	update|= sli->usesCompat;
79    if (enable_changes)
80	update|= sli->usesControls;
81    return update;
82}
83
84/***====================================================================***/
85
86	/*
87	 * Bool
88	 *XkbApplyLEDChangeToKeyboard(xkbi,map,on,change)
89	 *
90	 * Some indicators "drive" the keyboard when their state is explicitly
91	 * changed, as described in section 9.2.1 of the XKB protocol spec.
92	 * This function updates the state and controls for the keyboard
93	 * specified by 'xkbi' to reflect any changes that are required
94	 * when the indicator described by 'map' is turned on or off.  The
95	 * extent of the changes is reported in change, which must be defined.
96	 */
97static Bool
98XkbApplyLEDChangeToKeyboard(	XkbSrvInfoPtr		xkbi,
99				XkbIndicatorMapPtr	map,
100				Bool			on,
101				XkbChangesPtr		change)
102{
103Bool		ctrlChange,stateChange;
104XkbStatePtr	state;
105
106    if ((map->flags&XkbIM_NoExplicit)||((map->flags&XkbIM_LEDDrivesKB)==0))
107	return False;
108    ctrlChange= stateChange= False;
109    if (map->ctrls) {
110	XkbControlsPtr	ctrls= xkbi->desc->ctrls;
111	unsigned 	old;
112
113	old= ctrls->enabled_ctrls;
114	if (on)	ctrls->enabled_ctrls|= map->ctrls;
115	else	ctrls->enabled_ctrls&= ~map->ctrls;
116	if (old!=ctrls->enabled_ctrls) {
117	    change->ctrls.changed_ctrls= XkbControlsEnabledMask;
118	    change->ctrls.enabled_ctrls_changes= old^ctrls->enabled_ctrls;
119	    ctrlChange= True;
120	}
121    }
122    state= &xkbi->state;
123    if ((map->groups)&&((map->which_groups&(~XkbIM_UseBase))!=0)) {
124	register int i;
125	register unsigned bit,match;
126
127	if (on)	match= (map->groups)&XkbAllGroupsMask;
128	else 	match= (~map->groups)&XkbAllGroupsMask;
129	if (map->which_groups&(XkbIM_UseLocked|XkbIM_UseEffective)) {
130	    for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
131		if (bit&match)
132		    break;
133	    }
134	    if (map->which_groups&XkbIM_UseLatched)
135		XkbLatchGroup(xkbi->device,0); /* unlatch group */
136	    state->locked_group= i;
137	    stateChange= True;
138	}
139	else if (map->which_groups&(XkbIM_UseLatched|XkbIM_UseEffective)) {
140	    for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
141		if (bit&match)
142		    break;
143	    }
144	    state->locked_group= 0;
145	    XkbLatchGroup(xkbi->device,i);
146	    stateChange= True;
147	}
148    }
149    if ((map->mods.mask)&&((map->which_mods&(~XkbIM_UseBase))!=0)) {
150	if (map->which_mods&(XkbIM_UseLocked|XkbIM_UseEffective)) {
151	    register unsigned long old;
152	    old= state->locked_mods;
153	    if (on)	state->locked_mods|= map->mods.mask;
154	    else	state->locked_mods&= ~map->mods.mask;
155	    if (state->locked_mods!=old)
156		stateChange= True;
157	}
158	if (map->which_mods&(XkbIM_UseLatched|XkbIM_UseEffective)) {
159	    register unsigned long newmods;
160	    newmods= state->latched_mods;
161	    if (on)	newmods|=  map->mods.mask;
162	    else	newmods&= ~map->mods.mask;
163	    if (newmods!=state->locked_mods) {
164		newmods&= map->mods.mask;
165		XkbLatchModifiers(xkbi->device,map->mods.mask,newmods);
166		stateChange= True;
167	    }
168	}
169    }
170    return (stateChange || ctrlChange);
171}
172
173	/*
174	 * Bool
175	 * ComputeAutoState(map,state,ctrls)
176	 *
177	 * This function reports the effect of applying the specified
178	 * indicator map given the specified state and controls, as
179	 * described in section 9.2 of the XKB protocol specification.
180	 */
181
182static Bool
183ComputeAutoState(	XkbIndicatorMapPtr	map,
184			XkbStatePtr 		state,
185			XkbControlsPtr 		ctrls)
186{
187Bool 			on;
188CARD8 			mods,group;
189
190    on= False;
191    mods= group= 0;
192    if (map->which_mods&XkbIM_UseAnyMods) {
193	if (map->which_mods&XkbIM_UseBase)
194	    mods|= state->base_mods;
195	if (map->which_mods&XkbIM_UseLatched)
196	    mods|= state->latched_mods;
197	if (map->which_mods&XkbIM_UseLocked)
198	    mods|= state->locked_mods;
199	if (map->which_mods&XkbIM_UseEffective)
200	    mods|= state->mods;
201	if (map->which_mods&XkbIM_UseCompat)
202	    mods|= state->compat_state;
203	on = ((map->mods.mask&mods)!=0);
204	on = on||((mods==0)&&(map->mods.mask==0)&&(map->mods.vmods==0));
205    }
206    if (map->which_groups&XkbIM_UseAnyGroup) {
207	if (map->which_groups&XkbIM_UseBase)
208	    group|= (1L << state->base_group);
209	if (map->which_groups&XkbIM_UseLatched)
210	    group|= (1L << state->latched_group);
211	if (map->which_groups&XkbIM_UseLocked)
212	    group|= (1L << state->locked_group);
213	if (map->which_groups&XkbIM_UseEffective)
214	    group|= (1L << state->group);
215	on = on||(((map->groups&group)!=0)||(map->groups==0));
216    }
217    if (map->ctrls)
218	on = on||(ctrls->enabled_ctrls&map->ctrls);
219    return on;
220}
221
222
223static void
224XkbUpdateLedAutoState(	DeviceIntPtr			dev,
225			XkbSrvLedInfoPtr		sli,
226			unsigned			maps_to_check,
227			xkbExtensionDeviceNotify *	ed,
228			XkbChangesPtr			changes,
229			XkbEventCausePtr		cause)
230{
231DeviceIntPtr			kbd;
232XkbStatePtr			state;
233XkbControlsPtr			ctrls;
234XkbChangesRec			my_changes;
235xkbExtensionDeviceNotify	my_ed;
236register unsigned		i,bit,affected;
237register XkbIndicatorMapPtr	map;
238unsigned			oldState;
239
240    if ((maps_to_check==0)||(sli->maps==NULL)||(sli->mapsPresent==0))
241	return;
242
243    if (dev->key && dev->key->xkbInfo)
244	 kbd= dev;
245    else kbd= (DeviceIntPtr)LookupKeyboardDevice();
246
247    state= &kbd->key->xkbInfo->state;
248    ctrls= kbd->key->xkbInfo->desc->ctrls;
249    affected= maps_to_check;
250    oldState= sli->effectiveState;
251    sli->autoState&= ~affected;
252    for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) {
253	if ((affected&bit)==0)
254	    continue;
255	affected&= ~bit;
256	map= &sli->maps[i];
257	if((!(map->flags&XkbIM_NoAutomatic))&&ComputeAutoState(map,state,ctrls))
258	    sli->autoState|= bit;
259    }
260    sli->effectiveState= (sli->autoState|sli->explicitState);
261    affected= sli->effectiveState^oldState;
262    if (affected==0)
263	return;
264
265    if (ed==NULL) {
266	ed= &my_ed;
267	bzero((char *)ed,sizeof(xkbExtensionDeviceNotify));
268    }
269    else if ((ed->reason&XkbXI_IndicatorsMask)&&
270	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
271	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
272    }
273
274    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) {
275	if (changes==NULL) {
276	    changes= &my_changes;
277	    bzero((char *)changes,sizeof(XkbChangesRec));
278	}
279	changes->indicators.state_changes|= affected;
280    }
281
282    ed->reason|=	XkbXI_IndicatorStateMask;
283    ed->ledClass= 	sli->class;
284    ed->ledID=		sli->id;
285    ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
286    ed->ledState=	sli->effectiveState;
287    ed->unsupported|=	XkbXI_IndicatorStateMask;
288    ed->supported=	XkbXI_AllFeaturesMask;
289
290    if (changes!=&my_changes)	changes= NULL;
291    if (ed!=&my_ed)		ed= NULL;
292    if (changes || ed)
293	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
294    return;
295}
296
297static void
298XkbUpdateAllDeviceIndicators(XkbChangesPtr changes,XkbEventCausePtr cause)
299{
300DeviceIntPtr		edev;
301XkbSrvLedInfoPtr	sli;
302
303    for (edev=inputInfo.devices;edev!=NULL;edev=edev->next) {
304	if (edev->kbdfeed) {
305	    KbdFeedbackPtr	kf;
306	    for (kf=edev->kbdfeed;kf!=NULL;kf=kf->next) {
307		if ((kf->xkb_sli==NULL)||(kf->xkb_sli->maps==NULL))
308		    continue;
309		sli= kf->xkb_sli;
310		XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL,
311								changes,cause);
312
313	    }
314	}
315	if (edev->leds) {
316	    LedFeedbackPtr	lf;
317	    for (lf=edev->leds;lf!=NULL;lf=lf->next) {
318		if ((lf->xkb_sli==NULL)||(lf->xkb_sli->maps==NULL))
319		    continue;
320		sli= lf->xkb_sli;
321		XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL,
322								changes,cause);
323
324	    }
325	}
326    }
327    return;
328}
329
330
331/***====================================================================***/
332
333	/*
334	 * void
335	 * XkbSetIndicators(dev,affect,values,cause)
336	 *
337	 * Attempts to change the indicators specified in 'affect' to the
338	 * states specified in 'values' for the default keyboard feedback
339	 * on the keyboard specified by 'dev.'   Attempts to change indicator
340	 * state might be ignored or have no affect, depending on the XKB
341	 * indicator map for any affected indicators, as described in section
342	 * 9.2 of the XKB protocol specification.
343	 *
344	 * If 'changes' is non-NULL, this function notes any changes to the
345	 * keyboard state, controls, or indicator state that result from this
346	 * attempted change.   If 'changes' is NULL, this function generates
347	 * XKB events to report any such changes to interested clients.
348	 *
349	 * If 'cause' is non-NULL, it specifies the reason for the change,
350	 * as reported in some XKB events.   If it is NULL, this function
351	 * assumes that the change is the result of a core protocol
352	 * ChangeKeyboardMapping request.
353	 */
354
355void
356XkbSetIndicators(	DeviceIntPtr		dev,
357			CARD32			affect,
358			CARD32			values,
359			XkbEventCausePtr	cause)
360{
361XkbSrvLedInfoPtr		sli;
362XkbChangesRec			changes;
363xkbExtensionDeviceNotify	ed;
364unsigned 			side_affected;
365
366    bzero((char *)&changes,sizeof(XkbChangesRec));
367    bzero((char *)&ed,sizeof(xkbExtensionDeviceNotify));
368    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
369    sli->explicitState&= ~affect;
370    sli->explicitState|= (affect&values);
371    XkbApplyLedStateChanges(dev,sli,affect,&ed,&changes,cause);
372
373    side_affected= 0;
374    if (changes.state_changes!=0)
375	side_affected|= XkbIndicatorsToUpdate(dev,changes.state_changes,False);
376    if (changes.ctrls.enabled_ctrls_changes)
377	side_affected|= sli->usesControls;
378
379    if (side_affected) {
380	XkbUpdateLedAutoState(dev,sli,side_affected,&ed,&changes,cause);
381	affect|= side_affected;
382    }
383    if (changes.state_changes || changes.ctrls.enabled_ctrls_changes)
384	XkbUpdateAllDeviceIndicators(NULL,cause);
385
386    XkbFlushLedEvents(dev,dev,sli,&ed,&changes,cause);
387    return;
388}
389
390/***====================================================================***/
391
392/***====================================================================***/
393
394	/*
395	 * void
396	 * XkbUpdateIndicators(dev,update,check_edevs,changes,cause)
397	 *
398	 * Applies the indicator maps for any indicators specified in
399	 * 'update' from the default keyboard feedback on the device
400	 * specified by 'dev.'
401	 *
402	 * If 'changes' is NULL, this function generates and XKB events
403	 * required to report the necessary changes, otherwise it simply
404	 * notes the indicators with changed state.
405	 *
406	 * If 'check_edevs' is True, this function also checks the indicator
407	 * maps for any open extension devices that have them, and updates
408	 * the state of any extension device indicators as necessary.
409	 */
410
411void
412XkbUpdateIndicators(	DeviceIntPtr		dev,
413			register CARD32		update,
414			Bool			check_edevs,
415			XkbChangesPtr		changes,
416			XkbEventCausePtr	cause)
417{
418XkbSrvLedInfoPtr	sli;
419
420    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
421    XkbUpdateLedAutoState(dev,sli,update,NULL,changes,cause);
422    if (check_edevs)
423	XkbUpdateAllDeviceIndicators(changes,cause);
424    return;
425}
426
427/***====================================================================***/
428
429/***====================================================================***/
430
431	/*
432	 * void
433	 * XkbCheckIndicatorMaps(dev,sli,which)
434	 *
435	 * Updates the 'indicator accelerators' for the indicators specified
436	 * by 'which' in the feedback specified by 'sli.' The indicator
437	 * accelerators are internal to the server and are used to simplify
438	 * and speed up the process of figuring out which indicators might
439	 * be affected by a particular change in keyboard state or controls.
440	 */
441
442void
443XkbCheckIndicatorMaps(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned which)
444{
445register unsigned	i,bit;
446XkbIndicatorMapPtr	map;
447XkbDescPtr		xkb;
448
449    if ((sli->flags&XkbSLI_HasOwnState)==0)
450	dev= (DeviceIntPtr)LookupKeyboardDevice();
451
452    sli->usesBase&=	 ~which;
453    sli->usesLatched&=	 ~which;
454    sli->usesLocked&=	 ~which;
455    sli->usesEffective&= ~which;
456    sli->usesCompat&=	 ~which;
457    sli->usesControls&=	 ~which;
458    sli->mapsPresent&=	 ~which;
459
460    xkb= dev->key->xkbInfo->desc;
461    for (i=0,bit=1,map=sli->maps;i<XkbNumIndicators;i++,bit<<=1,map++) {
462	if (which&bit) {
463	    CARD8		what;
464
465	    if (!XkbIM_InUse(map))
466		continue;
467	    sli->mapsPresent|= bit;
468
469	    what= (map->which_mods|map->which_groups);
470	    if (what&XkbIM_UseBase)
471		 sli->usesBase|= bit;
472	    if (what&XkbIM_UseLatched)
473		 sli->usesLatched|= bit;
474	    if (what&XkbIM_UseLocked)
475		 sli->usesLocked|= bit;
476	    if (what&XkbIM_UseEffective)
477		 sli->usesEffective|= bit;
478	    if (what&XkbIM_UseCompat)
479		 sli->usesCompat|= bit;
480	    if (map->ctrls)
481		 sli->usesControls|= bit;
482
483	    map->mods.mask= map->mods.real_mods;
484	    if (map->mods.vmods!=0) {
485		map->mods.mask|= XkbMaskForVMask(xkb,map->mods.vmods);
486	    }
487	}
488    }
489    sli->usedComponents= 0;
490    if (sli->usesBase)
491	sli->usedComponents|= XkbModifierBaseMask|XkbGroupBaseMask;
492    if (sli->usesLatched)
493	sli->usedComponents|= XkbModifierLatchMask|XkbGroupLatchMask;
494    if (sli->usesLocked)
495	sli->usedComponents|= XkbModifierLockMask|XkbGroupLockMask;
496    if (sli->usesEffective)
497	sli->usedComponents|= XkbModifierStateMask|XkbGroupStateMask;
498    if (sli->usesCompat)
499	sli->usedComponents|= XkbCompatStateMask;
500    return;
501}
502
503/***====================================================================***/
504
505	/*
506	 * XkbSrvLedInfoPtr
507	 * XkbAllocSrvLedInfo(dev,kf,lf,needed_parts)
508	 *
509	 * Allocates an XkbSrvLedInfoPtr for the feedback specified by either
510	 * 'kf' or 'lf' on the keyboard specified by 'dev.'
511	 *
512	 * If 'needed_parts' is non-zero, this function makes sure that any
513	 * of the parts speicified therein are allocated.
514	 */
515XkbSrvLedInfoPtr
516XkbAllocSrvLedInfo(	DeviceIntPtr		dev,
517			KbdFeedbackPtr		kf,
518			LedFeedbackPtr		lf,
519			unsigned		needed_parts)
520{
521XkbSrvLedInfoPtr	sli;
522Bool			checkAccel;
523Bool			checkNames;
524
525    sli= NULL;
526    checkAccel= checkNames= False;
527    if ((kf!=NULL)&&(kf->xkb_sli==NULL)) {
528	kf->xkb_sli= sli= _XkbTypedCalloc(1,XkbSrvLedInfoRec);
529	if (sli==NULL)
530	    return NULL; /* ALLOCATION ERROR */
531	if (dev->key && dev->key->xkbInfo)
532	     sli->flags= XkbSLI_HasOwnState;
533	else sli->flags= 0;
534	sli->class=	KbdFeedbackClass;
535	sli->id=	kf->ctrl.id;
536	sli->fb.kf=	kf;
537
538	sli->autoState=		0;
539	sli->explicitState=	kf->ctrl.leds;
540	sli->effectiveState=	kf->ctrl.leds;
541
542	if ((kf==dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) {
543	    XkbDescPtr	xkb;
544	    xkb= dev->key->xkbInfo->desc;
545	    sli->flags|= 		XkbSLI_IsDefault;
546	    sli->physIndicators=	xkb->indicators->phys_indicators;
547	    sli->names=			xkb->names->indicators;
548	    sli->maps=			xkb->indicators->maps;
549	    checkNames= checkAccel=	True;
550	}
551	else {
552	    sli->physIndicators=	XkbAllIndicatorsMask;
553	    sli->names=			NULL;
554	    sli->maps=			NULL;
555	}
556    }
557    else if ((kf!=NULL)&&((kf->xkb_sli->flags&XkbSLI_IsDefault)!=0)) {
558	XkbDescPtr	xkb;
559	xkb= dev->key->xkbInfo->desc;
560	sli->physIndicators=	xkb->indicators->phys_indicators;
561	if (xkb->names->indicators!=sli->names) {
562	    checkNames= True;
563	    sli->names= xkb->names->indicators;
564	}
565	if (xkb->indicators->maps!=sli->maps) {
566	    checkAccel= True;
567	    sli->maps= xkb->indicators->maps;
568	}
569    }
570    else if ((lf!=NULL)&&(lf->xkb_sli==NULL)) {
571	lf->xkb_sli= sli= _XkbTypedCalloc(1,XkbSrvLedInfoRec);
572	if (sli==NULL)
573	    return NULL; /* ALLOCATION ERROR */
574	if (dev->key && dev->key->xkbInfo)
575	     sli->flags= XkbSLI_HasOwnState;
576	else sli->flags= 0;
577	sli->class=	LedFeedbackClass;
578	sli->id=	lf->ctrl.id;
579	sli->fb.lf=	lf;
580
581	sli->physIndicators=	lf->ctrl.led_mask;
582	sli->autoState=		0;
583	sli->explicitState=	lf->ctrl.led_values;
584	sli->effectiveState=	lf->ctrl.led_values;
585	sli->maps=		NULL;
586	sli->names=		NULL;
587    }
588    if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask))
589	sli->names= _XkbTypedCalloc(XkbNumIndicators,Atom);
590    if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask))
591	sli->maps= _XkbTypedCalloc(XkbNumIndicators,XkbIndicatorMapRec);
592    if (checkNames) {
593	register unsigned i,bit;
594	sli->namesPresent=	0;
595	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
596	    if (sli->names[i]!=None)
597		sli->namesPresent|= bit;
598	}
599    }
600    if (checkAccel)
601	 XkbCheckIndicatorMaps(dev,sli,XkbAllIndicatorsMask);
602    return sli;
603}
604
605void
606XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli)
607{
608    if ((sli->flags&XkbSLI_IsDefault)==0) {
609	if (sli->maps)	_XkbFree(sli->maps);
610	if (sli->names)	_XkbFree(sli->names);
611    }
612    sli->maps= NULL;
613    sli->names= NULL;
614    _XkbFree(sli);
615    return;
616}
617
618
619/***====================================================================***/
620
621	/*
622	 * XkbSrvLedInfoPtr
623	 * XkbFindSrvLedInfo(dev,class,id,needed_parts)
624	 *
625	 * Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id'
626	 * on the device specified by 'dev.'   If the class and id specify
627	 * a valid device feedback, this function returns the existing
628	 * feedback or allocates a new one.
629	 *
630	 */
631
632XkbSrvLedInfoPtr
633XkbFindSrvLedInfo(	DeviceIntPtr		dev,
634			unsigned		class,
635			unsigned		id,
636			unsigned		needed_parts)
637{
638XkbSrvLedInfoPtr	sli;
639
640    /* optimization to check for most common case */
641    if (((class==XkbDfltXIClass)&&(id==XkbDfltXIId))&&(dev->kbdfeed)) {
642	XkbSrvLedInfoPtr	sli;
643	sli= dev->kbdfeed->xkb_sli;
644	if (dev->kbdfeed->xkb_sli==NULL) {
645	    sli= XkbAllocSrvLedInfo(dev,dev->kbdfeed,NULL,needed_parts);
646	    dev->kbdfeed->xkb_sli= sli;
647	}
648	return dev->kbdfeed->xkb_sli;
649    }
650
651    sli= NULL;
652    if (class==XkbDfltXIClass) {
653	if (dev->kbdfeed)	class= KbdFeedbackClass;
654	else if (dev->leds)	class= LedFeedbackClass;
655	else 			return NULL;
656    }
657    if (class==KbdFeedbackClass) {
658	KbdFeedbackPtr	kf;
659	for (kf=dev->kbdfeed;kf!=NULL;kf=kf->next) {
660	    if ((id==XkbDfltXIId)||(id==kf->ctrl.id)) {
661		if (kf->xkb_sli==NULL)
662		    kf->xkb_sli= XkbAllocSrvLedInfo(dev,kf,NULL,needed_parts);
663		sli= kf->xkb_sli;
664		break;
665	    }
666	}
667    }
668    else if (class==LedFeedbackClass) {
669	LedFeedbackPtr	lf;
670	for (lf=dev->leds;lf!=NULL;lf=lf->next) {
671	    if ((id==XkbDfltXIId)||(id==lf->ctrl.id)) {
672		if (lf->xkb_sli==NULL)
673		    lf->xkb_sli= XkbAllocSrvLedInfo(dev,NULL,lf,needed_parts);
674		sli= lf->xkb_sli;
675		break;
676	    }
677	}
678    }
679    if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask))
680	sli->names= _XkbTypedCalloc(XkbNumIndicators,Atom);
681    if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask))
682	sli->maps= _XkbTypedCalloc(XkbNumIndicators,XkbIndicatorMapRec);
683    return sli;
684}
685
686/***====================================================================***/
687
688void
689XkbFlushLedEvents(	DeviceIntPtr			dev,
690			DeviceIntPtr			kbd,
691			XkbSrvLedInfoPtr		sli,
692			xkbExtensionDeviceNotify *	ed,
693			XkbChangesPtr			changes,
694			XkbEventCausePtr		cause)
695{
696    if (changes) {
697	if (changes->indicators.state_changes)
698	    XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState);
699	XkbSendNotification(kbd,changes,cause);
700	bzero((char *)changes,sizeof(XkbChangesRec));
701
702	if (XkbAX_NeedFeedback(kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) {
703		if (sli->effectiveState)
704			/* it appears that the which parameter is not used */
705			XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask);
706		else
707			XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask);
708	}
709    }
710    if (ed && (ed->reason)) {
711	if ((dev!=kbd)&&(ed->reason&XkbXI_IndicatorStateMask))
712	    XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState);
713	XkbSendExtensionDeviceNotify(dev,cause->client,ed);
714    }
715    bzero((char *)ed,sizeof(XkbExtensionDeviceNotify));
716    return;
717}
718
719/***====================================================================***/
720
721void
722XkbApplyLedNameChanges(	DeviceIntPtr 			dev,
723			XkbSrvLedInfoPtr		sli,
724			unsigned			changed_names,
725			xkbExtensionDeviceNotify *	ed,
726			XkbChangesPtr			changes,
727			XkbEventCausePtr		cause)
728{
729DeviceIntPtr			kbd;
730XkbChangesRec			my_changes;
731xkbExtensionDeviceNotify	my_ed;
732
733    if (changed_names==0)
734	return;
735    if (dev->key && dev->key->xkbInfo)
736	 kbd= dev;
737    else kbd= (DeviceIntPtr)LookupKeyboardDevice();
738
739    if (ed==NULL) {
740	ed= &my_ed;
741	bzero((char *)ed,sizeof(xkbExtensionDeviceNotify));
742    }
743    else if ((ed->reason&XkbXI_IndicatorsMask)&&
744	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
745	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
746    }
747
748    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) {
749	if (changes==NULL) {
750	   changes= &my_changes;
751	   bzero((char *)changes,sizeof(XkbChangesRec));
752	}
753	changes->names.changed|= XkbIndicatorNamesMask;
754	changes->names.changed_indicators|= changed_names;
755    }
756
757    ed->reason|=	XkbXI_IndicatorNamesMask;
758    ed->ledClass= 	sli->class;
759    ed->ledID=		sli->id;
760    ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
761    ed->ledState=	sli->effectiveState;
762    ed->unsupported=	0;
763    ed->supported=	XkbXI_AllFeaturesMask;
764
765    if (changes!=&my_changes)	changes= NULL;
766    if (ed!=&my_ed)		ed= NULL;
767    if (changes || ed)
768	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
769    return;
770}
771/***====================================================================***/
772
773	/*
774	 * void
775	 * XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause)
776	 *
777	 * Handles all of the secondary effects of the changes to the
778	 * feedback specified by 'sli' on the device specified by 'dev.'
779	 *
780	 * If 'changed_maps' specifies any indicators, this function generates
781	 * XkbExtensionDeviceNotify events and possibly IndicatorMapNotify
782	 * events to report the changes, and recalculates the effective
783	 * state of each indicator with a changed map.  If any indicators
784	 * change state, the server generates XkbExtensionDeviceNotify and
785	 * XkbIndicatorStateNotify events as appropriate.
786	 *
787	 * If 'changes' is non-NULL, this function updates it to reflect
788	 * any changes to the keyboard state or controls or to the 'core'
789	 * indicator names, maps, or state.   If 'changes' is NULL, this
790	 * function generates XKB events as needed to report the changes.
791	 * If 'dev' is not a keyboard device, any changes are reported
792	 * for the core keyboard.
793	 *
794	 * The 'cause' specifies the reason for the event (key event or
795	 * request) for the change, as reported in some XKB events.
796	 */
797
798void
799XkbApplyLedMapChanges(	DeviceIntPtr 			dev,
800			XkbSrvLedInfoPtr		sli,
801			unsigned			changed_maps,
802			xkbExtensionDeviceNotify *	ed,
803			XkbChangesPtr			changes,
804			XkbEventCausePtr		cause)
805{
806DeviceIntPtr			kbd;
807XkbChangesRec			my_changes;
808xkbExtensionDeviceNotify	my_ed;
809
810    if (changed_maps==0)
811	return;
812    if (dev->key && dev->key->xkbInfo)
813	 kbd= dev;
814    else kbd= (DeviceIntPtr)LookupKeyboardDevice();
815
816    if (ed==NULL) {
817	ed= &my_ed;
818	bzero((char *)ed,sizeof(xkbExtensionDeviceNotify));
819    }
820    else if ((ed->reason&XkbXI_IndicatorsMask)&&
821	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
822	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
823    }
824
825    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) {
826	if (changes==NULL) {
827	    changes= &my_changes;
828	    bzero((char *)changes,sizeof(XkbChangesRec));
829	}
830	changes->indicators.map_changes|= changed_maps;
831    }
832
833    XkbCheckIndicatorMaps(dev,sli,changed_maps);
834
835    ed->reason|=	XkbXI_IndicatorMapsMask;
836    ed->ledClass= 	sli->class;
837    ed->ledID=		sli->id;
838    ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
839    ed->ledState=	sli->effectiveState;
840    ed->unsupported|=	XkbXI_IndicatorMapsMask;
841    ed->supported=	XkbXI_AllFeaturesMask;
842
843    XkbUpdateLedAutoState(dev,sli,changed_maps,ed,changes,cause);
844
845    if (changes!=&my_changes)	changes= NULL;
846    if (ed!=&my_ed)		ed= NULL;
847    if (changes || ed)
848	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
849    return;
850}
851
852/***====================================================================***/
853
854void
855XkbApplyLedStateChanges(DeviceIntPtr 			dev,
856			XkbSrvLedInfoPtr		sli,
857			unsigned			changed_leds,
858			xkbExtensionDeviceNotify *	ed,
859			XkbChangesPtr			changes,
860			XkbEventCausePtr		cause)
861{
862XkbSrvInfoPtr			xkbi;
863DeviceIntPtr			kbd;
864XkbChangesRec			my_changes;
865xkbExtensionDeviceNotify	my_ed;
866register unsigned		i,bit,affected;
867XkbIndicatorMapPtr		map;
868unsigned			oldState;
869Bool				kb_changed;
870
871    if (changed_leds==0)
872	return;
873    if (dev->key && dev->key->xkbInfo)
874	 kbd= dev;
875    else kbd= (DeviceIntPtr)LookupKeyboardDevice();
876    xkbi= kbd->key->xkbInfo;
877
878    if (changes==NULL) {
879	changes= &my_changes;
880	bzero((char *)changes,sizeof(XkbChangesRec));
881    }
882
883    kb_changed= False;
884    affected= changed_leds;
885    oldState= sli->effectiveState;
886    for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) {
887	if ((affected&bit)==0)
888	    continue;
889	affected&= ~bit;
890	map= &sli->maps[i];
891	if (map->flags&XkbIM_NoExplicit) {
892	    sli->explicitState&= ~bit;
893	    continue;
894	}
895	if (map->flags&XkbIM_LEDDrivesKB) {
896	    Bool on= ((sli->explicitState&bit)!=0);
897	    if (XkbApplyLEDChangeToKeyboard(xkbi,map,on,changes))
898		kb_changed= True;
899	}
900    }
901    sli->effectiveState= (sli->autoState|sli->explicitState);
902    affected= sli->effectiveState^oldState;
903
904    if (ed==NULL) {
905	ed= &my_ed;
906	bzero((char *)ed,sizeof(xkbExtensionDeviceNotify));
907    }
908    else if (affected&&(ed->reason&XkbXI_IndicatorsMask)&&
909	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
910	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
911    }
912
913    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault))
914	changes->indicators.state_changes|= affected;
915    if (affected) {
916	ed->reason|=		XkbXI_IndicatorStateMask;
917	ed->ledClass= 		sli->class;
918	ed->ledID=		sli->id;
919	ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
920	ed->ledState=		sli->effectiveState;
921	ed->unsupported|=	XkbXI_IndicatorStateMask;
922	ed->supported=		XkbXI_AllFeaturesMask;
923    }
924
925    if (kb_changed) {
926	XkbComputeDerivedState(kbd->key->xkbInfo);
927	XkbUpdateLedAutoState(dev,sli,sli->mapsPresent,ed,changes,cause);
928    }
929
930    if (changes!=&my_changes)	changes= NULL;
931    if (ed!=&my_ed)		ed= NULL;
932    if (changes || ed)
933	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
934    if (kb_changed)
935	XkbUpdateAllDeviceIndicators(NULL,cause);
936    return;
937}
938