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