diff --git a/Xi/exevents.c b/Xi/exevents.c index 106da3a1b..20038a635 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1197,7 +1197,6 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource, TouchOwnershipEvent *ev) { Bool was_owner = (resource == ti->listeners[0].listener); - void *grab; int i; /* Send a TouchEnd event to the resource being removed, but only if they @@ -1212,11 +1211,7 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource, /* Remove the resource from the listener list, updating * ti->num_listeners, as well as ti->num_grabs if it was a grab. */ - if (TouchRemoveListener(ti, resource)) { - if (dixLookupResourceByType(&grab, resource, RT_PASSIVEGRAB, - serverClient, DixGetAttrAccess) == Success) - ti->num_grabs--; - } + TouchRemoveListener(ti, resource); /* If the current owner was removed and there are further listeners, deliver * the TouchOwnership or TouchBegin event to the new owner. */ @@ -1310,34 +1305,19 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti, if (listener->type == LISTENER_GRAB || listener->type == LISTENER_POINTER_GRAB) { - rc = dixLookupResourceByType((pointer *) grab, listener->listener, - RT_PASSIVEGRAB, - serverClient, DixSendAccess); - if (rc != Success) { - /* the grab doesn't exist but we have a grabbing listener - this - * is an implicit/active grab */ - rc = dixLookupClient(client, listener->listener, serverClient, - DixSendAccess); - if (rc != Success) - return FALSE; - *grab = dev->deviceGrab.grab; - if (!*grab) - return FALSE; - } + *grab = listener->grab; + + BUG_RETURN_VAL(!*grab, FALSE); *client = rClient(*grab); *win = (*grab)->window; *mask = (*grab)->xi2mask; } else { - if (listener->level == CORE) - rc = dixLookupWindow(win, listener->listener, - serverClient, DixSendAccess); - else - rc = dixLookupResourceByType((pointer *) win, listener->listener, - RT_INPUTCLIENT, - serverClient, DixSendAccess); + rc = dixLookupResourceByType((pointer *) win, listener->listener, + listener->resource_type, + serverClient, DixSendAccess); if (rc != Success) return FALSE; @@ -1477,6 +1457,8 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, */ l = &ti->listeners[ti->num_listeners - 1]; l->listener = devgrab->resource; + l->grab = devgrab; + //l->resource_type = RT_NONE; if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin) l->type = LISTENER_POINTER_GRAB; @@ -1576,32 +1558,41 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev) else ti = TouchFindByClientID(dev, touchid); - /* Under the following circumstances we create a new touch record for an - * existing touch: - * - * - The touch may be pointer emulated - * - An explicit grab is active on the device - * - The grab is a pointer grab - * - * This allows for an explicit grab to receive pointer events for an already - * active touch. - */ - if (!ti && type != ET_TouchBegin && emulate_pointer && - dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab && + /* Active pointer grab */ + if (emulate_pointer && dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab && (dev->deviceGrab.grab->grabtype == CORE || dev->deviceGrab.grab->grabtype == XI || - !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin))) { - ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid, - emulate_pointer); - if (!ti) { - DebugF("[Xi] %s: Failed to create new dix record for explicitly " - "grabbed touchpoint %d\n", - dev->name, type, touchid); - return; - } + !xi2mask_isset(dev->deviceGrab.grab->xi2mask, dev, XI_TouchBegin))) + { + /* Active pointer grab on touch point and we get a TouchEnd - claim this + * touchpoint accepted, otherwise clients waiting for ownership will + * wait on this touchpoint until this client ungrabs, or the cows come + * home, whichever is earlier */ + if (ti && type == ET_TouchEnd) + TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch); + else if (!ti && type != ET_TouchBegin) { + /* Under the following circumstances we create a new touch record for an + * existing touch: + * + * - The touch may be pointer emulated + * - An explicit grab is active on the device + * - The grab is a pointer grab + * + * This allows for an explicit grab to receive pointer events for an already + * active touch. + */ + ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid, + emulate_pointer); + if (!ti) { + DebugF("[Xi] %s: Failed to create new dix record for explicitly " + "grabbed touchpoint %d\n", + dev->name, touchid); + return; + } - TouchBuildSprite(dev, ti, ev); - TouchSetupListeners(dev, ti, ev); + TouchBuildSprite(dev, ti, ev); + TouchSetupListeners(dev, ti, ev); + } } if (!ti) { diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c index 89f16d8be..4dc3d76e9 100644 --- a/Xi/xichangehierarchy.c +++ b/Xi/xichangehierarchy.c @@ -304,15 +304,16 @@ remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES]) flags[keybd->id] |= XIDeviceDisabled; flags[ptr->id] |= XIDeviceDisabled; - RemoveDevice(XTestptr, FALSE); - RemoveDevice(XTestkeybd, FALSE); - RemoveDevice(keybd, FALSE); - RemoveDevice(ptr, FALSE); flags[XTestptr->id] |= XISlaveRemoved; flags[XTestkeybd->id] |= XISlaveRemoved; flags[keybd->id] |= XIMasterRemoved; flags[ptr->id] |= XIMasterRemoved; + RemoveDevice(XTestptr, FALSE); + RemoveDevice(XTestkeybd, FALSE); + RemoveDevice(keybd, FALSE); + RemoveDevice(ptr, FALSE); + unwind: return rc; } diff --git a/dix/events.c b/dix/events.c index ddb5b343d..904f0ba87 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1435,6 +1435,7 @@ UpdateTouchesForGrab(DeviceIntPtr mouse) ti->listeners[0].type = LISTENER_POINTER_GRAB; else ti->listeners[0].type = LISTENER_GRAB; + ti->listeners[0].grab = grab; } } } @@ -1503,11 +1504,27 @@ DeactivatePointerGrab(DeviceIntPtr mouse) { GrabPtr grab = mouse->deviceGrab.grab; DeviceIntPtr dev; + Bool wasPassive = mouse->deviceGrab.fromPassiveGrab; Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && mouse->deviceGrab.implicitGrab); XID grab_resource = grab->resource; int i; + /* If an explicit grab was deactivated, we must remove it from the head of + * all the touches' listener lists. */ + for (i = 0; !wasPassive && mouse->touch && i < mouse->touch->num_touches; i++) { + TouchPointInfoPtr ti = mouse->touch->touches + i; + if (ti->active && TouchResourceIsOwner(ti, grab_resource)) { + /* Rejecting will generate a TouchEnd, but we must not + emulate a ButtonRelease here. So pretend the listener + already has the end event */ + if (grab->grabtype == CORE || grab->grabtype == XI || + !xi2mask_isset(mouse->deviceGrab.grab->xi2mask, mouse, XI_TouchBegin)) + ti->listeners[0].state = LISTENER_HAS_END; + TouchListenerAcceptReject(mouse, ti, 0, XIRejectTouch); + } + } + TouchRemovePointerGrab(mouse); mouse->valuator->motionHintWindow = NullWindow; @@ -1531,15 +1548,6 @@ DeactivatePointerGrab(DeviceIntPtr mouse) ReattachToOldMaster(mouse); ComputeFreezes(); - - /* If an explicit grab was deactivated, we must remove it from the head of - * all the touches' listener lists. */ - for (i = 0; mouse->touch && i < mouse->touch->num_touches; i++) { - TouchPointInfoPtr ti = mouse->touch->touches + i; - - if (ti->active && TouchResourceIsOwner(ti, grab_resource)) - TouchListenerAcceptReject(mouse, ti, 0, XIRejectTouch); - } } /** @@ -2224,7 +2232,7 @@ DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent * @return TRUE if the event should be discarded, FALSE otherwise. */ static BOOL -FilterRawEvents(const ClientPtr client, const GrabPtr grab) +FilterRawEvents(const ClientPtr client, const GrabPtr grab, WindowPtr root) { XIClientPtr client_xi_version; int cmp; @@ -2240,7 +2248,10 @@ FilterRawEvents(const ClientPtr client, const GrabPtr grab) client_xi_version->minor_version, 2, 0); /* XI 2.0: if device is grabbed, skip XI 2.1: if device is grabbed by us, skip, we've already delivered */ - return (cmp == 0) ? TRUE : SameClient(grab, client); + if (cmp == 0) + return TRUE; + + return (grab->window != root) ? FALSE : SameClient(grab, client); } /** @@ -2293,7 +2304,7 @@ DeliverRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) */ ic.next = NULL; - if (!FilterRawEvents(rClient(&ic), grab)) + if (!FilterRawEvents(rClient(&ic), grab, root)) DeliverEventToInputClients(device, &ic, root, xi, 1, filter, NULL, &c, &m); } @@ -5027,7 +5038,7 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, grab = grabInfo->grab; if (grab && grab->grabtype != grabtype) *status = AlreadyGrabbed; - if (grab && !SameClient(grab, client)) + else if (grab && !SameClient(grab, client)) *status = AlreadyGrabbed; else if ((!pWin->realized) || (confineTo && diff --git a/dix/getevents.c b/dix/getevents.c index 8b4379d1c..241fcfd69 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -1951,32 +1951,27 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid, default: return 0; } - if (t->mode == XIDirectTouch && !(flags & TOUCH_CLIENT_ID)) { - if (!valuator_mask_isset(&mask, 0)) - valuator_mask_set_double(&mask, 0, - valuator_mask_get_double(touchpoint.ti-> - valuators, 0)); - if (!valuator_mask_isset(&mask, 1)) - valuator_mask_set_double(&mask, 1, - valuator_mask_get_double(touchpoint.ti-> - valuators, 1)); - } /* Get our screen event co-ordinates (root_x/root_y/event_x/event_y): * these come from the touchpoint in Absolute mode, or the sprite in * Relative. */ if (t->mode == XIDirectTouch) { - transformAbsolute(dev, &mask); - if (!(flags & TOUCH_CLIENT_ID)) { - for (i = 0; i < valuator_mask_size(&mask); i++) { - double val; + for (i = 0; i < max(valuator_mask_size(&mask), 2); i++) { + double val; - if (valuator_mask_fetch_double(&mask, i, &val)) - valuator_mask_set_double(touchpoint.ti->valuators, i, val); - } + if (valuator_mask_fetch_double(&mask, i, &val)) + valuator_mask_set_double(touchpoint.ti->valuators, i, val); + /* If the device doesn't post new X and Y axis values, + * use the last values posted. + */ + else if (i < 2 && + valuator_mask_fetch_double(touchpoint.ti->valuators, i, &val)) + valuator_mask_set_double(&mask, i, val); + } } + transformAbsolute(dev, &mask); clipAbsolute(dev, &mask); } else { diff --git a/dix/grabs.c b/dix/grabs.c index 55bf64f2c..d55a69cf0 100644 --- a/dix/grabs.c +++ b/dix/grabs.c @@ -219,7 +219,10 @@ CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice, grab->resource = FakeClientID(client); grab->device = device; grab->window = window; - grab->eventMask = mask->core; /* same for XI */ + if (grabtype == CORE || grabtype == XI) + grab->eventMask = mask->core; /* same for XI */ + else + grab->eventMask = 0; grab->deviceMask = 0; grab->ownerEvents = param->ownerEvents; grab->keyboardMode = param->this_device_mode; diff --git a/dix/touch.c b/dix/touch.c index 5f77be575..2b30b7df0 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -682,15 +682,20 @@ TouchResourceIsOwner(TouchPointInfoPtr ti, XID resource) * Add the resource to this touch's listeners. */ void -TouchAddListener(TouchPointInfoPtr ti, XID resource, enum InputLevel level, - enum TouchListenerType type, enum TouchListenerState state, - WindowPtr window) +TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type, + enum InputLevel level, enum TouchListenerType type, + enum TouchListenerState state, WindowPtr window, + GrabPtr grab) { ti->listeners[ti->num_listeners].listener = resource; + ti->listeners[ti->num_listeners].resource_type = resource_type; ti->listeners[ti->num_listeners].level = level; ti->listeners[ti->num_listeners].state = state; ti->listeners[ti->num_listeners].type = type; ti->listeners[ti->num_listeners].window = window; + ti->listeners[ti->num_listeners].grab = grab; + if (grab) + ti->num_grabs++; ti->num_listeners++; } @@ -709,6 +714,11 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource) if (ti->listeners[i].listener == resource) { int j; + if (ti->listeners[i].grab) { + ti->listeners[i].grab = NULL; + ti->num_grabs--; + } + for (j = i; j < ti->num_listeners - 1; j++) ti->listeners[j] = ti->listeners[j + 1]; ti->num_listeners--; @@ -739,9 +749,9 @@ TouchAddGrabListener(DeviceIntPtr dev, TouchPointInfoPtr ti, type = LISTENER_POINTER_GRAB; } - TouchAddListener(ti, grab->resource, grab->grabtype, - type, LISTENER_AWAITING_BEGIN, grab->window); - ti->num_grabs++; + /* grab listeners are always RT_NONE since we keep the grab pointer */ + TouchAddListener(ti, grab->resource, RT_NONE, grab->grabtype, + type, LISTENER_AWAITING_BEGIN, grab->window, grab); } /** @@ -796,8 +806,8 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti, if (!xi2mask_isset(iclients->xi2mask, dev, XI_TouchOwnership)) TouchEventHistoryAllocate(ti); - TouchAddListener(ti, iclients->resource, XI2, - type, LISTENER_AWAITING_BEGIN, win); + TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI2, + type, LISTENER_AWAITING_BEGIN, win, NULL); return TRUE; } } @@ -811,9 +821,9 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti, continue; TouchEventHistoryAllocate(ti); - TouchAddListener(ti, iclients->resource, XI, + TouchAddListener(ti, iclients->resource, RT_INPUTCLIENT, XI, LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN, - win); + win, NULL); return TRUE; } } @@ -826,9 +836,9 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti, /* window owner */ if (IsMaster(dev) && (win->eventMask & core_filter)) { TouchEventHistoryAllocate(ti); - TouchAddListener(ti, win->drawable.id, CORE, + TouchAddListener(ti, win->drawable.id, RT_WINDOW, CORE, LISTENER_POINTER_REGULAR, LISTENER_AWAITING_BEGIN, - win); + win, NULL); return TRUE; } @@ -838,8 +848,8 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti, continue; TouchEventHistoryAllocate(ti); - TouchAddListener(ti, oclients->resource, CORE, - type, LISTENER_AWAITING_BEGIN, win); + TouchAddListener(ti, oclients->resource, RT_OTHERCLIENT, CORE, + type, LISTENER_AWAITING_BEGIN, win, NULL); return TRUE; } } @@ -994,8 +1004,6 @@ TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener, for (i = 0; i < nev; i++) mieqProcessDeviceEvent(dev, events + i, NULL); - ProcessInputEvents(); - FreeEventList(events, GetMaximumEventsNum()); return nev ? Success : BadMatch; diff --git a/hw/xfree86/common/xf86DGA.c b/hw/xfree86/common/xf86DGA.c index a441dee99..7f1a0c6ff 100644 --- a/hw/xfree86/common/xf86DGA.c +++ b/hw/xfree86/common/xf86DGA.c @@ -1033,6 +1033,9 @@ DGAProcessKeyboardEvent(ScreenPtr pScreen, DGAEvent * event, DeviceIntPtr keybd) UpdateDeviceState(keybd, &ev); + if (!IsMaster(keybd)) + return; + /* * Deliver the DGA event */ @@ -1074,6 +1077,7 @@ DGAProcessPointerEvent(ScreenPtr pScreen, DGAEvent * event, DeviceIntPtr mouse) DeviceEvent ev = { .header = ET_Internal, .length = sizeof(ev), + .detail.key = event->detail, .type = event->subtype, .corestate = butc ? butc->state : 0 }; @@ -1083,6 +1087,9 @@ DGAProcessPointerEvent(ScreenPtr pScreen, DGAEvent * event, DeviceIntPtr mouse) UpdateDeviceState(mouse, &ev); + if (!IsMaster(mouse)) + return; + /* * Deliver the DGA event */ @@ -1190,9 +1197,6 @@ DGAHandleEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) if (!pScreenPriv) return; - if (!IsMaster(device)) - return; - switch (event->subtype) { case KeyPress: case KeyRelease: diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index 3ad34b543..7e80fa922 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -180,6 +180,7 @@ xf86ProcessActionEvent(ActionEvent action, void *arg) switch (action) { case ACTION_TERMINATE: if (!xf86Info.dontZap) { + xf86Msg(X_INFO, "Server zapped. Shutting down.\n"); #ifdef XFreeXDGA DGAShutdown(); #endif @@ -618,14 +619,16 @@ InputHandlerProc xf86SetConsoleHandler(InputHandlerProc proc, pointer data) { static IHPtr handler = NULL; - IHPtr old_handler = handler; + InputHandlerProc old_proc = NULL; - if (old_handler) - xf86RemoveGeneralHandler(old_handler); + if (handler) { + old_proc = handler->ihproc; + xf86RemoveGeneralHandler(handler); + } handler = xf86AddGeneralHandler(xf86Info.consoleFd, proc, data); - return (old_handler) ? old_handler->ihproc : NULL; + return old_proc; } static void diff --git a/include/input.h b/include/input.h index f8459b8c8..f0196f514 100644 --- a/include/input.h +++ b/include/input.h @@ -560,9 +560,9 @@ extern void TouchEventHistoryPush(TouchPointInfoPtr ti, const DeviceEvent *ev); extern void TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource); extern Bool TouchResourceIsOwner(TouchPointInfoPtr ti, XID resource); -extern void TouchAddListener(TouchPointInfoPtr ti, XID resource, +extern void TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type, enum InputLevel level, enum TouchListenerType type, - enum TouchListenerState state, WindowPtr window); + enum TouchListenerState state, WindowPtr window, GrabPtr grab); extern Bool TouchRemoveListener(TouchPointInfoPtr ti, XID resource); extern void TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev); diff --git a/include/inputstr.h b/include/inputstr.h index 5a38924de..98342432b 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -298,6 +298,17 @@ typedef struct _ValuatorClassRec { int v_scroll_axis; /* vert smooth-scrolling axis */ } ValuatorClassRec; +typedef struct _TouchListener { + XID listener; /* grabs/event selection IDs receiving + * events for this touch */ + int resource_type; /* listener's resource type */ + enum TouchListenerType type; + enum TouchListenerState state; + enum InputLevel level; /* matters only for emulating touches */ + WindowPtr window; + GrabPtr grab; +} TouchListener; + typedef struct _TouchPointInfo { uint32_t client_id; /* touch ID as seen in client events */ int sourceid; /* Source device's ID for this touchpoint */ @@ -306,14 +317,7 @@ typedef struct _TouchPointInfo { * but still owned by a grab */ SpriteRec sprite; /* window trace for delivery */ ValuatorMask *valuators; /* last recorded axis values */ - struct _TouchListener { - XID listener; /* grabs/event selection IDs receiving - * events for this touch */ - enum TouchListenerType type; - enum TouchListenerState state; - enum InputLevel level; /* matters only for emulating touches */ - WindowPtr window; - } *listeners; + TouchListener *listeners; /* set of listeners */ int num_listeners; int num_grabs; /* number of open grabs on this touch * which have not accepted or rejected */ @@ -323,15 +327,13 @@ typedef struct _TouchPointInfo { size_t history_size; /* Size of history in elements */ } TouchPointInfoRec; -typedef struct _TouchListener TouchListener; - typedef struct _DDXTouchPointInfo { uint32_t client_id; /* touch ID as seen in client events */ Bool active; /* whether or not the touch is active */ uint32_t ddx_id; /* touch ID given by the DDX */ Bool emulate_pointer; - ValuatorMask *valuators; /* last recorded axis values */ + ValuatorMask *valuators; /* last axis values as posted, pre-transform */ } DDXTouchPointInfoRec; typedef struct _TouchClassRec { diff --git a/mi/mieq.c b/mi/mieq.c index b2c7769ec..67d392894 100644 --- a/mi/mieq.c +++ b/mi/mieq.c @@ -623,7 +623,11 @@ mieqProcessInputEvents(void) mieqProcessDeviceEvent(dev, &event, screen); /* Update the sprite now. Next event may be from different device. */ - if (event.any.type == ET_Motion && master) + if (master && + (event.any.type == ET_Motion || + ((event.any.type == ET_TouchBegin || + event.any.type == ET_TouchUpdate) && + event.device_event.flags & TOUCH_POINTER_EMULATED))) miPointerUpdateSprite(dev); #ifdef XQUARTZ diff --git a/render/animcur.c b/render/animcur.c index ebc5b8ef7..9cbba83fa 100644 --- a/render/animcur.c +++ b/render/animcur.c @@ -143,6 +143,8 @@ AnimCurScreenBlockHandler(ScreenPtr pScreen, Bool activeDevice = FALSE; CARD32 now = 0, soonest = ~0; /* earliest time to wakeup again */ + Unwrap(as, pScreen, BlockHandler); + for (dev = inputInfo.devices; dev; dev = dev->next) { if (IsPointerDevice(dev) && pScreen == dev->spriteInfo->anim.pScreen) { if (!activeDevice) { @@ -180,7 +182,6 @@ AnimCurScreenBlockHandler(ScreenPtr pScreen, if (activeDevice) AdjustWaitForDelay(pTimeout, soonest - now); - Unwrap(as, pScreen, BlockHandler); (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask); if (activeDevice) Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); diff --git a/xkb/xkbUtils.c b/xkb/xkbUtils.c index c23cd7784..6c6af60f0 100644 --- a/xkb/xkbUtils.c +++ b/xkb/xkbUtils.c @@ -642,6 +642,7 @@ XkbComputeCompatState(XkbSrvInfoPtr xkbi) CARD16 grp_mask; XkbStatePtr state = &xkbi->state; XkbCompatMapPtr map; + XkbControlsPtr ctrls; if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat) return; @@ -650,9 +651,14 @@ XkbComputeCompatState(XkbSrvInfoPtr xkbi) grp_mask = map->groups[state->group].mask; state->compat_state = state->mods | grp_mask; state->compat_lookup_mods = state->lookup_mods | grp_mask; + ctrls= xkbi->desc->ctrls; - if (xkbi->desc->ctrls->enabled_ctrls & XkbIgnoreGroupLockMask) - grp_mask = map->groups[state->base_group].mask; + if (ctrls->enabled_ctrls & XkbIgnoreGroupLockMask) { + unsigned char grp = state->base_group+state->latched_group; + if (grp >= ctrls->num_groups) + grp = XkbAdjustGroup(XkbCharToInt(grp), ctrls); + grp_mask = map->groups[grp].mask; + } state->compat_grab_mods = state->grab_mods | grp_mask; return; }