1006 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1006 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
| /************************************************************
 | |
| Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this
 | |
| software and its documentation for any purpose and without
 | |
| fee is hereby granted, provided that the above copyright
 | |
| notice appear in all copies and that both that copyright
 | |
| notice and this permission notice appear in supporting
 | |
| documentation, and that the name of Silicon Graphics not be
 | |
| used in advertising or publicity pertaining to distribution
 | |
| of the software without specific prior written permission.
 | |
| Silicon Graphics makes no representation about the suitability
 | |
| of this software for any purpose. It is provided "as is"
 | |
| without any express or implied warranty.
 | |
| 
 | |
| SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 | |
| SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 | |
| AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
 | |
| GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 | |
| DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
| DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 | |
| OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
 | |
| THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
| ********************************************************/
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <ctype.h>
 | |
| #include <math.h>
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include "misc.h"
 | |
| #include "inputstr.h"
 | |
| 
 | |
| #include <X11/extensions/XI.h>
 | |
| #include <xkbsrv.h>
 | |
| #include "xkb.h"
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * unsigned
 | |
|          * XkbIndicatorsToUpdate(dev,changed,check_devs_rtrn)
 | |
|          *
 | |
|          * Given a keyboard and a set of state components that have changed,
 | |
|          * this function returns the indicators on the default keyboard
 | |
|          * feedback that might be affected.   It also reports whether or not
 | |
|          * any extension devices might be affected in check_devs_rtrn.
 | |
|          */
 | |
| 
 | |
| unsigned
 | |
| XkbIndicatorsToUpdate(DeviceIntPtr dev,
 | |
|                       unsigned long state_changes, Bool enable_changes)
 | |
| {
 | |
|     register unsigned update = 0;
 | |
|     XkbSrvLedInfoPtr sli;
 | |
| 
 | |
|     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
 | |
| 
 | |
|     if (!sli)
 | |
|         return update;
 | |
| 
 | |
|     if (state_changes & (XkbModifierStateMask | XkbGroupStateMask))
 | |
|         update |= sli->usesEffective;
 | |
|     if (state_changes & (XkbModifierBaseMask | XkbGroupBaseMask))
 | |
|         update |= sli->usesBase;
 | |
|     if (state_changes & (XkbModifierLatchMask | XkbGroupLatchMask))
 | |
|         update |= sli->usesLatched;
 | |
|     if (state_changes & (XkbModifierLockMask | XkbGroupLockMask))
 | |
|         update |= sli->usesLocked;
 | |
|     if (state_changes & XkbCompatStateMask)
 | |
|         update |= sli->usesCompat;
 | |
|     if (enable_changes)
 | |
|         update |= sli->usesControls;
 | |
|     return update;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * Bool
 | |
|          *XkbApplyLEDChangeToKeyboard(xkbi,map,on,change)
 | |
|          *
 | |
|          * Some indicators "drive" the keyboard when their state is explicitly
 | |
|          * changed, as described in section 9.2.1 of the XKB protocol spec.
 | |
|          * This function updates the state and controls for the keyboard
 | |
|          * specified by 'xkbi' to reflect any changes that are required
 | |
|          * when the indicator described by 'map' is turned on or off.  The
 | |
|          * extent of the changes is reported in change, which must be defined.
 | |
|          */
 | |
| static Bool
 | |
| XkbApplyLEDChangeToKeyboard(XkbSrvInfoPtr xkbi,
 | |
|                             XkbIndicatorMapPtr map,
 | |
|                             Bool on, XkbChangesPtr change)
 | |
| {
 | |
|     Bool ctrlChange, stateChange;
 | |
|     XkbStatePtr state;
 | |
| 
 | |
|     if ((map->flags & XkbIM_NoExplicit) ||
 | |
|         ((map->flags & XkbIM_LEDDrivesKB) == 0))
 | |
|         return FALSE;
 | |
|     ctrlChange = stateChange = FALSE;
 | |
|     if (map->ctrls) {
 | |
|         XkbControlsPtr ctrls = xkbi->desc->ctrls;
 | |
|         unsigned old;
 | |
| 
 | |
|         old = ctrls->enabled_ctrls;
 | |
|         if (on)
 | |
|             ctrls->enabled_ctrls |= map->ctrls;
 | |
|         else
 | |
|             ctrls->enabled_ctrls &= ~map->ctrls;
 | |
|         if (old != ctrls->enabled_ctrls) {
 | |
|             change->ctrls.changed_ctrls = XkbControlsEnabledMask;
 | |
|             change->ctrls.enabled_ctrls_changes = old ^ ctrls->enabled_ctrls;
 | |
|             ctrlChange = TRUE;
 | |
|         }
 | |
|     }
 | |
|     state = &xkbi->state;
 | |
|     if ((map->groups) && ((map->which_groups & (~XkbIM_UseBase)) != 0)) {
 | |
|         register int i;
 | |
|         register unsigned bit, match;
 | |
| 
 | |
|         if (on)
 | |
|             match = (map->groups) & XkbAllGroupsMask;
 | |
|         else
 | |
|             match = (~map->groups) & XkbAllGroupsMask;
 | |
|         if (map->which_groups & (XkbIM_UseLocked | XkbIM_UseEffective)) {
 | |
|             for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
 | |
|                 if (bit & match)
 | |
|                     break;
 | |
|             }
 | |
|             if (map->which_groups & XkbIM_UseLatched)
 | |
|                 XkbLatchGroup(xkbi->device, 0); /* unlatch group */
 | |
|             state->locked_group = i;
 | |
|             stateChange = TRUE;
 | |
|         }
 | |
|         else if (map->which_groups & (XkbIM_UseLatched | XkbIM_UseEffective)) {
 | |
|             for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
 | |
|                 if (bit & match)
 | |
|                     break;
 | |
|             }
 | |
|             state->locked_group = 0;
 | |
|             XkbLatchGroup(xkbi->device, i);
 | |
|             stateChange = TRUE;
 | |
|         }
 | |
|     }
 | |
|     if ((map->mods.mask) && ((map->which_mods & (~XkbIM_UseBase)) != 0)) {
 | |
|         if (map->which_mods & (XkbIM_UseLocked | XkbIM_UseEffective)) {
 | |
|             register unsigned long old;
 | |
| 
 | |
|             old = state->locked_mods;
 | |
|             if (on)
 | |
|                 state->locked_mods |= map->mods.mask;
 | |
|             else
 | |
|                 state->locked_mods &= ~map->mods.mask;
 | |
|             if (state->locked_mods != old)
 | |
|                 stateChange = TRUE;
 | |
|         }
 | |
|         if (map->which_mods & (XkbIM_UseLatched | XkbIM_UseEffective)) {
 | |
|             register unsigned long newmods;
 | |
| 
 | |
|             newmods = state->latched_mods;
 | |
|             if (on)
 | |
|                 newmods |= map->mods.mask;
 | |
|             else
 | |
|                 newmods &= ~map->mods.mask;
 | |
|             if (newmods != state->locked_mods) {
 | |
|                 newmods &= map->mods.mask;
 | |
|                 XkbLatchModifiers(xkbi->device, map->mods.mask, newmods);
 | |
|                 stateChange = TRUE;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return stateChange || ctrlChange;
 | |
| }
 | |
| 
 | |
|         /*
 | |
|          * Bool
 | |
|          * ComputeAutoState(map,state,ctrls)
 | |
|          *
 | |
|          * This function reports the effect of applying the specified
 | |
|          * indicator map given the specified state and controls, as
 | |
|          * described in section 9.2 of the XKB protocol specification.
 | |
|          */
 | |
| 
 | |
| static Bool
 | |
| ComputeAutoState(XkbIndicatorMapPtr map,
 | |
|                  XkbStatePtr state, XkbControlsPtr ctrls)
 | |
| {
 | |
|     Bool on;
 | |
|     CARD8 mods, group;
 | |
| 
 | |
|     on = FALSE;
 | |
|     mods = group = 0;
 | |
|     if (map->which_mods & XkbIM_UseAnyMods) {
 | |
|         if (map->which_mods & XkbIM_UseBase)
 | |
|             mods |= state->base_mods;
 | |
|         if (map->which_mods & XkbIM_UseLatched)
 | |
|             mods |= state->latched_mods;
 | |
|         if (map->which_mods & XkbIM_UseLocked)
 | |
|             mods |= state->locked_mods;
 | |
|         if (map->which_mods & XkbIM_UseEffective)
 | |
|             mods |= state->mods;
 | |
|         if (map->which_mods & XkbIM_UseCompat)
 | |
|             mods |= state->compat_state;
 | |
|         on = ((map->mods.mask & mods) != 0);
 | |
|         on = on || ((mods == 0) && (map->mods.mask == 0) &&
 | |
|                     (map->mods.vmods == 0));
 | |
|     }
 | |
|     if (map->which_groups & XkbIM_UseAnyGroup) {
 | |
|         if (map->which_groups & XkbIM_UseBase)
 | |
|             group |= (1L << state->base_group);
 | |
|         if (map->which_groups & XkbIM_UseLatched)
 | |
|             group |= (1L << state->latched_group);
 | |
|         if (map->which_groups & XkbIM_UseLocked)
 | |
|             group |= (1L << state->locked_group);
 | |
|         if (map->which_groups & XkbIM_UseEffective)
 | |
|             group |= (1L << state->group);
 | |
|         on = on || (((map->groups & group) != 0) || (map->groups == 0));
 | |
|     }
 | |
|     if (map->ctrls)
 | |
|         on = on || (ctrls->enabled_ctrls & map->ctrls);
 | |
|     return on;
 | |
| }
 | |
| 
 | |
| static void
 | |
| XkbUpdateLedAutoState(DeviceIntPtr dev,
 | |
|                       XkbSrvLedInfoPtr sli,
 | |
|                       unsigned maps_to_check,
 | |
|                       xkbExtensionDeviceNotify * ed,
 | |
|                       XkbChangesPtr changes, XkbEventCausePtr cause)
 | |
| {
 | |
|     DeviceIntPtr kbd;
 | |
|     XkbStatePtr state;
 | |
|     XkbControlsPtr ctrls;
 | |
|     XkbChangesRec my_changes;
 | |
|     xkbExtensionDeviceNotify my_ed;
 | |
|     register unsigned i, bit, affected;
 | |
|     register XkbIndicatorMapPtr map;
 | |
|     unsigned oldState;
 | |
| 
 | |
|     if ((maps_to_check == 0) || (sli->maps == NULL) || (sli->mapsPresent == 0))
 | |
|         return;
 | |
| 
 | |
|     if (dev->key && dev->key->xkbInfo)
 | |
|         kbd = dev;
 | |
|     else
 | |
|         kbd = inputInfo.keyboard;
 | |
| 
 | |
|     state = &kbd->key->xkbInfo->state;
 | |
|     ctrls = kbd->key->xkbInfo->desc->ctrls;
 | |
|     affected = maps_to_check;
 | |
|     oldState = sli->effectiveState;
 | |
|     sli->autoState &= ~affected;
 | |
|     for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) {
 | |
|         if ((affected & bit) == 0)
 | |
|             continue;
 | |
|         affected &= ~bit;
 | |
|         map = &sli->maps[i];
 | |
|         if ((!(map->flags & XkbIM_NoAutomatic)) &&
 | |
|             ComputeAutoState(map, state, ctrls))
 | |
|             sli->autoState |= bit;
 | |
|     }
 | |
|     sli->effectiveState = (sli->autoState | sli->explicitState);
 | |
|     affected = sli->effectiveState ^ oldState;
 | |
|     if (affected == 0)
 | |
|         return;
 | |
| 
 | |
|     if (ed == NULL) {
 | |
|         ed = &my_ed;
 | |
|         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
 | |
|     }
 | |
|     else if ((ed->reason & XkbXI_IndicatorsMask) &&
 | |
|              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     }
 | |
| 
 | |
|     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
 | |
|         if (changes == NULL) {
 | |
|             changes = &my_changes;
 | |
|             memset((char *) changes, 0, sizeof(XkbChangesRec));
 | |
|         }
 | |
|         changes->indicators.state_changes |= affected;
 | |
|     }
 | |
| 
 | |
|     ed->reason |= XkbXI_IndicatorStateMask;
 | |
|     ed->ledClass = sli->class;
 | |
|     ed->ledID = sli->id;
 | |
|     ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
 | |
|     ed->ledState = sli->effectiveState;
 | |
|     ed->unsupported = 0;
 | |
|     ed->supported = XkbXI_AllFeaturesMask;
 | |
| 
 | |
|     if (changes != &my_changes)
 | |
|         changes = NULL;
 | |
|     if (ed != &my_ed)
 | |
|         ed = NULL;
 | |
|     if (changes || ed)
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| void
 | |
| XkbUpdateAllDeviceIndicators(XkbChangesPtr changes, XkbEventCausePtr cause)
 | |
| {
 | |
|     DeviceIntPtr edev;
 | |
|     XkbSrvLedInfoPtr sli;
 | |
| 
 | |
|     for (edev = inputInfo.devices; edev != NULL; edev = edev->next) {
 | |
|         if (edev->kbdfeed) {
 | |
|             KbdFeedbackPtr kf;
 | |
| 
 | |
|             for (kf = edev->kbdfeed; kf != NULL; kf = kf->next) {
 | |
|                 if ((kf->xkb_sli == NULL) || (kf->xkb_sli->maps == NULL))
 | |
|                     continue;
 | |
|                 sli = kf->xkb_sli;
 | |
|                 XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL,
 | |
|                                       changes, cause);
 | |
| 
 | |
|             }
 | |
|         }
 | |
|         if (edev->leds) {
 | |
|             LedFeedbackPtr lf;
 | |
| 
 | |
|             for (lf = edev->leds; lf != NULL; lf = lf->next) {
 | |
|                 if ((lf->xkb_sli == NULL) || (lf->xkb_sli->maps == NULL))
 | |
|                     continue;
 | |
|                 sli = lf->xkb_sli;
 | |
|                 XkbUpdateLedAutoState(edev, sli, sli->mapsPresent, NULL,
 | |
|                                       changes, cause);
 | |
| 
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * void
 | |
|          * XkbSetIndicators(dev,affect,values,cause)
 | |
|          *
 | |
|          * Attempts to change the indicators specified in 'affect' to the
 | |
|          * states specified in 'values' for the default keyboard feedback
 | |
|          * on the keyboard specified by 'dev.'   Attempts to change indicator
 | |
|          * state might be ignored or have no affect, depending on the XKB
 | |
|          * indicator map for any affected indicators, as described in section
 | |
|          * 9.2 of the XKB protocol specification.
 | |
|          *
 | |
|          * If 'changes' is non-NULL, this function notes any changes to the
 | |
|          * keyboard state, controls, or indicator state that result from this
 | |
|          * attempted change.   If 'changes' is NULL, this function generates
 | |
|          * XKB events to report any such changes to interested clients.
 | |
|          *
 | |
|          * If 'cause' is non-NULL, it specifies the reason for the change,
 | |
|          * as reported in some XKB events.   If it is NULL, this function
 | |
|          * assumes that the change is the result of a core protocol
 | |
|          * ChangeKeyboardMapping request.
 | |
|          */
 | |
| 
 | |
| void
 | |
| XkbSetIndicators(DeviceIntPtr dev,
 | |
|                  CARD32 affect, CARD32 values, XkbEventCausePtr cause)
 | |
| {
 | |
|     XkbSrvLedInfoPtr sli;
 | |
|     XkbChangesRec changes;
 | |
|     xkbExtensionDeviceNotify ed;
 | |
|     unsigned side_affected;
 | |
| 
 | |
|     memset((char *) &changes, 0, sizeof(XkbChangesRec));
 | |
|     memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify));
 | |
|     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
 | |
|     sli->explicitState &= ~affect;
 | |
|     sli->explicitState |= (affect & values);
 | |
|     XkbApplyLedStateChanges(dev, sli, affect, &ed, &changes, cause);
 | |
| 
 | |
|     side_affected = 0;
 | |
|     if (changes.state_changes != 0)
 | |
|         side_affected |=
 | |
|             XkbIndicatorsToUpdate(dev, changes.state_changes, FALSE);
 | |
|     if (changes.ctrls.enabled_ctrls_changes)
 | |
|         side_affected |= sli->usesControls;
 | |
| 
 | |
|     if (side_affected) {
 | |
|         XkbUpdateLedAutoState(dev, sli, side_affected, &ed, &changes, cause);
 | |
|         affect |= side_affected;
 | |
|     }
 | |
|     if (changes.state_changes || changes.ctrls.enabled_ctrls_changes)
 | |
|         XkbUpdateAllDeviceIndicators(NULL, cause);
 | |
| 
 | |
|     XkbFlushLedEvents(dev, dev, sli, &ed, &changes, cause);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * void
 | |
|          * XkbUpdateIndicators(dev,update,check_edevs,changes,cause)
 | |
|          *
 | |
|          * Applies the indicator maps for any indicators specified in
 | |
|          * 'update' from the default keyboard feedback on the device
 | |
|          * specified by 'dev.'
 | |
|          *
 | |
|          * If 'changes' is NULL, this function generates and XKB events
 | |
|          * required to report the necessary changes, otherwise it simply
 | |
|          * notes the indicators with changed state.
 | |
|          *
 | |
|          * If 'check_edevs' is TRUE, this function also checks the indicator
 | |
|          * maps for any open extension devices that have them, and updates
 | |
|          * the state of any extension device indicators as necessary.
 | |
|          */
 | |
| 
 | |
| void
 | |
| XkbUpdateIndicators(DeviceIntPtr dev,
 | |
|                     register CARD32 update,
 | |
|                     Bool check_edevs,
 | |
|                     XkbChangesPtr changes, XkbEventCausePtr cause)
 | |
| {
 | |
|     XkbSrvLedInfoPtr sli;
 | |
| 
 | |
|     sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
 | |
|     XkbUpdateLedAutoState(dev, sli, update, NULL, changes, cause);
 | |
|     if (check_edevs)
 | |
|         XkbUpdateAllDeviceIndicators(changes, cause);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * void
 | |
|          * XkbCheckIndicatorMaps(dev,sli,which)
 | |
|          *
 | |
|          * Updates the 'indicator accelerators' for the indicators specified
 | |
|          * by 'which' in the feedback specified by 'sli.' The indicator
 | |
|          * accelerators are internal to the server and are used to simplify
 | |
|          * and speed up the process of figuring out which indicators might
 | |
|          * be affected by a particular change in keyboard state or controls.
 | |
|          */
 | |
| 
 | |
| void
 | |
| XkbCheckIndicatorMaps(DeviceIntPtr dev, XkbSrvLedInfoPtr sli, unsigned which)
 | |
| {
 | |
|     register unsigned i, bit;
 | |
|     XkbIndicatorMapPtr map;
 | |
|     XkbDescPtr xkb;
 | |
| 
 | |
|     if ((sli->flags & XkbSLI_HasOwnState) == 0)
 | |
|         return;
 | |
| 
 | |
|     sli->usesBase &= ~which;
 | |
|     sli->usesLatched &= ~which;
 | |
|     sli->usesLocked &= ~which;
 | |
|     sli->usesEffective &= ~which;
 | |
|     sli->usesCompat &= ~which;
 | |
|     sli->usesControls &= ~which;
 | |
|     sli->mapsPresent &= ~which;
 | |
| 
 | |
|     xkb = dev->key->xkbInfo->desc;
 | |
|     for (i = 0, bit = 1, map = sli->maps; i < XkbNumIndicators;
 | |
|          i++, bit <<= 1, map++) {
 | |
|         if (which & bit) {
 | |
|             CARD8 what;
 | |
| 
 | |
|             if (!map || !XkbIM_InUse(map))
 | |
|                 continue;
 | |
|             sli->mapsPresent |= bit;
 | |
| 
 | |
|             what = (map->which_mods | map->which_groups);
 | |
|             if (what & XkbIM_UseBase)
 | |
|                 sli->usesBase |= bit;
 | |
|             if (what & XkbIM_UseLatched)
 | |
|                 sli->usesLatched |= bit;
 | |
|             if (what & XkbIM_UseLocked)
 | |
|                 sli->usesLocked |= bit;
 | |
|             if (what & XkbIM_UseEffective)
 | |
|                 sli->usesEffective |= bit;
 | |
|             if (what & XkbIM_UseCompat)
 | |
|                 sli->usesCompat |= bit;
 | |
|             if (map->ctrls)
 | |
|                 sli->usesControls |= bit;
 | |
| 
 | |
|             map->mods.mask = map->mods.real_mods;
 | |
|             if (map->mods.vmods != 0) {
 | |
|                 map->mods.mask |= XkbMaskForVMask(xkb, map->mods.vmods);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     sli->usedComponents = 0;
 | |
|     if (sli->usesBase)
 | |
|         sli->usedComponents |= XkbModifierBaseMask | XkbGroupBaseMask;
 | |
|     if (sli->usesLatched)
 | |
|         sli->usedComponents |= XkbModifierLatchMask | XkbGroupLatchMask;
 | |
|     if (sli->usesLocked)
 | |
|         sli->usedComponents |= XkbModifierLockMask | XkbGroupLockMask;
 | |
|     if (sli->usesEffective)
 | |
|         sli->usedComponents |= XkbModifierStateMask | XkbGroupStateMask;
 | |
|     if (sli->usesCompat)
 | |
|         sli->usedComponents |= XkbCompatStateMask;
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * XkbSrvLedInfoPtr
 | |
|          * XkbAllocSrvLedInfo(dev,kf,lf,needed_parts)
 | |
|          *
 | |
|          * Allocates an XkbSrvLedInfoPtr for the feedback specified by either
 | |
|          * 'kf' or 'lf' on the keyboard specified by 'dev.'
 | |
|          *
 | |
|          * If 'needed_parts' is non-zero, this function makes sure that any
 | |
|          * of the parts speicified therein are allocated.
 | |
|          */
 | |
| XkbSrvLedInfoPtr
 | |
| XkbAllocSrvLedInfo(DeviceIntPtr dev,
 | |
|                    KbdFeedbackPtr kf, LedFeedbackPtr lf, unsigned needed_parts)
 | |
| {
 | |
|     XkbSrvLedInfoPtr sli;
 | |
|     Bool checkAccel;
 | |
|     Bool checkNames;
 | |
| 
 | |
|     sli = NULL;
 | |
|     checkAccel = checkNames = FALSE;
 | |
|     if ((kf != NULL) && (kf->xkb_sli == NULL)) {
 | |
|         kf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec));
 | |
|         if (sli == NULL)
 | |
|             return NULL;        /* ALLOCATION ERROR */
 | |
|         if (dev->key && dev->key->xkbInfo)
 | |
|             sli->flags = XkbSLI_HasOwnState;
 | |
|         else
 | |
|             sli->flags = 0;
 | |
|         sli->class = KbdFeedbackClass;
 | |
|         sli->id = kf->ctrl.id;
 | |
|         sli->fb.kf = kf;
 | |
| 
 | |
|         sli->autoState = 0;
 | |
|         sli->explicitState = kf->ctrl.leds;
 | |
|         sli->effectiveState = kf->ctrl.leds;
 | |
| 
 | |
|         if ((kf == dev->kbdfeed) && (dev->key) && (dev->key->xkbInfo)) {
 | |
|             XkbDescPtr xkb;
 | |
| 
 | |
|             xkb = dev->key->xkbInfo->desc;
 | |
|             sli->flags |= XkbSLI_IsDefault;
 | |
|             sli->physIndicators = xkb->indicators->phys_indicators;
 | |
|             sli->names = xkb->names->indicators;
 | |
|             sli->maps = xkb->indicators->maps;
 | |
|             checkNames = checkAccel = TRUE;
 | |
|         }
 | |
|         else {
 | |
|             sli->physIndicators = XkbAllIndicatorsMask;
 | |
|             sli->names = NULL;
 | |
|             sli->maps = NULL;
 | |
|         }
 | |
|     }
 | |
|     else if ((kf != NULL) && ((kf->xkb_sli->flags & XkbSLI_IsDefault) != 0)) {
 | |
|         XkbDescPtr xkb;
 | |
| 
 | |
|         xkb = dev->key->xkbInfo->desc;
 | |
|         sli = kf->xkb_sli;
 | |
|         sli->physIndicators = xkb->indicators->phys_indicators;
 | |
|         if (xkb->names->indicators != sli->names) {
 | |
|             checkNames = TRUE;
 | |
|             sli->names = xkb->names->indicators;
 | |
|         }
 | |
|         if (xkb->indicators->maps != sli->maps) {
 | |
|             checkAccel = TRUE;
 | |
|             sli->maps = xkb->indicators->maps;
 | |
|         }
 | |
|     }
 | |
|     else if ((lf != NULL) && (lf->xkb_sli == NULL)) {
 | |
|         lf->xkb_sli = sli = calloc(1, sizeof(XkbSrvLedInfoRec));
 | |
|         if (sli == NULL)
 | |
|             return NULL;        /* ALLOCATION ERROR */
 | |
|         if (dev->key && dev->key->xkbInfo)
 | |
|             sli->flags = XkbSLI_HasOwnState;
 | |
|         else
 | |
|             sli->flags = 0;
 | |
|         sli->class = LedFeedbackClass;
 | |
|         sli->id = lf->ctrl.id;
 | |
|         sli->fb.lf = lf;
 | |
| 
 | |
|         sli->physIndicators = lf->ctrl.led_mask;
 | |
|         sli->autoState = 0;
 | |
|         sli->explicitState = lf->ctrl.led_values;
 | |
|         sli->effectiveState = lf->ctrl.led_values;
 | |
|         sli->maps = NULL;
 | |
|         sli->names = NULL;
 | |
|     }
 | |
|     else
 | |
|         return NULL;
 | |
|     if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask))
 | |
|         sli->names = calloc(XkbNumIndicators, sizeof(Atom));
 | |
|     if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask))
 | |
|         sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
 | |
|     if (checkNames) {
 | |
|         register unsigned i, bit;
 | |
| 
 | |
|         sli->namesPresent = 0;
 | |
|         for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
 | |
|             if (sli->names[i] != None)
 | |
|                 sli->namesPresent |= bit;
 | |
|         }
 | |
|     }
 | |
|     if (checkAccel)
 | |
|         XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask);
 | |
|     return sli;
 | |
| }
 | |
| 
 | |
| void
 | |
| XkbFreeSrvLedInfo(XkbSrvLedInfoPtr sli)
 | |
| {
 | |
|     if ((sli->flags & XkbSLI_IsDefault) == 0) {
 | |
|         free(sli->maps);
 | |
|         free(sli->names);
 | |
|     }
 | |
|     sli->maps = NULL;
 | |
|     sli->names = NULL;
 | |
|     free(sli);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * XkbSrvLedInfoPtr
 | |
|  * XkbCopySrvLedInfo(dev,src,kf,lf)
 | |
|  *
 | |
|  * Takes the given XkbSrvLedInfoPtr and duplicates it. A deep copy is made,
 | |
|  * thus the new copy behaves like the original one and can be freed with
 | |
|  * XkbFreeSrvLedInfo.
 | |
|  */
 | |
| XkbSrvLedInfoPtr
 | |
| XkbCopySrvLedInfo(DeviceIntPtr from,
 | |
|                   XkbSrvLedInfoPtr src, KbdFeedbackPtr kf, LedFeedbackPtr lf)
 | |
| {
 | |
|     XkbSrvLedInfoPtr sli_new = NULL;
 | |
| 
 | |
|     if (!src)
 | |
|         goto finish;
 | |
| 
 | |
|     sli_new = calloc(1, sizeof(XkbSrvLedInfoRec));
 | |
|     if (!sli_new)
 | |
|         goto finish;
 | |
| 
 | |
|     memcpy(sli_new, src, sizeof(XkbSrvLedInfoRec));
 | |
|     if (sli_new->class == KbdFeedbackClass)
 | |
|         sli_new->fb.kf = kf;
 | |
|     else
 | |
|         sli_new->fb.lf = lf;
 | |
| 
 | |
|     if (!(sli_new->flags & XkbSLI_IsDefault)) {
 | |
|         sli_new->names = calloc(XkbNumIndicators, sizeof(Atom));
 | |
|         sli_new->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
 | |
|     }                           /* else sli_new->names/maps is pointing to
 | |
|                                    dev->key->xkbInfo->desc->names->indicators;
 | |
|                                    dev->key->xkbInfo->desc->names->indicators; */
 | |
| 
 | |
|  finish:
 | |
|     return sli_new;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * XkbSrvLedInfoPtr
 | |
|          * XkbFindSrvLedInfo(dev,class,id,needed_parts)
 | |
|          *
 | |
|          * Finds the XkbSrvLedInfoPtr for the specified 'class' and 'id'
 | |
|          * on the device specified by 'dev.'   If the class and id specify
 | |
|          * a valid device feedback, this function returns the existing
 | |
|          * feedback or allocates a new one.
 | |
|          *
 | |
|          */
 | |
| 
 | |
| XkbSrvLedInfoPtr
 | |
| XkbFindSrvLedInfo(DeviceIntPtr dev,
 | |
|                   unsigned class, unsigned id, unsigned needed_parts)
 | |
| {
 | |
|     XkbSrvLedInfoPtr sli;
 | |
| 
 | |
|     /* optimization to check for most common case */
 | |
|     if (((class == XkbDfltXIClass) && (id == XkbDfltXIId)) && (dev->kbdfeed)) {
 | |
|         if (dev->kbdfeed->xkb_sli == NULL) {
 | |
|             dev->kbdfeed->xkb_sli =
 | |
|                 XkbAllocSrvLedInfo(dev, dev->kbdfeed, NULL, needed_parts);
 | |
|         }
 | |
|         return dev->kbdfeed->xkb_sli;
 | |
|     }
 | |
| 
 | |
|     sli = NULL;
 | |
|     if (class == XkbDfltXIClass) {
 | |
|         if (dev->kbdfeed)
 | |
|             class = KbdFeedbackClass;
 | |
|         else if (dev->leds)
 | |
|             class = LedFeedbackClass;
 | |
|         else
 | |
|             return NULL;
 | |
|     }
 | |
|     if (class == KbdFeedbackClass) {
 | |
|         KbdFeedbackPtr kf;
 | |
| 
 | |
|         for (kf = dev->kbdfeed; kf != NULL; kf = kf->next) {
 | |
|             if ((id == XkbDfltXIId) || (id == kf->ctrl.id)) {
 | |
|                 if (kf->xkb_sli == NULL)
 | |
|                     kf->xkb_sli =
 | |
|                         XkbAllocSrvLedInfo(dev, kf, NULL, needed_parts);
 | |
|                 sli = kf->xkb_sli;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     else if (class == LedFeedbackClass) {
 | |
|         LedFeedbackPtr lf;
 | |
| 
 | |
|         for (lf = dev->leds; lf != NULL; lf = lf->next) {
 | |
|             if ((id == XkbDfltXIId) || (id == lf->ctrl.id)) {
 | |
|                 if (lf->xkb_sli == NULL)
 | |
|                     lf->xkb_sli =
 | |
|                         XkbAllocSrvLedInfo(dev, NULL, lf, needed_parts);
 | |
|                 sli = lf->xkb_sli;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if (sli) {
 | |
|         if ((sli->names == NULL) && (needed_parts & XkbXI_IndicatorNamesMask))
 | |
|             sli->names = calloc(XkbNumIndicators, sizeof(Atom));
 | |
|         if ((sli->maps == NULL) && (needed_parts & XkbXI_IndicatorMapsMask))
 | |
|             sli->maps = calloc(XkbNumIndicators, sizeof(XkbIndicatorMapRec));
 | |
|     }
 | |
|     return sli;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| void
 | |
| XkbFlushLedEvents(DeviceIntPtr dev,
 | |
|                   DeviceIntPtr kbd,
 | |
|                   XkbSrvLedInfoPtr sli,
 | |
|                   xkbExtensionDeviceNotify * ed,
 | |
|                   XkbChangesPtr changes, XkbEventCausePtr cause)
 | |
| {
 | |
|     if (changes) {
 | |
|         if (changes->indicators.state_changes)
 | |
|             XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState);
 | |
|         XkbSendNotification(kbd, changes, cause);
 | |
|         memset((char *) changes, 0, sizeof(XkbChangesRec));
 | |
| 
 | |
|         if (XkbAX_NeedFeedback
 | |
|             (kbd->key->xkbInfo->desc->ctrls, XkbAX_IndicatorFBMask)) {
 | |
|             if (sli->effectiveState)
 | |
|                 /* it appears that the which parameter is not used */
 | |
|                 XkbDDXAccessXBeep(dev, _BEEP_LED_ON, XkbAccessXFeedbackMask);
 | |
|             else
 | |
|                 XkbDDXAccessXBeep(dev, _BEEP_LED_OFF, XkbAccessXFeedbackMask);
 | |
|         }
 | |
|     }
 | |
|     if (ed) {
 | |
|         if (ed->reason) {
 | |
|             if ((dev != kbd) && (ed->reason & XkbXI_IndicatorStateMask))
 | |
|                 XkbDDXUpdateDeviceIndicators(dev, sli, sli->effectiveState);
 | |
|             XkbSendExtensionDeviceNotify(dev, cause->client, ed);
 | |
|         }
 | |
|         memset((char *) ed, 0, sizeof(XkbExtensionDeviceNotify));
 | |
|     }
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| void
 | |
| XkbApplyLedNameChanges(DeviceIntPtr dev,
 | |
|                        XkbSrvLedInfoPtr sli,
 | |
|                        unsigned changed_names,
 | |
|                        xkbExtensionDeviceNotify * ed,
 | |
|                        XkbChangesPtr changes, XkbEventCausePtr cause)
 | |
| {
 | |
|     DeviceIntPtr kbd;
 | |
|     XkbChangesRec my_changes;
 | |
|     xkbExtensionDeviceNotify my_ed;
 | |
| 
 | |
|     if (changed_names == 0)
 | |
|         return;
 | |
|     if (dev->key && dev->key->xkbInfo)
 | |
|         kbd = dev;
 | |
|     else
 | |
|         kbd = inputInfo.keyboard;
 | |
| 
 | |
|     if (ed == NULL) {
 | |
|         ed = &my_ed;
 | |
|         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
 | |
|     }
 | |
|     else if ((ed->reason & XkbXI_IndicatorsMask) &&
 | |
|              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     }
 | |
| 
 | |
|     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
 | |
|         if (changes == NULL) {
 | |
|             changes = &my_changes;
 | |
|             memset((char *) changes, 0, sizeof(XkbChangesRec));
 | |
|         }
 | |
|         changes->names.changed |= XkbIndicatorNamesMask;
 | |
|         changes->names.changed_indicators |= changed_names;
 | |
|     }
 | |
| 
 | |
|     ed->reason |= XkbXI_IndicatorNamesMask;
 | |
|     ed->ledClass = sli->class;
 | |
|     ed->ledID = sli->id;
 | |
|     ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
 | |
|     ed->ledState = sli->effectiveState;
 | |
|     ed->unsupported = 0;
 | |
|     ed->supported = XkbXI_AllFeaturesMask;
 | |
| 
 | |
|     if (changes != &my_changes)
 | |
|         changes = NULL;
 | |
|     if (ed != &my_ed)
 | |
|         ed = NULL;
 | |
|     if (changes || ed)
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
|         /*
 | |
|          * void
 | |
|          * XkbApplyLedMapChanges(dev,sli,changed_maps,changes,cause)
 | |
|          *
 | |
|          * Handles all of the secondary effects of the changes to the
 | |
|          * feedback specified by 'sli' on the device specified by 'dev.'
 | |
|          *
 | |
|          * If 'changed_maps' specifies any indicators, this function generates
 | |
|          * XkbExtensionDeviceNotify events and possibly IndicatorMapNotify
 | |
|          * events to report the changes, and recalculates the effective
 | |
|          * state of each indicator with a changed map.  If any indicators
 | |
|          * change state, the server generates XkbExtensionDeviceNotify and
 | |
|          * XkbIndicatorStateNotify events as appropriate.
 | |
|          *
 | |
|          * If 'changes' is non-NULL, this function updates it to reflect
 | |
|          * any changes to the keyboard state or controls or to the 'core'
 | |
|          * indicator names, maps, or state.   If 'changes' is NULL, this
 | |
|          * function generates XKB events as needed to report the changes.
 | |
|          * If 'dev' is not a keyboard device, any changes are reported
 | |
|          * for the core keyboard.
 | |
|          *
 | |
|          * The 'cause' specifies the reason for the event (key event or
 | |
|          * request) for the change, as reported in some XKB events.
 | |
|          */
 | |
| 
 | |
| void
 | |
| XkbApplyLedMapChanges(DeviceIntPtr dev,
 | |
|                       XkbSrvLedInfoPtr sli,
 | |
|                       unsigned changed_maps,
 | |
|                       xkbExtensionDeviceNotify * ed,
 | |
|                       XkbChangesPtr changes, XkbEventCausePtr cause)
 | |
| {
 | |
|     DeviceIntPtr kbd;
 | |
|     XkbChangesRec my_changes;
 | |
|     xkbExtensionDeviceNotify my_ed;
 | |
| 
 | |
|     if (changed_maps == 0)
 | |
|         return;
 | |
|     if (dev->key && dev->key->xkbInfo)
 | |
|         kbd = dev;
 | |
|     else
 | |
|         kbd = inputInfo.keyboard;
 | |
| 
 | |
|     if (ed == NULL) {
 | |
|         ed = &my_ed;
 | |
|         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
 | |
|     }
 | |
|     else if ((ed->reason & XkbXI_IndicatorsMask) &&
 | |
|              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     }
 | |
| 
 | |
|     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault)) {
 | |
|         if (changes == NULL) {
 | |
|             changes = &my_changes;
 | |
|             memset((char *) changes, 0, sizeof(XkbChangesRec));
 | |
|         }
 | |
|         changes->indicators.map_changes |= changed_maps;
 | |
|     }
 | |
| 
 | |
|     XkbCheckIndicatorMaps(dev, sli, changed_maps);
 | |
| 
 | |
|     ed->reason |= XkbXI_IndicatorMapsMask;
 | |
|     ed->ledClass = sli->class;
 | |
|     ed->ledID = sli->id;
 | |
|     ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
 | |
|     ed->ledState = sli->effectiveState;
 | |
|     ed->unsupported = 0;
 | |
|     ed->supported = XkbXI_AllFeaturesMask;
 | |
| 
 | |
|     XkbUpdateLedAutoState(dev, sli, changed_maps, ed, changes, cause);
 | |
| 
 | |
|     if (changes != &my_changes)
 | |
|         changes = NULL;
 | |
|     if (ed != &my_ed)
 | |
|         ed = NULL;
 | |
|     if (changes || ed)
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /***====================================================================***/
 | |
| 
 | |
| void
 | |
| XkbApplyLedStateChanges(DeviceIntPtr dev,
 | |
|                         XkbSrvLedInfoPtr sli,
 | |
|                         unsigned changed_leds,
 | |
|                         xkbExtensionDeviceNotify * ed,
 | |
|                         XkbChangesPtr changes, XkbEventCausePtr cause)
 | |
| {
 | |
|     XkbSrvInfoPtr xkbi;
 | |
|     DeviceIntPtr kbd;
 | |
|     XkbChangesRec my_changes;
 | |
|     xkbExtensionDeviceNotify my_ed;
 | |
|     register unsigned i, bit, affected;
 | |
|     XkbIndicatorMapPtr map;
 | |
|     unsigned oldState;
 | |
|     Bool kb_changed;
 | |
| 
 | |
|     if (changed_leds == 0)
 | |
|         return;
 | |
|     if (dev->key && dev->key->xkbInfo)
 | |
|         kbd = dev;
 | |
|     else
 | |
|         kbd = inputInfo.keyboard;
 | |
|     xkbi = kbd->key->xkbInfo;
 | |
| 
 | |
|     if (changes == NULL) {
 | |
|         changes = &my_changes;
 | |
|         memset((char *) changes, 0, sizeof(XkbChangesRec));
 | |
|     }
 | |
| 
 | |
|     kb_changed = FALSE;
 | |
|     affected = changed_leds;
 | |
|     oldState = sli->effectiveState;
 | |
|     for (i = 0, bit = 1; (i < XkbNumIndicators) && (affected); i++, bit <<= 1) {
 | |
|         if ((affected & bit) == 0)
 | |
|             continue;
 | |
|         affected &= ~bit;
 | |
|         map = &sli->maps[i];
 | |
|         if (map->flags & XkbIM_NoExplicit) {
 | |
|             sli->explicitState &= ~bit;
 | |
|             continue;
 | |
|         }
 | |
|         if (map->flags & XkbIM_LEDDrivesKB) {
 | |
|             Bool on = ((sli->explicitState & bit) != 0);
 | |
| 
 | |
|             if (XkbApplyLEDChangeToKeyboard(xkbi, map, on, changes))
 | |
|                 kb_changed = TRUE;
 | |
|         }
 | |
|     }
 | |
|     sli->effectiveState = (sli->autoState | sli->explicitState);
 | |
|     affected = sli->effectiveState ^ oldState;
 | |
| 
 | |
|     if (ed == NULL) {
 | |
|         ed = &my_ed;
 | |
|         memset((char *) ed, 0, sizeof(xkbExtensionDeviceNotify));
 | |
|     }
 | |
|     else if (affected && (ed->reason & XkbXI_IndicatorsMask) &&
 | |
|              ((ed->ledClass != sli->class) || (ed->ledID != sli->id))) {
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     }
 | |
| 
 | |
|     if ((kbd == dev) && (sli->flags & XkbSLI_IsDefault))
 | |
|         changes->indicators.state_changes |= affected;
 | |
|     if (affected) {
 | |
|         ed->reason |= XkbXI_IndicatorStateMask;
 | |
|         ed->ledClass = sli->class;
 | |
|         ed->ledID = sli->id;
 | |
|         ed->ledsDefined = sli->namesPresent | sli->mapsPresent;
 | |
|         ed->ledState = sli->effectiveState;
 | |
|         ed->unsupported = 0;
 | |
|         ed->supported = XkbXI_AllFeaturesMask;
 | |
|     }
 | |
| 
 | |
|     if (kb_changed) {
 | |
|         XkbComputeDerivedState(kbd->key->xkbInfo);
 | |
|         XkbUpdateLedAutoState(dev, sli, sli->mapsPresent, ed, changes, cause);
 | |
|     }
 | |
| 
 | |
|     if (changes != &my_changes)
 | |
|         changes = NULL;
 | |
|     if (ed != &my_ed)
 | |
|         ed = NULL;
 | |
|     if (changes || ed)
 | |
|         XkbFlushLedEvents(dev, kbd, sli, ed, changes, cause);
 | |
|     if (kb_changed)
 | |
|         XkbUpdateAllDeviceIndicators(NULL, cause);
 | |
|     return;
 | |
| }
 |