1 /************************************************************
2 Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
3 
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.
15 
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.
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 
55 unsigned
XkbIndicatorsToUpdate(DeviceIntPtr dev,unsigned long state_changes,Bool enable_changes)56 XkbIndicatorsToUpdate(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          */
95 static Bool
XkbApplyLEDChangeToKeyboard(XkbSrvInfoPtr xkbi,XkbIndicatorMapPtr map,Bool on,XkbChangesPtr change)96 XkbApplyLEDChangeToKeyboard(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 
190 static Bool
ComputeAutoState(XkbIndicatorMapPtr map,XkbStatePtr state,XkbControlsPtr ctrls)191 ComputeAutoState(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 
230 static void
XkbUpdateLedAutoState(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned maps_to_check,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)231 XkbUpdateLedAutoState(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 
307 void
XkbUpdateAllDeviceIndicators(XkbChangesPtr changes,XkbEventCausePtr cause)308 XkbUpdateAllDeviceIndicators(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 
366 void
XkbSetIndicators(DeviceIntPtr dev,CARD32 affect,CARD32 values,XkbEventCausePtr cause)367 XkbSetIndicators(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 
421 void
XkbUpdateIndicators(DeviceIntPtr dev,register CARD32 update,Bool check_edevs,XkbChangesPtr changes,XkbEventCausePtr cause)422 XkbUpdateIndicators(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 
451 void
XkbCheckIndicatorMaps(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned which)452 XkbCheckIndicatorMaps(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          */
525 XkbSrvLedInfoPtr
XkbAllocSrvLedInfo(DeviceIntPtr dev,KbdFeedbackPtr kf,LedFeedbackPtr lf,unsigned needed_parts)526 XkbAllocSrvLedInfo(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 
621 void
XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli)622 XkbFreeSrvLedInfo(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  */
642 XkbSrvLedInfoPtr
XkbCopySrvLedInfo(DeviceIntPtr from,XkbSrvLedInfoPtr src,KbdFeedbackPtr kf,LedFeedbackPtr lf)643 XkbCopySrvLedInfo(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 
685 XkbSrvLedInfoPtr
XkbFindSrvLedInfo(DeviceIntPtr dev,unsigned class,unsigned id,unsigned needed_parts)686 XkbFindSrvLedInfo(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 
746 void
XkbFlushLedEvents(DeviceIntPtr dev,DeviceIntPtr kbd,XkbSrvLedInfoPtr sli,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)747 XkbFlushLedEvents(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 
781 void
XkbApplyLedNameChanges(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned changed_names,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)782 XkbApplyLedNameChanges(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 
861 void
XkbApplyLedMapChanges(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned changed_maps,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)862 XkbApplyLedMapChanges(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 
919 void
XkbApplyLedStateChanges(DeviceIntPtr dev,XkbSrvLedInfoPtr sli,unsigned changed_leds,xkbExtensionDeviceNotify * ed,XkbChangesPtr changes,XkbEventCausePtr cause)920 XkbApplyLedStateChanges(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 }
1006