1 /************************************************************
2 Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 ********************************************************/
27 #ifdef HAVE_DIX_CONFIG_H
28 #include <dix-config.h>
29 #endif
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"
39 #include <X11/extensions/XI.h>
40 #include <xkbsrv.h>
41 #include "xkb.h"
43 /***====================================================================***/
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 */
55 unsigned
56 XkbIndicatorsToUpdate( DeviceIntPtr dev,
57 unsigned long state_changes,
58 Bool enable_changes)
59 {
60 register unsigned update= 0;
61 XkbSrvLedInfoPtr sli;
63 sli= XkbFindSrvLedInfo(dev,XkbDfltXIClass,XkbDfltXIId,0);
65 if (!sli)
66 return update;
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 }
83 /***====================================================================***/
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 */
96 static Bool
97 XkbApplyLEDChangeToKeyboard( XkbSrvInfoPtr xkbi,
98 XkbIndicatorMapPtr map,
99 Bool on,
100 XkbChangesPtr change)
101 {
102 Bool ctrlChange,stateChange;
103 XkbStatePtr state;
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;
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;
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 }
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 */
181 static Bool
182 ComputeAutoState( XkbIndicatorMapPtr map,
183 XkbStatePtr state,
184 XkbControlsPtr ctrls)
185 {
186 Bool on;
187 CARD8 mods,group;
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 }
222 static void
223 XkbUpdateLedAutoState( DeviceIntPtr dev,
224 XkbSrvLedInfoPtr sli,
225 unsigned maps_to_check,
226 xkbExtensionDeviceNotify * ed,
227 XkbChangesPtr changes,
228 XkbEventCausePtr cause)
229 {
230 DeviceIntPtr kbd;
231 XkbStatePtr state;
232 XkbControlsPtr ctrls;
233 XkbChangesRec my_changes;
234 xkbExtensionDeviceNotify my_ed;
235 register unsigned i,bit,affected;
236 register XkbIndicatorMapPtr map;
237 unsigned oldState;
239 if ((maps_to_check==0)||(sli->maps==NULL)||(sli->mapsPresent==0))
240 return;
242 if (dev->key && dev->key->xkbInfo)
243 kbd= dev;
244 else kbd= inputInfo.keyboard;
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;
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 }
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 }
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;
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 }
296 static void
297 XkbUpdateAllDeviceIndicators(XkbChangesPtr changes,XkbEventCausePtr cause)
298 {
299 DeviceIntPtr edev;
300 XkbSrvLedInfoPtr sli;
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);
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);
323 }
324 }
325 }
326 return;
327 }
330 /***====================================================================***/
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 */
354 void
355 XkbSetIndicators( DeviceIntPtr dev,
356 CARD32 affect,
357 CARD32 values,
358 XkbEventCausePtr cause)
359 {
360 XkbSrvLedInfoPtr sli;
361 XkbChangesRec changes;
362 xkbExtensionDeviceNotify ed;
363 unsigned side_affected;
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);
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;
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);
385 XkbFlushLedEvents(dev,dev,sli,&ed,&changes,cause);
386 return;
387 }
389 /***====================================================================***/
391 /***====================================================================***/
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 */
410 void
411 XkbUpdateIndicators( DeviceIntPtr dev,
412 register CARD32 update,
413 Bool check_edevs,
414 XkbChangesPtr changes,
415 XkbEventCausePtr cause)
416 {
417 XkbSrvLedInfoPtr sli;
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 }
426 /***====================================================================***/
428 /***====================================================================***/
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 */
441 void
442 XkbCheckIndicatorMaps(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned which)
443 {
444 register unsigned i,bit;
445 XkbIndicatorMapPtr map;
446 XkbDescPtr xkb;
448 if ((sli->flags&XkbSLI_HasOwnState)==0)
449 return;
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;
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;
464 if (!map || !XkbIM_InUse(map))
465 continue;
466 sli->mapsPresent|= bit;
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;
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 }
502 /***====================================================================***/
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 */
514 XkbSrvLedInfoPtr
515 XkbAllocSrvLedInfo( DeviceIntPtr dev,
516 KbdFeedbackPtr kf,
517 LedFeedbackPtr lf,
518 unsigned needed_parts)
519 {
520 XkbSrvLedInfoPtr sli;
521 Bool checkAccel;
522 Bool checkNames;
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;
537 sli->autoState= 0;
538 sli->explicitState= kf->ctrl.leds;
539 sli->effectiveState= kf->ctrl.leds;
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;
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 }
607 void
608 XkbFreeSrvLedInfo(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 }
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 */
628 XkbSrvLedInfoPtr
629 XkbCopySrvLedInfo( DeviceIntPtr from,
630 XkbSrvLedInfoPtr src,
631 KbdFeedbackPtr kf,
632 LedFeedbackPtr lf)
633 {
634 XkbSrvLedInfoPtr sli_new = NULL;
636 if (!src)
637 goto finish;
639 sli_new = calloc(1, sizeof( XkbSrvLedInfoRec));
640 if (!sli_new)
641 goto finish;
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;
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; */
656 finish:
657 return sli_new;
658 }
660 /***====================================================================***/
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 */
673 XkbSrvLedInfoPtr
674 XkbFindSrvLedInfo( DeviceIntPtr dev,
675 unsigned class,
676 unsigned id,
677 unsigned needed_parts)
678 {
679 XkbSrvLedInfoPtr sli;
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 }
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 }
729 /***====================================================================***/
731 void
732 XkbFlushLedEvents( 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));
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 }
764 /***====================================================================***/
766 void
767 XkbApplyLedNameChanges( DeviceIntPtr dev,
768 XkbSrvLedInfoPtr sli,
769 unsigned changed_names,
770 xkbExtensionDeviceNotify * ed,
771 XkbChangesPtr changes,
772 XkbEventCausePtr cause)
773 {
774 DeviceIntPtr kbd;
775 XkbChangesRec my_changes;
776 xkbExtensionDeviceNotify my_ed;
778 if (changed_names==0)
779 return;
780 if (dev->key && dev->key->xkbInfo)
781 kbd= dev;
782 else kbd= inputInfo.keyboard;
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 }
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 }
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;
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 /***====================================================================***/
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 */
843 void
844 XkbApplyLedMapChanges( DeviceIntPtr dev,
845 XkbSrvLedInfoPtr sli,
846 unsigned changed_maps,
847 xkbExtensionDeviceNotify * ed,
848 XkbChangesPtr changes,
849 XkbEventCausePtr cause)
850 {
851 DeviceIntPtr kbd;
852 XkbChangesRec my_changes;
853 xkbExtensionDeviceNotify my_ed;
855 if (changed_maps==0)
856 return;
857 if (dev->key && dev->key->xkbInfo)
858 kbd= dev;
859 else kbd= inputInfo.keyboard;
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 }
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 }
878 XkbCheckIndicatorMaps(dev,sli,changed_maps);
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;
888 XkbUpdateLedAutoState(dev,sli,changed_maps,ed,changes,cause);
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 }
897 /***====================================================================***/
899 void
900 XkbApplyLedStateChanges(DeviceIntPtr dev,
901 XkbSrvLedInfoPtr sli,
902 unsigned changed_leds,
903 xkbExtensionDeviceNotify * ed,
904 XkbChangesPtr changes,
905 XkbEventCausePtr cause)
906 {
907 XkbSrvInfoPtr xkbi;
908 DeviceIntPtr kbd;
909 XkbChangesRec my_changes;
910 xkbExtensionDeviceNotify my_ed;
911 register unsigned i,bit,affected;
912 XkbIndicatorMapPtr map;
913 unsigned oldState;
914 Bool kb_changed;
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;
923 if (changes==NULL) {
924 changes= &my_changes;
925 memset((char *)changes, 0, sizeof(XkbChangesRec));
926 }
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;
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 }
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 }
970 if (kb_changed) {
971 XkbComputeDerivedState(kbd->key->xkbInfo);
972 XkbUpdateLedAutoState(dev,sli,sli->mapsPresent,ed,changes,cause);
973 }
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 }