From ac164e58870d70640381e68b776eb95578c7fbd3 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 4 May 2016 20:36:18 +1000 Subject: [PATCH] xkb: after changing the keymap, force an indicator update When NumLock is on and a new keymap is applied, the next modifier state change will turn off that LED (but leave the state enabled). The cause for this is a bit convoluted: * the SLI explicitState is copied from the current state in ProcXkbGetKbdByName. Thus, if NumLock is on, that state is 0x2. * on the next modifier key press (e.g. Shift), XkbApplyState() calls into XkbUpdateIndicators() -> XkbUpdateLedAutoState() to update SLIs (if any) for the currently changed modifier. But it does so with a mask only for the changed modifier (i.e. for Shift). * XkbUpdateLedAutoState() calculates the state based on this mask and ends up with 0 because we don't have a Shift LED and we masked out the others. * XkbUpdateLedAutoState() compares that state with the previous state (which is still 0x2) and then proceeds to turn the LED off This doesn't happen in the normal case because either the mask encompasses all modifiers or the state matches of the masked-out modifiers matches the old state. Avoid this issue by forcing an SLI update after changing the keymap. This updates the sli->effectiveState and thus restores everything to happy working order. https://bugzilla.redhat.com/show_bug.cgi?id=1047151 Signed-off-by: Peter Hutterer Reviewed-by: Daniel Stone --- include/xkbsrv.h | 4 ++++ xkb/xkb.c | 3 ++- xkb/xkbLEDs.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/xkbsrv.h b/include/xkbsrv.h index cc6307af5..7e71089f1 100644 --- a/include/xkbsrv.h +++ b/include/xkbsrv.h @@ -496,6 +496,10 @@ extern _X_EXPORT void XkbUpdateIndicators(DeviceIntPtr /* keybd */ , XkbEventCausePtr /* cause */ ); +extern _X_EXPORT void XkbUpdateAllDeviceIndicators(XkbChangesPtr /* changes */, + XkbEventCausePtr /* cause */ + ); + extern _X_EXPORT XkbSrvLedInfoPtr XkbAllocSrvLedInfo(DeviceIntPtr /* dev */ , KbdFeedbackPtr /* kf */ , LedFeedbackPtr /* lf */ , diff --git a/xkb/xkb.c b/xkb/xkb.c index 294cdf8a3..3a6ad651e 100644 --- a/xkb/xkb.c +++ b/xkb/xkb.c @@ -5692,7 +5692,6 @@ ProcXkbListComponents(ClientPtr client) } /***====================================================================***/ - int ProcXkbGetKbdByName(ClientPtr client) { @@ -6017,6 +6016,8 @@ ProcXkbGetKbdByName(ClientPtr client) new = NULL; } XkbFreeComponentNames(&names, FALSE); + XkbUpdateAllDeviceIndicators(NULL, NULL); + return Success; } diff --git a/xkb/xkbLEDs.c b/xkb/xkbLEDs.c index 4e1600207..5792d9fb7 100644 --- a/xkb/xkbLEDs.c +++ b/xkb/xkbLEDs.c @@ -304,7 +304,7 @@ XkbUpdateLedAutoState(DeviceIntPtr dev, return; } -static void +void XkbUpdateAllDeviceIndicators(XkbChangesPtr changes, XkbEventCausePtr cause) { DeviceIntPtr edev;