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