1706f2543Smrg/************************************************************
2706f2543SmrgCopyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3706f2543Smrg
4706f2543SmrgPermission to use, copy, modify, and distribute this
5706f2543Smrgsoftware and its documentation for any purpose and without
6706f2543Smrgfee is hereby granted, provided that the above copyright
7706f2543Smrgnotice appear in all copies and that both that copyright
8706f2543Smrgnotice and this permission notice appear in supporting
9706f2543Smrgdocumentation, and that the name of Silicon Graphics not be
10706f2543Smrgused in advertising or publicity pertaining to distribution
11706f2543Smrgof the software without specific prior written permission.
12706f2543SmrgSilicon Graphics makes no representation about the suitability
13706f2543Smrgof this software for any purpose. It is provided "as is"
14706f2543Smrgwithout any express or implied warranty.
15706f2543Smrg
16706f2543SmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18706f2543SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19706f2543SmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20706f2543SmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21706f2543SmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22706f2543SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23706f2543SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
24706f2543Smrg
25706f2543Smrg********************************************************/
26706f2543Smrg
27706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
28706f2543Smrg#include <dix-config.h>
29706f2543Smrg#endif
30706f2543Smrg
31706f2543Smrg#include <stdio.h>
32706f2543Smrg#include <ctype.h>
33706f2543Smrg#include <math.h>
34706f2543Smrg#include <X11/X.h>
35706f2543Smrg#include <X11/Xproto.h>
36706f2543Smrg#include "misc.h"
37706f2543Smrg#include "inputstr.h"
38706f2543Smrg
39706f2543Smrg#include <X11/extensions/XI.h>
40706f2543Smrg#include <xkbsrv.h>
41706f2543Smrg#include "xkb.h"
42706f2543Smrg
43706f2543Smrg/***====================================================================***/
44706f2543Smrg
45706f2543Smrg	/*
46706f2543Smrg	 * unsigned
47706f2543Smrg	 * XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn)
48706f2543Smrg	 *
49706f2543Smrg	 * Given a keyboard and a set of state components that have changed,
50706f2543Smrg	 * this function returns the indicators on the default keyboard
51706f2543Smrg	 * feedback that might be affected.   It also reports whether or not
52706f2543Smrg	 * any extension devices might be affected in check_devs_rtrn.
53706f2543Smrg	 */
54706f2543Smrg
55706f2543Smrgunsigned
56706f2543SmrgXkbIndicatorsToUpdate(	DeviceIntPtr	dev,
57706f2543Smrg			unsigned long 	state_changes,
58706f2543Smrg			Bool		enable_changes)
59706f2543Smrg{
60706f2543Smrgregister unsigned	update=	0;
61706f2543SmrgXkbSrvLedInfoPtr	sli;
62706f2543Smrg
63706f2543Smrg    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
64706f2543Smrg
65706f2543Smrg    if (!sli)
66706f2543Smrg        return update;
67706f2543Smrg
68706f2543Smrg    if (state_changes&(XkbModifierStateMask|XkbGroupStateMask))
69706f2543Smrg	update|= sli->usesEffective;
70706f2543Smrg    if (state_changes&(XkbModifierBaseMask|XkbGroupBaseMask))
71706f2543Smrg	update|= sli->usesBase;
72706f2543Smrg    if (state_changes&(XkbModifierLatchMask|XkbGroupLatchMask))
73706f2543Smrg	update|= sli->usesLatched;
74706f2543Smrg    if (state_changes&(XkbModifierLockMask|XkbGroupLockMask))
75706f2543Smrg	update|= sli->usesLocked;
76706f2543Smrg    if (state_changes&XkbCompatStateMask)
77706f2543Smrg	update|= sli->usesCompat;
78706f2543Smrg    if (enable_changes)
79706f2543Smrg	update|= sli->usesControls;
80706f2543Smrg    return update;
81706f2543Smrg}
82706f2543Smrg
83706f2543Smrg/***====================================================================***/
84706f2543Smrg
85706f2543Smrg	/*
86706f2543Smrg	 * Bool
87706f2543Smrg	 *XkbApplyLEDChangeToKeyboard(xkbi,map,on,change)
88706f2543Smrg	 *
89706f2543Smrg	 * Some indicators "drive" the keyboard when their state is explicitly
90706f2543Smrg	 * changed, as described in section 9.2.1 of the XKB protocol spec.
91706f2543Smrg	 * This function updates the state and controls for the keyboard
92706f2543Smrg	 * specified by 'xkbi' to reflect any changes that are required
93706f2543Smrg	 * when the indicator described by 'map' is turned on or off.  The
94706f2543Smrg	 * extent of the changes is reported in change, which must be defined.
95706f2543Smrg	 */
96706f2543Smrgstatic Bool
97706f2543SmrgXkbApplyLEDChangeToKeyboard(	XkbSrvInfoPtr		xkbi,
98706f2543Smrg				XkbIndicatorMapPtr	map,
99706f2543Smrg				Bool			on,
100706f2543Smrg				XkbChangesPtr		change)
101706f2543Smrg{
102706f2543SmrgBool		ctrlChange,stateChange;
103706f2543SmrgXkbStatePtr	state;
104706f2543Smrg
105706f2543Smrg    if ((map->flags&XkbIM_NoExplicit)||((map->flags&XkbIM_LEDDrivesKB)==0))
106706f2543Smrg	return FALSE;
107706f2543Smrg    ctrlChange= stateChange= FALSE;
108706f2543Smrg    if (map->ctrls) {
109706f2543Smrg	XkbControlsPtr	ctrls= xkbi->desc->ctrls;
110706f2543Smrg	unsigned 	old;
111706f2543Smrg
112706f2543Smrg	old= ctrls->enabled_ctrls;
113706f2543Smrg	if (on)	ctrls->enabled_ctrls|= map->ctrls;
114706f2543Smrg	else	ctrls->enabled_ctrls&= ~map->ctrls;
115706f2543Smrg	if (old!=ctrls->enabled_ctrls) {
116706f2543Smrg	    change->ctrls.changed_ctrls= XkbControlsEnabledMask;
117706f2543Smrg	    change->ctrls.enabled_ctrls_changes= old^ctrls->enabled_ctrls;
118706f2543Smrg	    ctrlChange= TRUE;
119706f2543Smrg	}
120706f2543Smrg    }
121706f2543Smrg    state= &xkbi->state;
122706f2543Smrg    if ((map->groups)&&((map->which_groups&(~XkbIM_UseBase))!=0)) {
123706f2543Smrg	register int i;
124706f2543Smrg	register unsigned bit,match;
125706f2543Smrg
126706f2543Smrg	if (on)	match= (map->groups)&XkbAllGroupsMask;
127706f2543Smrg	else 	match= (~map->groups)&XkbAllGroupsMask;
128706f2543Smrg	if (map->which_groups&(XkbIM_UseLocked|XkbIM_UseEffective)) {
129706f2543Smrg	    for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
130706f2543Smrg		if (bit&match)
131706f2543Smrg		    break;
132706f2543Smrg	    }
133706f2543Smrg	    if (map->which_groups&XkbIM_UseLatched)
134706f2543Smrg		XkbLatchGroup(xkbi->device,0); /* unlatch group */
135706f2543Smrg	    state->locked_group= i;
136706f2543Smrg	    stateChange= TRUE;
137706f2543Smrg	}
138706f2543Smrg	else if (map->which_groups&(XkbIM_UseLatched|XkbIM_UseEffective)) {
139706f2543Smrg	    for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
140706f2543Smrg		if (bit&match)
141706f2543Smrg		    break;
142706f2543Smrg	    }
143706f2543Smrg	    state->locked_group= 0;
144706f2543Smrg	    XkbLatchGroup(xkbi->device,i);
145706f2543Smrg	    stateChange= TRUE;
146706f2543Smrg	}
147706f2543Smrg    }
148706f2543Smrg    if ((map->mods.mask)&&((map->which_mods&(~XkbIM_UseBase))!=0)) {
149706f2543Smrg	if (map->which_mods&(XkbIM_UseLocked|XkbIM_UseEffective)) {
150706f2543Smrg	    register unsigned long old;
151706f2543Smrg	    old= state->locked_mods;
152706f2543Smrg	    if (on)	state->locked_mods|= map->mods.mask;
153706f2543Smrg	    else	state->locked_mods&= ~map->mods.mask;
154706f2543Smrg	    if (state->locked_mods!=old)
155706f2543Smrg		stateChange= TRUE;
156706f2543Smrg	}
157706f2543Smrg	if (map->which_mods&(XkbIM_UseLatched|XkbIM_UseEffective)) {
158706f2543Smrg	    register unsigned long newmods;
159706f2543Smrg	    newmods= state->latched_mods;
160706f2543Smrg	    if (on)	newmods|=  map->mods.mask;
161706f2543Smrg	    else	newmods&= ~map->mods.mask;
162706f2543Smrg	    if (newmods!=state->locked_mods) {
163706f2543Smrg		newmods&= map->mods.mask;
164706f2543Smrg		XkbLatchModifiers(xkbi->device,map->mods.mask,newmods);
165706f2543Smrg		stateChange= TRUE;
166706f2543Smrg	    }
167706f2543Smrg	}
168706f2543Smrg    }
169706f2543Smrg    return stateChange || ctrlChange;
170706f2543Smrg}
171706f2543Smrg
172706f2543Smrg	/*
173706f2543Smrg	 * Bool
174706f2543Smrg	 * ComputeAutoState(map,state,ctrls)
175706f2543Smrg	 *
176706f2543Smrg	 * This function reports the effect of applying the specified
177706f2543Smrg	 * indicator map given the specified state and controls, as
178706f2543Smrg	 * described in section 9.2 of the XKB protocol specification.
179706f2543Smrg	 */
180706f2543Smrg
181706f2543Smrgstatic Bool
182706f2543SmrgComputeAutoState(	XkbIndicatorMapPtr	map,
183706f2543Smrg			XkbStatePtr 		state,
184706f2543Smrg			XkbControlsPtr 		ctrls)
185706f2543Smrg{
186706f2543SmrgBool 			on;
187706f2543SmrgCARD8 			mods,group;
188706f2543Smrg
189706f2543Smrg    on= FALSE;
190706f2543Smrg    mods= group= 0;
191706f2543Smrg    if (map->which_mods&XkbIM_UseAnyMods) {
192706f2543Smrg	if (map->which_mods&XkbIM_UseBase)
193706f2543Smrg	    mods|= state->base_mods;
194706f2543Smrg	if (map->which_mods&XkbIM_UseLatched)
195706f2543Smrg	    mods|= state->latched_mods;
196706f2543Smrg	if (map->which_mods&XkbIM_UseLocked)
197706f2543Smrg	    mods|= state->locked_mods;
198706f2543Smrg	if (map->which_mods&XkbIM_UseEffective)
199706f2543Smrg	    mods|= state->mods;
200706f2543Smrg	if (map->which_mods&XkbIM_UseCompat)
201706f2543Smrg	    mods|= state->compat_state;
202706f2543Smrg	on = ((map->mods.mask&mods)!=0);
203706f2543Smrg	on = on||((mods==0)&&(map->mods.mask==0)&&(map->mods.vmods==0));
204706f2543Smrg    }
205706f2543Smrg    if (map->which_groups&XkbIM_UseAnyGroup) {
206706f2543Smrg	if (map->which_groups&XkbIM_UseBase)
207706f2543Smrg	    group|= (1L << state->base_group);
208706f2543Smrg	if (map->which_groups&XkbIM_UseLatched)
209706f2543Smrg	    group|= (1L << state->latched_group);
210706f2543Smrg	if (map->which_groups&XkbIM_UseLocked)
211706f2543Smrg	    group|= (1L << state->locked_group);
212706f2543Smrg	if (map->which_groups&XkbIM_UseEffective)
213706f2543Smrg	    group|= (1L << state->group);
214706f2543Smrg	on = on||(((map->groups&group)!=0)||(map->groups==0));
215706f2543Smrg    }
216706f2543Smrg    if (map->ctrls)
217706f2543Smrg	on = on||(ctrls->enabled_ctrls&map->ctrls);
218706f2543Smrg    return on;
219706f2543Smrg}
220706f2543Smrg
221706f2543Smrg
222706f2543Smrgstatic void
223706f2543SmrgXkbUpdateLedAutoState(	DeviceIntPtr			dev,
224706f2543Smrg			XkbSrvLedInfoPtr		sli,
225706f2543Smrg			unsigned			maps_to_check,
226706f2543Smrg			xkbExtensionDeviceNotify *	ed,
227706f2543Smrg			XkbChangesPtr			changes,
228706f2543Smrg			XkbEventCausePtr		cause)
229706f2543Smrg{
230706f2543SmrgDeviceIntPtr			kbd;
231706f2543SmrgXkbStatePtr			state;
232706f2543SmrgXkbControlsPtr			ctrls;
233706f2543SmrgXkbChangesRec			my_changes;
234706f2543SmrgxkbExtensionDeviceNotify	my_ed;
235706f2543Smrgregister unsigned		i,bit,affected;
236706f2543Smrgregister XkbIndicatorMapPtr	map;
237706f2543Smrgunsigned			oldState;
238706f2543Smrg
239706f2543Smrg    if ((maps_to_check==0)||(sli->maps==NULL)||(sli->mapsPresent==0))
240706f2543Smrg	return;
241706f2543Smrg
242706f2543Smrg    if (dev->key && dev->key->xkbInfo)
243706f2543Smrg	 kbd= dev;
244706f2543Smrg    else kbd= inputInfo.keyboard;
245706f2543Smrg
246706f2543Smrg    state= &kbd->key->xkbInfo->state;
247706f2543Smrg    ctrls= kbd->key->xkbInfo->desc->ctrls;
248706f2543Smrg    affected= maps_to_check;
249706f2543Smrg    oldState= sli->effectiveState;
250706f2543Smrg    sli->autoState&= ~affected;
251706f2543Smrg    for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) {
252706f2543Smrg	if ((affected&bit)==0)
253706f2543Smrg	    continue;
254706f2543Smrg	affected&= ~bit;
255706f2543Smrg	map= &sli->maps[i];
256706f2543Smrg	if((!(map->flags&XkbIM_NoAutomatic))&&ComputeAutoState(map,state,ctrls))
257706f2543Smrg	    sli->autoState|= bit;
258706f2543Smrg    }
259706f2543Smrg    sli->effectiveState= (sli->autoState|sli->explicitState);
260706f2543Smrg    affected= sli->effectiveState^oldState;
261706f2543Smrg    if (affected==0)
262706f2543Smrg	return;
263706f2543Smrg
264706f2543Smrg    if (ed==NULL) {
265706f2543Smrg	ed= &my_ed;
266706f2543Smrg	memset((char *)ed, 0, sizeof(xkbExtensionDeviceNotify));
267706f2543Smrg    }
268706f2543Smrg    else if ((ed->reason&XkbXI_IndicatorsMask)&&
269706f2543Smrg	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
270706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
271706f2543Smrg    }
272706f2543Smrg
273706f2543Smrg    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) {
274706f2543Smrg	if (changes==NULL) {
275706f2543Smrg	    changes= &my_changes;
276706f2543Smrg	    memset((char *)changes, 0, sizeof(XkbChangesRec));
277706f2543Smrg	}
278706f2543Smrg	changes->indicators.state_changes|= affected;
279706f2543Smrg    }
280706f2543Smrg
281706f2543Smrg    ed->reason|=	XkbXI_IndicatorStateMask;
282706f2543Smrg    ed->ledClass= 	sli->class;
283706f2543Smrg    ed->ledID=		sli->id;
284706f2543Smrg    ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
285706f2543Smrg    ed->ledState=	sli->effectiveState;
286706f2543Smrg    ed->unsupported=	0;
287706f2543Smrg    ed->supported=	XkbXI_AllFeaturesMask;
288706f2543Smrg
289706f2543Smrg    if (changes!=&my_changes)	changes= NULL;
290706f2543Smrg    if (ed!=&my_ed)		ed= NULL;
291706f2543Smrg    if (changes || ed)
292706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
293706f2543Smrg    return;
294706f2543Smrg}
295706f2543Smrg
296706f2543Smrgstatic void
297706f2543SmrgXkbUpdateAllDeviceIndicators(XkbChangesPtr changes,XkbEventCausePtr cause)
298706f2543Smrg{
299706f2543SmrgDeviceIntPtr		edev;
300706f2543SmrgXkbSrvLedInfoPtr	sli;
301706f2543Smrg
302706f2543Smrg    for (edev=inputInfo.devices;edev!=NULL;edev=edev->next) {
303706f2543Smrg	if (edev->kbdfeed) {
304706f2543Smrg	    KbdFeedbackPtr	kf;
305706f2543Smrg	    for (kf=edev->kbdfeed;kf!=NULL;kf=kf->next) {
306706f2543Smrg		if ((kf->xkb_sli==NULL)||(kf->xkb_sli->maps==NULL))
307706f2543Smrg		    continue;
308706f2543Smrg		sli= kf->xkb_sli;
309706f2543Smrg		XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL,
310706f2543Smrg								changes,cause);
311706f2543Smrg
312706f2543Smrg	    }
313706f2543Smrg	}
314706f2543Smrg	if (edev->leds) {
315706f2543Smrg	    LedFeedbackPtr	lf;
316706f2543Smrg	    for (lf=edev->leds;lf!=NULL;lf=lf->next) {
317706f2543Smrg		if ((lf->xkb_sli==NULL)||(lf->xkb_sli->maps==NULL))
318706f2543Smrg		    continue;
319706f2543Smrg		sli= lf->xkb_sli;
320706f2543Smrg		XkbUpdateLedAutoState(edev,sli,sli->mapsPresent,NULL,
321706f2543Smrg								changes,cause);
322706f2543Smrg
323706f2543Smrg	    }
324706f2543Smrg	}
325706f2543Smrg    }
326706f2543Smrg    return;
327706f2543Smrg}
328706f2543Smrg
329706f2543Smrg
330706f2543Smrg/***====================================================================***/
331706f2543Smrg
332706f2543Smrg	/*
333706f2543Smrg	 * void
334706f2543Smrg	 * XkbSetIndicators(dev,affect,values,cause)
335706f2543Smrg	 *
336706f2543Smrg	 * Attempts to change the indicators specified in 'affect' to the
337706f2543Smrg	 * states specified in 'values' for the default keyboard feedback
338706f2543Smrg	 * on the keyboard specified by 'dev.'   Attempts to change indicator
339706f2543Smrg	 * state might be ignored or have no affect, depending on the XKB
340706f2543Smrg	 * indicator map for any affected indicators, as described in section
341706f2543Smrg	 * 9.2 of the XKB protocol specification.
342706f2543Smrg	 *
343706f2543Smrg	 * If 'changes' is non-NULL, this function notes any changes to the
344706f2543Smrg	 * keyboard state, controls, or indicator state that result from this
345706f2543Smrg	 * attempted change.   If 'changes' is NULL, this function generates
346706f2543Smrg	 * XKB events to report any such changes to interested clients.
347706f2543Smrg	 *
348706f2543Smrg	 * If 'cause' is non-NULL, it specifies the reason for the change,
349706f2543Smrg	 * as reported in some XKB events.   If it is NULL, this function
350706f2543Smrg	 * assumes that the change is the result of a core protocol
351706f2543Smrg	 * ChangeKeyboardMapping request.
352706f2543Smrg	 */
353706f2543Smrg
354706f2543Smrgvoid
355706f2543SmrgXkbSetIndicators(	DeviceIntPtr		dev,
356706f2543Smrg			CARD32			affect,
357706f2543Smrg			CARD32			values,
358706f2543Smrg			XkbEventCausePtr	cause)
359706f2543Smrg{
360706f2543SmrgXkbSrvLedInfoPtr		sli;
361706f2543SmrgXkbChangesRec			changes;
362706f2543SmrgxkbExtensionDeviceNotify	ed;
363706f2543Smrgunsigned 			side_affected;
364706f2543Smrg
365706f2543Smrg    memset((char *)&changes, 0, sizeof(XkbChangesRec));
366706f2543Smrg    memset((char *)&ed, 0, sizeof(xkbExtensionDeviceNotify));
367706f2543Smrg    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
368706f2543Smrg    sli->explicitState&= ~affect;
369706f2543Smrg    sli->explicitState|= (affect&values);
370706f2543Smrg    XkbApplyLedStateChanges(dev,sli,affect,&ed,&changes,cause);
371706f2543Smrg
372706f2543Smrg    side_affected= 0;
373706f2543Smrg    if (changes.state_changes!=0)
374706f2543Smrg	side_affected|= XkbIndicatorsToUpdate(dev,changes.state_changes,FALSE);
375706f2543Smrg    if (changes.ctrls.enabled_ctrls_changes)
376706f2543Smrg	side_affected|= sli->usesControls;
377706f2543Smrg
378706f2543Smrg    if (side_affected) {
379706f2543Smrg	XkbUpdateLedAutoState(dev,sli,side_affected,&ed,&changes,cause);
380706f2543Smrg	affect|= side_affected;
381706f2543Smrg    }
382706f2543Smrg    if (changes.state_changes || changes.ctrls.enabled_ctrls_changes)
383706f2543Smrg	XkbUpdateAllDeviceIndicators(NULL,cause);
384706f2543Smrg
385706f2543Smrg    XkbFlushLedEvents(dev,dev,sli,&ed,&changes,cause);
386706f2543Smrg    return;
387706f2543Smrg}
388706f2543Smrg
389706f2543Smrg/***====================================================================***/
390706f2543Smrg
391706f2543Smrg/***====================================================================***/
392706f2543Smrg
393706f2543Smrg	/*
394706f2543Smrg	 * void
395706f2543Smrg	 * XkbUpdateIndicators(dev,update,check_edevs,changes,cause)
396706f2543Smrg	 *
397706f2543Smrg	 * Applies the indicator maps for any indicators specified in
398706f2543Smrg	 * 'update' from the default keyboard feedback on the device
399706f2543Smrg	 * specified by 'dev.'
400706f2543Smrg	 *
401706f2543Smrg	 * If 'changes' is NULL, this function generates and XKB events
402706f2543Smrg	 * required to report the necessary changes, otherwise it simply
403706f2543Smrg	 * notes the indicators with changed state.
404706f2543Smrg	 *
405706f2543Smrg	 * If 'check_edevs' is TRUE, this function also checks the indicator
406706f2543Smrg	 * maps for any open extension devices that have them, and updates
407706f2543Smrg	 * the state of any extension device indicators as necessary.
408706f2543Smrg	 */
409706f2543Smrg
410706f2543Smrgvoid
411706f2543SmrgXkbUpdateIndicators(	DeviceIntPtr		dev,
412706f2543Smrg			register CARD32		update,
413706f2543Smrg			Bool			check_edevs,
414706f2543Smrg			XkbChangesPtr		changes,
415706f2543Smrg			XkbEventCausePtr	cause)
416706f2543Smrg{
417706f2543SmrgXkbSrvLedInfoPtr	sli;
418706f2543Smrg
419706f2543Smrg    sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
420706f2543Smrg    XkbUpdateLedAutoState(dev,sli,update,NULL,changes,cause);
421706f2543Smrg    if (check_edevs)
422706f2543Smrg	XkbUpdateAllDeviceIndicators(changes,cause);
423706f2543Smrg    return;
424706f2543Smrg}
425706f2543Smrg
426706f2543Smrg/***====================================================================***/
427706f2543Smrg
428706f2543Smrg/***====================================================================***/
429706f2543Smrg
430706f2543Smrg	/*
431706f2543Smrg	 * void
432706f2543Smrg	 * XkbCheckIndicatorMaps(dev,sli,which)
433706f2543Smrg	 *
434706f2543Smrg	 * Updates the 'indicator accelerators' for the indicators specified
435706f2543Smrg	 * by 'which' in the feedback specified by 'sli.' The indicator
436706f2543Smrg	 * accelerators are internal to the server and are used to simplify
437706f2543Smrg	 * and speed up the process of figuring out which indicators might
438706f2543Smrg	 * be affected by a particular change in keyboard state or controls.
439706f2543Smrg	 */
440706f2543Smrg
441706f2543Smrgvoid
442706f2543SmrgXkbCheckIndicatorMaps(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned which)
443706f2543Smrg{
444706f2543Smrgregister unsigned	i,bit;
445706f2543SmrgXkbIndicatorMapPtr	map;
446706f2543SmrgXkbDescPtr		xkb;
447706f2543Smrg
448706f2543Smrg    if ((sli->flags&XkbSLI_HasOwnState)==0)
449706f2543Smrg        return;
450706f2543Smrg
451706f2543Smrg    sli->usesBase&=	 ~which;
452706f2543Smrg    sli->usesLatched&=	 ~which;
453706f2543Smrg    sli->usesLocked&=	 ~which;
454706f2543Smrg    sli->usesEffective&= ~which;
455706f2543Smrg    sli->usesCompat&=	 ~which;
456706f2543Smrg    sli->usesControls&=	 ~which;
457706f2543Smrg    sli->mapsPresent&=	 ~which;
458706f2543Smrg
459706f2543Smrg    xkb= dev->key->xkbInfo->desc;
460706f2543Smrg    for (i=0,bit=1,map=sli->maps;i<XkbNumIndicators;i++,bit<<=1,map++) {
461706f2543Smrg	if (which&bit) {
462706f2543Smrg	    CARD8		what;
463706f2543Smrg
464706f2543Smrg	    if (!map || !XkbIM_InUse(map))
465706f2543Smrg		continue;
466706f2543Smrg	    sli->mapsPresent|= bit;
467706f2543Smrg
468706f2543Smrg	    what= (map->which_mods|map->which_groups);
469706f2543Smrg	    if (what&XkbIM_UseBase)
470706f2543Smrg		 sli->usesBase|= bit;
471706f2543Smrg	    if (what&XkbIM_UseLatched)
472706f2543Smrg		 sli->usesLatched|= bit;
473706f2543Smrg	    if (what&XkbIM_UseLocked)
474706f2543Smrg		 sli->usesLocked|= bit;
475706f2543Smrg	    if (what&XkbIM_UseEffective)
476706f2543Smrg		 sli->usesEffective|= bit;
477706f2543Smrg	    if (what&XkbIM_UseCompat)
478706f2543Smrg		 sli->usesCompat|= bit;
479706f2543Smrg	    if (map->ctrls)
480706f2543Smrg		 sli->usesControls|= bit;
481706f2543Smrg
482706f2543Smrg	    map->mods.mask= map->mods.real_mods;
483706f2543Smrg	    if (map->mods.vmods!=0) {
484706f2543Smrg		map->mods.mask|= XkbMaskForVMask(xkb,map->mods.vmods);
485706f2543Smrg	    }
486706f2543Smrg	}
487706f2543Smrg    }
488706f2543Smrg    sli->usedComponents= 0;
489706f2543Smrg    if (sli->usesBase)
490706f2543Smrg	sli->usedComponents|= XkbModifierBaseMask|XkbGroupBaseMask;
491706f2543Smrg    if (sli->usesLatched)
492706f2543Smrg	sli->usedComponents|= XkbModifierLatchMask|XkbGroupLatchMask;
493706f2543Smrg    if (sli->usesLocked)
494706f2543Smrg	sli->usedComponents|= XkbModifierLockMask|XkbGroupLockMask;
495706f2543Smrg    if (sli->usesEffective)
496706f2543Smrg	sli->usedComponents|= XkbModifierStateMask|XkbGroupStateMask;
497706f2543Smrg    if (sli->usesCompat)
498706f2543Smrg	sli->usedComponents|= XkbCompatStateMask;
499706f2543Smrg    return;
500706f2543Smrg}
501706f2543Smrg
502706f2543Smrg/***====================================================================***/
503706f2543Smrg
504706f2543Smrg	/*
505706f2543Smrg	 * XkbSrvLedInfoPtr
506706f2543Smrg	 * XkbAllocSrvLedInfo(dev,kf,lf,needed_parts)
507706f2543Smrg	 *
508706f2543Smrg	 * Allocates an XkbSrvLedInfoPtr for the feedback specified by either
509706f2543Smrg	 * 'kf' or 'lf' on the keyboard specified by 'dev.'
510706f2543Smrg	 *
511706f2543Smrg	 * If 'needed_parts' is non-zero, this function makes sure that any
512706f2543Smrg	 * of the parts speicified therein are allocated.
513706f2543Smrg	 */
514706f2543SmrgXkbSrvLedInfoPtr
515706f2543SmrgXkbAllocSrvLedInfo(	DeviceIntPtr		dev,
516706f2543Smrg			KbdFeedbackPtr		kf,
517706f2543Smrg			LedFeedbackPtr		lf,
518706f2543Smrg			unsigned		needed_parts)
519706f2543Smrg{
520706f2543SmrgXkbSrvLedInfoPtr	sli;
521706f2543SmrgBool			checkAccel;
522706f2543SmrgBool			checkNames;
523706f2543Smrg
524706f2543Smrg    sli= NULL;
525706f2543Smrg    checkAccel= checkNames= FALSE;
526706f2543Smrg    if ((kf!=NULL)&&(kf->xkb_sli==NULL)) {
527706f2543Smrg	kf->xkb_sli= sli= calloc(1, sizeof(XkbSrvLedInfoRec));
528706f2543Smrg	if (sli==NULL)
529706f2543Smrg	    return NULL; /* ALLOCATION ERROR */
530706f2543Smrg	if (dev->key && dev->key->xkbInfo)
531706f2543Smrg	     sli->flags= XkbSLI_HasOwnState;
532706f2543Smrg	else sli->flags= 0;
533706f2543Smrg	sli->class=	KbdFeedbackClass;
534706f2543Smrg	sli->id=	kf->ctrl.id;
535706f2543Smrg	sli->fb.kf=	kf;
536706f2543Smrg
537706f2543Smrg	sli->autoState=		0;
538706f2543Smrg	sli->explicitState=	kf->ctrl.leds;
539706f2543Smrg	sli->effectiveState=	kf->ctrl.leds;
540706f2543Smrg
541706f2543Smrg	if ((kf==dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) {
542706f2543Smrg	    XkbDescPtr	xkb;
543706f2543Smrg	    xkb= dev->key->xkbInfo->desc;
544706f2543Smrg	    sli->flags|= 		XkbSLI_IsDefault;
545706f2543Smrg	    sli->physIndicators=	xkb->indicators->phys_indicators;
546706f2543Smrg	    sli->names=			xkb->names->indicators;
547706f2543Smrg	    sli->maps=			xkb->indicators->maps;
548706f2543Smrg	    checkNames= checkAccel=	TRUE;
549706f2543Smrg	}
550706f2543Smrg	else {
551706f2543Smrg	    sli->physIndicators=	XkbAllIndicatorsMask;
552706f2543Smrg	    sli->names=			NULL;
553706f2543Smrg	    sli->maps=			NULL;
554706f2543Smrg	}
555706f2543Smrg    }
556706f2543Smrg    else if ((kf!=NULL)&&((kf->xkb_sli->flags&XkbSLI_IsDefault)!=0)) {
557706f2543Smrg	XkbDescPtr	xkb;
558706f2543Smrg	xkb= dev->key->xkbInfo->desc;
559706f2543Smrg	sli= kf->xkb_sli;
560706f2543Smrg	sli->physIndicators=	xkb->indicators->phys_indicators;
561706f2543Smrg	if (xkb->names->indicators!=sli->names) {
562706f2543Smrg	    checkNames= TRUE;
563706f2543Smrg	    sli->names= xkb->names->indicators;
564706f2543Smrg	}
565706f2543Smrg	if (xkb->indicators->maps!=sli->maps) {
566706f2543Smrg	    checkAccel= TRUE;
567706f2543Smrg	    sli->maps= xkb->indicators->maps;
568706f2543Smrg	}
569706f2543Smrg    }
570706f2543Smrg    else if ((lf!=NULL)&&(lf->xkb_sli==NULL)) {
571706f2543Smrg	lf->xkb_sli= sli= calloc(1, sizeof(XkbSrvLedInfoRec));
572706f2543Smrg	if (sli==NULL)
573706f2543Smrg	    return NULL; /* ALLOCATION ERROR */
574706f2543Smrg	if (dev->key && dev->key->xkbInfo)
575706f2543Smrg	     sli->flags= XkbSLI_HasOwnState;
576706f2543Smrg	else sli->flags= 0;
577706f2543Smrg	sli->class=	LedFeedbackClass;
578706f2543Smrg	sli->id=	lf->ctrl.id;
579706f2543Smrg	sli->fb.lf=	lf;
580706f2543Smrg
581706f2543Smrg	sli->physIndicators=	lf->ctrl.led_mask;
582706f2543Smrg	sli->autoState=		0;
583706f2543Smrg	sli->explicitState=	lf->ctrl.led_values;
584706f2543Smrg	sli->effectiveState=	lf->ctrl.led_values;
585706f2543Smrg	sli->maps=		NULL;
586706f2543Smrg	sli->names=		NULL;
587706f2543Smrg    }
588706f2543Smrg    else
589706f2543Smrg	return NULL;
590706f2543Smrg    if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask))
591706f2543Smrg	sli->names= calloc(XkbNumIndicators, sizeof(Atom));
592706f2543Smrg    if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask))
593706f2543Smrg	sli->maps= calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
594706f2543Smrg    if (checkNames) {
595706f2543Smrg	register unsigned i,bit;
596706f2543Smrg	sli->namesPresent=	0;
597706f2543Smrg	for (i=0,bit=1;i<XkbNumIndicators;i++,bit<<=1) {
598706f2543Smrg	    if (sli->names[i]!=None)
599706f2543Smrg		sli->namesPresent|= bit;
600706f2543Smrg	}
601706f2543Smrg    }
602706f2543Smrg    if (checkAccel)
603706f2543Smrg	 XkbCheckIndicatorMaps(dev,sli,XkbAllIndicatorsMask);
604706f2543Smrg    return sli;
605706f2543Smrg}
606706f2543Smrg
607706f2543Smrgvoid
608706f2543SmrgXkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli)
609706f2543Smrg{
610706f2543Smrg    if ((sli->flags&XkbSLI_IsDefault)==0) {
611706f2543Smrg	free(sli->maps);
612706f2543Smrg	free(sli->names);
613706f2543Smrg    }
614706f2543Smrg    sli->maps= NULL;
615706f2543Smrg    sli->names= NULL;
616706f2543Smrg    free(sli);
617706f2543Smrg    return;
618706f2543Smrg}
619706f2543Smrg
620706f2543Smrg/*
621706f2543Smrg * XkbSrvLedInfoPtr
622706f2543Smrg * XkbCopySrvLedInfo(dev,src,kf,lf)
623706f2543Smrg *
624706f2543Smrg * Takes the given XkbSrvLedInfoPtr and duplicates it. A deep copy is made,
625706f2543Smrg * thus the new copy behaves like the original one and can be freed with
626706f2543Smrg * XkbFreeSrvLedInfo.
627706f2543Smrg */
628706f2543SmrgXkbSrvLedInfoPtr
629706f2543SmrgXkbCopySrvLedInfo(	DeviceIntPtr		from,
630706f2543Smrg			XkbSrvLedInfoPtr	src,
631706f2543Smrg			KbdFeedbackPtr		kf,
632706f2543Smrg			LedFeedbackPtr		lf)
633706f2543Smrg{
634706f2543Smrg    XkbSrvLedInfoPtr sli_new = NULL;
635706f2543Smrg
636706f2543Smrg    if (!src)
637706f2543Smrg	goto finish;
638706f2543Smrg
639706f2543Smrg    sli_new = calloc(1, sizeof( XkbSrvLedInfoRec));
640706f2543Smrg    if (!sli_new)
641706f2543Smrg	goto finish;
642706f2543Smrg
643706f2543Smrg    memcpy(sli_new, src, sizeof(XkbSrvLedInfoRec));
644706f2543Smrg    if (sli_new->class == KbdFeedbackClass)
645706f2543Smrg	sli_new->fb.kf = kf;
646706f2543Smrg    else
647706f2543Smrg	sli_new->fb.lf = lf;
648706f2543Smrg
649706f2543Smrg    if (!(sli_new->flags & XkbSLI_IsDefault)) {
650706f2543Smrg	sli_new->names= calloc(XkbNumIndicators, sizeof(Atom));
651706f2543Smrg	sli_new->maps= calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
652706f2543Smrg    } /* else sli_new->names/maps is pointing to
653706f2543Smrg	dev->key->xkbInfo->desc->names->indicators;
654706f2543Smrg	dev->key->xkbInfo->desc->names->indicators; */
655706f2543Smrg
656706f2543Smrgfinish:
657706f2543Smrg    return sli_new;
658706f2543Smrg}
659706f2543Smrg
660706f2543Smrg/***====================================================================***/
661706f2543Smrg
662706f2543Smrg	/*
663706f2543Smrg	 * XkbSrvLedInfoPtr
664706f2543Smrg	 * XkbFindSrvLedInfo(dev,class,id,needed_parts)
665706f2543Smrg	 *
666706f2543Smrg	 * Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id'
667706f2543Smrg	 * on the device specified by 'dev.'   If the class and id specify
668706f2543Smrg	 * a valid device feedback, this function returns the existing
669706f2543Smrg	 * feedback or allocates a new one.
670706f2543Smrg	 *
671706f2543Smrg	 */
672706f2543Smrg
673706f2543SmrgXkbSrvLedInfoPtr
674706f2543SmrgXkbFindSrvLedInfo(	DeviceIntPtr		dev,
675706f2543Smrg			unsigned		class,
676706f2543Smrg			unsigned		id,
677706f2543Smrg			unsigned		needed_parts)
678706f2543Smrg{
679706f2543SmrgXkbSrvLedInfoPtr	sli;
680706f2543Smrg
681706f2543Smrg    /* optimization to check for most common case */
682706f2543Smrg    if (((class==XkbDfltXIClass)&&(id==XkbDfltXIId))&&(dev->kbdfeed)) {
683706f2543Smrg	XkbSrvLedInfoPtr	sli;
684706f2543Smrg	sli= dev->kbdfeed->xkb_sli;
685706f2543Smrg	if (dev->kbdfeed->xkb_sli==NULL) {
686706f2543Smrg	    sli= XkbAllocSrvLedInfo(dev,dev->kbdfeed,NULL,needed_parts);
687706f2543Smrg	    dev->kbdfeed->xkb_sli= sli;
688706f2543Smrg	}
689706f2543Smrg	return dev->kbdfeed->xkb_sli;
690706f2543Smrg    }
691706f2543Smrg
692706f2543Smrg    sli= NULL;
693706f2543Smrg    if (class==XkbDfltXIClass) {
694706f2543Smrg	if (dev->kbdfeed)	class= KbdFeedbackClass;
695706f2543Smrg	else if (dev->leds)	class= LedFeedbackClass;
696706f2543Smrg	else 			return NULL;
697706f2543Smrg    }
698706f2543Smrg    if (class==KbdFeedbackClass) {
699706f2543Smrg	KbdFeedbackPtr	kf;
700706f2543Smrg	for (kf=dev->kbdfeed;kf!=NULL;kf=kf->next) {
701706f2543Smrg	    if ((id==XkbDfltXIId)||(id==kf->ctrl.id)) {
702706f2543Smrg		if (kf->xkb_sli==NULL)
703706f2543Smrg		    kf->xkb_sli= XkbAllocSrvLedInfo(dev,kf,NULL,needed_parts);
704706f2543Smrg		sli= kf->xkb_sli;
705706f2543Smrg		break;
706706f2543Smrg	    }
707706f2543Smrg	}
708706f2543Smrg    }
709706f2543Smrg    else if (class==LedFeedbackClass) {
710706f2543Smrg	LedFeedbackPtr	lf;
711706f2543Smrg	for (lf=dev->leds;lf!=NULL;lf=lf->next) {
712706f2543Smrg	    if ((id==XkbDfltXIId)||(id==lf->ctrl.id)) {
713706f2543Smrg		if (lf->xkb_sli==NULL)
714706f2543Smrg		    lf->xkb_sli= XkbAllocSrvLedInfo(dev,NULL,lf,needed_parts);
715706f2543Smrg		sli= lf->xkb_sli;
716706f2543Smrg		break;
717706f2543Smrg	    }
718706f2543Smrg	}
719706f2543Smrg    }
720706f2543Smrg    if (sli) {
721706f2543Smrg	if ((sli->names==NULL)&&(needed_parts&XkbXI_IndicatorNamesMask))
722706f2543Smrg	    sli->names= calloc(XkbNumIndicators, sizeof(Atom));
723706f2543Smrg	if ((sli->maps==NULL)&&(needed_parts&XkbXI_IndicatorMapsMask))
724706f2543Smrg	    sli->maps= calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
725706f2543Smrg    }
726706f2543Smrg    return sli;
727706f2543Smrg}
728706f2543Smrg
729706f2543Smrg/***====================================================================***/
730706f2543Smrg
731706f2543Smrgvoid
732706f2543SmrgXkbFlushLedEvents(	DeviceIntPtr			dev,
733706f2543Smrg			DeviceIntPtr			kbd,
734706f2543Smrg			XkbSrvLedInfoPtr		sli,
735706f2543Smrg			xkbExtensionDeviceNotify *	ed,
736706f2543Smrg			XkbChangesPtr			changes,
737706f2543Smrg			XkbEventCausePtr		cause)
738706f2543Smrg{
739706f2543Smrg    if (changes) {
740706f2543Smrg	if (changes->indicators.state_changes)
741706f2543Smrg	    XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState);
742706f2543Smrg	XkbSendNotification(kbd,changes,cause);
743706f2543Smrg	memset((char *)changes, 0, sizeof(XkbChangesRec));
744706f2543Smrg
745706f2543Smrg	if (XkbAX_NeedFeedback(kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) {
746706f2543Smrg		if (sli->effectiveState)
747706f2543Smrg			/* it appears that the which parameter is not used */
748706f2543Smrg			XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask);
749706f2543Smrg		else
750706f2543Smrg			XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask);
751706f2543Smrg	}
752706f2543Smrg    }
753706f2543Smrg    if (ed) {
754706f2543Smrg	if (ed->reason) {
755706f2543Smrg	    if ((dev!=kbd)&&(ed->reason&XkbXI_IndicatorStateMask))
756706f2543Smrg		XkbDDXUpdateDeviceIndicators(dev,sli,sli->effectiveState);
757706f2543Smrg	    XkbSendExtensionDeviceNotify(dev,cause->client,ed);
758706f2543Smrg	}
759706f2543Smrg	memset((char *)ed, 0, sizeof(XkbExtensionDeviceNotify));
760706f2543Smrg    }
761706f2543Smrg    return;
762706f2543Smrg}
763706f2543Smrg
764706f2543Smrg/***====================================================================***/
765706f2543Smrg
766706f2543Smrgvoid
767706f2543SmrgXkbApplyLedNameChanges(	DeviceIntPtr 			dev,
768706f2543Smrg			XkbSrvLedInfoPtr		sli,
769706f2543Smrg			unsigned			changed_names,
770706f2543Smrg			xkbExtensionDeviceNotify *	ed,
771706f2543Smrg			XkbChangesPtr			changes,
772706f2543Smrg			XkbEventCausePtr		cause)
773706f2543Smrg{
774706f2543SmrgDeviceIntPtr			kbd;
775706f2543SmrgXkbChangesRec			my_changes;
776706f2543SmrgxkbExtensionDeviceNotify	my_ed;
777706f2543Smrg
778706f2543Smrg    if (changed_names==0)
779706f2543Smrg	return;
780706f2543Smrg    if (dev->key && dev->key->xkbInfo)
781706f2543Smrg	 kbd= dev;
782706f2543Smrg    else kbd= inputInfo.keyboard;
783706f2543Smrg
784706f2543Smrg    if (ed==NULL) {
785706f2543Smrg	ed= &my_ed;
786706f2543Smrg	memset((char *)ed, 0, sizeof(xkbExtensionDeviceNotify));
787706f2543Smrg    }
788706f2543Smrg    else if ((ed->reason&XkbXI_IndicatorsMask)&&
789706f2543Smrg	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
790706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
791706f2543Smrg    }
792706f2543Smrg
793706f2543Smrg    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) {
794706f2543Smrg	if (changes==NULL) {
795706f2543Smrg	   changes= &my_changes;
796706f2543Smrg	   memset((char *)changes, 0, sizeof(XkbChangesRec));
797706f2543Smrg	}
798706f2543Smrg	changes->names.changed|= XkbIndicatorNamesMask;
799706f2543Smrg	changes->names.changed_indicators|= changed_names;
800706f2543Smrg    }
801706f2543Smrg
802706f2543Smrg    ed->reason|=	XkbXI_IndicatorNamesMask;
803706f2543Smrg    ed->ledClass= 	sli->class;
804706f2543Smrg    ed->ledID=		sli->id;
805706f2543Smrg    ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
806706f2543Smrg    ed->ledState=	sli->effectiveState;
807706f2543Smrg    ed->unsupported=	0;
808706f2543Smrg    ed->supported=	XkbXI_AllFeaturesMask;
809706f2543Smrg
810706f2543Smrg    if (changes!=&my_changes)	changes= NULL;
811706f2543Smrg    if (ed!=&my_ed)		ed= NULL;
812706f2543Smrg    if (changes || ed)
813706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
814706f2543Smrg    return;
815706f2543Smrg}
816706f2543Smrg/***====================================================================***/
817706f2543Smrg
818706f2543Smrg	/*
819706f2543Smrg	 * void
820706f2543Smrg	 * XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause)
821706f2543Smrg	 *
822706f2543Smrg	 * Handles all of the secondary effects of the changes to the
823706f2543Smrg	 * feedback specified by 'sli' on the device specified by 'dev.'
824706f2543Smrg	 *
825706f2543Smrg	 * If 'changed_maps' specifies any indicators, this function generates
826706f2543Smrg	 * XkbExtensionDeviceNotify events and possibly IndicatorMapNotify
827706f2543Smrg	 * events to report the changes, and recalculates the effective
828706f2543Smrg	 * state of each indicator with a changed map.  If any indicators
829706f2543Smrg	 * change state, the server generates XkbExtensionDeviceNotify and
830706f2543Smrg	 * XkbIndicatorStateNotify events as appropriate.
831706f2543Smrg	 *
832706f2543Smrg	 * If 'changes' is non-NULL, this function updates it to reflect
833706f2543Smrg	 * any changes to the keyboard state or controls or to the 'core'
834706f2543Smrg	 * indicator names, maps, or state.   If 'changes' is NULL, this
835706f2543Smrg	 * function generates XKB events as needed to report the changes.
836706f2543Smrg	 * If 'dev' is not a keyboard device, any changes are reported
837706f2543Smrg	 * for the core keyboard.
838706f2543Smrg	 *
839706f2543Smrg	 * The 'cause' specifies the reason for the event (key event or
840706f2543Smrg	 * request) for the change, as reported in some XKB events.
841706f2543Smrg	 */
842706f2543Smrg
843706f2543Smrgvoid
844706f2543SmrgXkbApplyLedMapChanges(	DeviceIntPtr 			dev,
845706f2543Smrg			XkbSrvLedInfoPtr		sli,
846706f2543Smrg			unsigned			changed_maps,
847706f2543Smrg			xkbExtensionDeviceNotify *	ed,
848706f2543Smrg			XkbChangesPtr			changes,
849706f2543Smrg			XkbEventCausePtr		cause)
850706f2543Smrg{
851706f2543SmrgDeviceIntPtr			kbd;
852706f2543SmrgXkbChangesRec			my_changes;
853706f2543SmrgxkbExtensionDeviceNotify	my_ed;
854706f2543Smrg
855706f2543Smrg    if (changed_maps==0)
856706f2543Smrg	return;
857706f2543Smrg    if (dev->key && dev->key->xkbInfo)
858706f2543Smrg	 kbd= dev;
859706f2543Smrg    else kbd= inputInfo.keyboard;
860706f2543Smrg
861706f2543Smrg    if (ed==NULL) {
862706f2543Smrg	ed= &my_ed;
863706f2543Smrg	memset((char *)ed, 0, sizeof(xkbExtensionDeviceNotify));
864706f2543Smrg    }
865706f2543Smrg    else if ((ed->reason&XkbXI_IndicatorsMask)&&
866706f2543Smrg	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
867706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
868706f2543Smrg    }
869706f2543Smrg
870706f2543Smrg    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault)) {
871706f2543Smrg	if (changes==NULL) {
872706f2543Smrg	    changes= &my_changes;
873706f2543Smrg	    memset((char *)changes, 0, sizeof(XkbChangesRec));
874706f2543Smrg	}
875706f2543Smrg	changes->indicators.map_changes|= changed_maps;
876706f2543Smrg    }
877706f2543Smrg
878706f2543Smrg    XkbCheckIndicatorMaps(dev,sli,changed_maps);
879706f2543Smrg
880706f2543Smrg    ed->reason|=	XkbXI_IndicatorMapsMask;
881706f2543Smrg    ed->ledClass= 	sli->class;
882706f2543Smrg    ed->ledID=		sli->id;
883706f2543Smrg    ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
884706f2543Smrg    ed->ledState=	sli->effectiveState;
885706f2543Smrg    ed->unsupported=	0;
886706f2543Smrg    ed->supported=	XkbXI_AllFeaturesMask;
887706f2543Smrg
888706f2543Smrg    XkbUpdateLedAutoState(dev,sli,changed_maps,ed,changes,cause);
889706f2543Smrg
890706f2543Smrg    if (changes!=&my_changes)	changes= NULL;
891706f2543Smrg    if (ed!=&my_ed)		ed= NULL;
892706f2543Smrg    if (changes || ed)
893706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
894706f2543Smrg    return;
895706f2543Smrg}
896706f2543Smrg
897706f2543Smrg/***====================================================================***/
898706f2543Smrg
899706f2543Smrgvoid
900706f2543SmrgXkbApplyLedStateChanges(DeviceIntPtr 			dev,
901706f2543Smrg			XkbSrvLedInfoPtr		sli,
902706f2543Smrg			unsigned			changed_leds,
903706f2543Smrg			xkbExtensionDeviceNotify *	ed,
904706f2543Smrg			XkbChangesPtr			changes,
905706f2543Smrg			XkbEventCausePtr		cause)
906706f2543Smrg{
907706f2543SmrgXkbSrvInfoPtr			xkbi;
908706f2543SmrgDeviceIntPtr			kbd;
909706f2543SmrgXkbChangesRec			my_changes;
910706f2543SmrgxkbExtensionDeviceNotify	my_ed;
911706f2543Smrgregister unsigned		i,bit,affected;
912706f2543SmrgXkbIndicatorMapPtr		map;
913706f2543Smrgunsigned			oldState;
914706f2543SmrgBool				kb_changed;
915706f2543Smrg
916706f2543Smrg    if (changed_leds==0)
917706f2543Smrg	return;
918706f2543Smrg    if (dev->key && dev->key->xkbInfo)
919706f2543Smrg	 kbd= dev;
920706f2543Smrg    else kbd= inputInfo.keyboard;
921706f2543Smrg    xkbi= kbd->key->xkbInfo;
922706f2543Smrg
923706f2543Smrg    if (changes==NULL) {
924706f2543Smrg	changes= &my_changes;
925706f2543Smrg	memset((char *)changes, 0, sizeof(XkbChangesRec));
926706f2543Smrg    }
927706f2543Smrg
928706f2543Smrg    kb_changed= FALSE;
929706f2543Smrg    affected= changed_leds;
930706f2543Smrg    oldState= sli->effectiveState;
931706f2543Smrg    for (i=0,bit=1;(i<XkbNumIndicators)&&(affected);i++,bit<<=1) {
932706f2543Smrg	if ((affected&bit)==0)
933706f2543Smrg	    continue;
934706f2543Smrg	affected&= ~bit;
935706f2543Smrg	map= &sli->maps[i];
936706f2543Smrg	if (map->flags&XkbIM_NoExplicit) {
937706f2543Smrg	    sli->explicitState&= ~bit;
938706f2543Smrg	    continue;
939706f2543Smrg	}
940706f2543Smrg	if (map->flags&XkbIM_LEDDrivesKB) {
941706f2543Smrg	    Bool on= ((sli->explicitState&bit)!=0);
942706f2543Smrg	    if (XkbApplyLEDChangeToKeyboard(xkbi,map,on,changes))
943706f2543Smrg		kb_changed= TRUE;
944706f2543Smrg	}
945706f2543Smrg    }
946706f2543Smrg    sli->effectiveState= (sli->autoState|sli->explicitState);
947706f2543Smrg    affected= sli->effectiveState^oldState;
948706f2543Smrg
949706f2543Smrg    if (ed==NULL) {
950706f2543Smrg	ed= &my_ed;
951706f2543Smrg	memset((char *)ed, 0, sizeof(xkbExtensionDeviceNotify));
952706f2543Smrg    }
953706f2543Smrg    else if (affected&&(ed->reason&XkbXI_IndicatorsMask)&&
954706f2543Smrg	     ((ed->ledClass!=sli->class)||(ed->ledID!=sli->id))) {
955706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
956706f2543Smrg    }
957706f2543Smrg
958706f2543Smrg    if ((kbd==dev)&&(sli->flags&XkbSLI_IsDefault))
959706f2543Smrg	changes->indicators.state_changes|= affected;
960706f2543Smrg    if (affected) {
961706f2543Smrg	ed->reason|=		XkbXI_IndicatorStateMask;
962706f2543Smrg	ed->ledClass= 		sli->class;
963706f2543Smrg	ed->ledID=		sli->id;
964706f2543Smrg	ed->ledsDefined=	sli->namesPresent|sli->mapsPresent;
965706f2543Smrg	ed->ledState=		sli->effectiveState;
966706f2543Smrg	ed->unsupported=	0;
967706f2543Smrg	ed->supported=		XkbXI_AllFeaturesMask;
968706f2543Smrg    }
969706f2543Smrg
970706f2543Smrg    if (kb_changed) {
971706f2543Smrg	XkbComputeDerivedState(kbd->key->xkbInfo);
972706f2543Smrg	XkbUpdateLedAutoState(dev,sli,sli->mapsPresent,ed,changes,cause);
973706f2543Smrg    }
974706f2543Smrg
975706f2543Smrg    if (changes!=&my_changes)	changes= NULL;
976706f2543Smrg    if (ed!=&my_ed)		ed= NULL;
977706f2543Smrg    if (changes || ed)
978706f2543Smrg	XkbFlushLedEvents(dev,kbd,sli,ed,changes,cause);
979706f2543Smrg    if (kb_changed)
980706f2543Smrg	XkbUpdateAllDeviceIndicators(NULL,cause);
981706f2543Smrg    return;
982706f2543Smrg}
983