From 72cfc1a097dc1e09d2cd9415ef7855a2cef92351 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 11 Apr 2012 09:43:23 +1000 Subject: Xi: fix XITouchClass sourceid assignment Signed-off-by: Peter Hutterer Reviewed-by: Chase Douglas --- Xi/xiquerydevice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xi/xiquerydevice.c b/Xi/xiquerydevice.c index 749bc24c9..15c8b2a7b 100644 --- a/Xi/xiquerydevice.c +++ b/Xi/xiquerydevice.c @@ -430,7 +430,7 @@ ListTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch) { touch->type = XITouchClass; touch->length = sizeof(xXITouchInfo) >> 2; - touch->sourceid = touch->sourceid; + touch->sourceid = dev->touch->sourceid; touch->mode = dev->touch->mode; touch->num_touches = dev->touch->num_touches; -- cgit v1.2.3 From c5a45b0f7658c77725adce2b64a0fbd62f208328 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Thu, 12 Apr 2012 10:11:10 +1000 Subject: dix: don't BUG_WARN for button events from button-only device Events from button-only devices still need coordinates, and they get them from scale_to_desktop(). Therefore, a dev without valuators is not a bug. However, a dev with valuators, but less than two of them still is a bug. This was noticed when unplugging a "Creative Technology SB Arena Headset", which has some BTNs and some KEYs, but no REL or ABS valuators. It emits [BTN_3] = 0 on unplug, which would trigger the BUG_WARN. Signed-off-by: Daniel Kurtz Reviewed-by: Chase Douglas Signed-off-by: Peter Hutterer --- dix/getevents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dix/getevents.c b/dix/getevents.c index 3093786c3..23bbe065c 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -848,7 +848,7 @@ scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask, ScreenPtr scr = miPointerGetScreen(dev); double x, y; - BUG_WARN(!dev->valuator || dev->valuator->numAxes < 2); + BUG_WARN(dev->valuator && dev->valuator->numAxes < 2); if (!dev->valuator || dev->valuator->numAxes < 2) { /* if we have no axes, last.valuators must be in screen coords * anyway */ -- cgit v1.2.3 From 82a1ae0af3b136371638659c3e909880a99f721c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 12 Apr 2012 15:54:00 +1000 Subject: xfree86: after VT switching back, only enable previously enabled devices If a device was enabled before the VT switch, re-enabled it. Otherwise leave it as is, there was probably a reason why it was disabled. Signed-off-by: Peter Hutterer Reviewed-by: Chase Douglas Reviewed-by: Daniel Stone --- hw/xfree86/common/xf86Events.c | 8 ++++++-- hw/xfree86/common/xf86Xinput.h | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index 058057e92..5896f220c 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -449,6 +449,8 @@ xf86VTSwitch(void) xf86DisableInputHandler(ih); for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) { if (pInfo->dev) { + if (!pInfo->dev->enabled) + pInfo->flags |= XI86_DEVICE_DISABLED; xf86ReleaseKeys(pInfo->dev); ProcessInputEvents(); DisableDevice(pInfo->dev, TRUE); @@ -482,8 +484,9 @@ xf86VTSwitch(void) pInfo = xf86InputDevs; while (pInfo) { - if (pInfo->dev) + if (pInfo->dev && (pInfo->flags & XI86_DEVICE_DISABLED) == 0) EnableDevice(pInfo->dev, TRUE); + pInfo->flags &= ~XI86_DEVICE_DISABLED; pInfo = pInfo->next; } for (ih = InputHandlers; ih; ih = ih->next) @@ -537,8 +540,9 @@ xf86VTSwitch(void) pInfo = xf86InputDevs; while (pInfo) { - if (pInfo->dev) + if (pInfo->dev && (pInfo->flags & XI86_DEVICE_DISABLED) == 0) EnableDevice(pInfo->dev, TRUE); + pInfo->flags &= ~XI86_DEVICE_DISABLED; pInfo = pInfo->next; } diff --git a/hw/xfree86/common/xf86Xinput.h b/hw/xfree86/common/xf86Xinput.h index 3731a34d5..1d4363a50 100644 --- a/hw/xfree86/common/xf86Xinput.h +++ b/hw/xfree86/common/xf86Xinput.h @@ -61,6 +61,9 @@ #define XI86_ALWAYS_CORE 0x04 /* device always controls the pointer */ /* the device sends Xinput and core pointer events */ #define XI86_SEND_CORE_EVENTS XI86_ALWAYS_CORE +/* 0x08 is reserved for legacy XI86_SEND_DRAG_EVENTS, do not use for now */ +/* server-internal only */ +#define XI86_DEVICE_DISABLED 0x10 /* device was disabled before vt switch */ /* This holds the input driver entry and module information. */ typedef struct _InputDriverRec { -- cgit v1.2.3 From 210cd12c47d063f97915ff23292b61d09abfd73a Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Tue, 10 Apr 2012 17:12:40 -0700 Subject: Don't update listener after deactivating implicit pointer grab After the pointer grab is deactivated, the touch listener record is updated at the end of DeliverTouchEmulatedEvent. However, the touch record is ended when the grab is deactivated, so the update to the listener record is in an array of memory that has been freed. Signed-off-by: Chase Douglas Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- Xi/exevents.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index ff2224094..31171239f 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1389,8 +1389,10 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, if (ev->any.type == ET_TouchEnd && !dev->button->buttonsDown && - dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) + dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) { (*dev->deviceGrab.DeactivateGrab) (dev); + return Success; + } } } else { -- cgit v1.2.3 From 163b0f375d73c05873fb341652de3ed347337828 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Tue, 10 Apr 2012 17:12:41 -0700 Subject: Update event type when delivering end event to a pointer listener Just like when we deliver to a touch listener, we must convert a touch end event to an update event for further clients. This also ensures that the touch record is not deleted at the end of ProcessTouchEvent(). Signed-off-by: Chase Douglas Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- Xi/exevents.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Xi/exevents.c b/Xi/exevents.c index 31171239f..a843e0300 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1757,6 +1757,13 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev, listener->type == LISTENER_POINTER_GRAB) { rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab, xi2mask); + + if (ti->num_listeners > 1) { + ev->any.type = ET_TouchUpdate; + ev->device_event.flags |= TOUCH_PENDING_END; + ti->pending_finish = TRUE; + } + goto out; } -- cgit v1.2.3 From 32ece7c09bf0ebc3d99b4078aacebbd44314776a Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Tue, 10 Apr 2012 17:12:42 -0700 Subject: Ensure sequential touches are pointer emulated sequentially Issue: * Two sequential touches (i.e. down, up, down, up) * Both are grabbed by a touch grab * Both have a second listener in the form of a pointer grab or selection * The second and first touches are rejected in that order The first touch must be pointer emulated before the second touch, so the second touch must be paused until the first touch is rejected or accepted and all events are delivered to pointer clients. This change ensures all pointer emulated events are emitted sequentially. It necessarily imposes a delay on further touch events when pointer grabs and selections are used, but there is no way around it. Signed-off-by: Chase Douglas Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- Xi/exevents.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index a843e0300..c05c22604 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1110,6 +1110,48 @@ EmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource) FreeEventList(tel, GetMaximumEventsNum()); } +/** + * Find the oldest touch that still has a pointer emulation client. + * + * Pointer emulation can only be performed for the oldest touch. Otherwise, the + * order of events seen by the client will be wrong. This function helps us find + * the next touch to be emulated. + * + * @param dev The device to find touches for. + */ +static TouchPointInfoPtr +FindOldestPointerEmulatedTouch(DeviceIntPtr dev) +{ + TouchPointInfoPtr oldest = NULL; + int i; + + for (i = 0; i < dev->touch->num_touches; i++) { + TouchPointInfoPtr ti = dev->touch->touches + i; + int j; + + if (!ti->active || !ti->emulate_pointer) + continue; + + for (j = 0; j < ti->num_listeners; j++) { + if (ti->listeners[j].type == LISTENER_POINTER_GRAB || + ti->listeners[j].type == LISTENER_POINTER_REGULAR) + break; + } + if (j == ti->num_listeners) + continue; + + if (!oldest) { + oldest = ti; + continue; + } + + if (oldest->client_id - ti->client_id < UINT_MAX / 2) + oldest = ti; + } + + return oldest; +} + /** * If the current owner has rejected the event, deliver the * TouchOwnership/TouchBegin to the next item in the sprite stack. @@ -1123,8 +1165,16 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, ti->listeners[0].state == LISTENER_EARLY_ACCEPT) DeliverTouchEvents(dev, ti, (InternalEvent *) ev, ti->listeners[0].listener); - else if (ti->listeners[0].state == LISTENER_AWAITING_BEGIN) + else if (ti->listeners[0].state == LISTENER_AWAITING_BEGIN) { + /* We can't punt to a pointer listener unless all older pointer + * emulated touches have been seen already. */ + if ((ti->listeners[0].type == LISTENER_POINTER_GRAB || + ti->listeners[0].type == LISTENER_POINTER_REGULAR) && + ti != FindOldestPointerEmulatedTouch(dev)) + return; + TouchEventHistoryReplay(ti, dev, ti->listeners[0].listener); + } /* If we've just removed the last grab and the touch has physically * ended, send a TouchEnd event too and finalise the touch. */ @@ -1138,6 +1188,25 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, ActivateEarlyAccept(dev, ti); } +/** + * Check the oldest touch to see if it needs to be replayed to its pointer + * owner. + * + * Touch event propagation is paused if it hits a pointer listener while an + * older touch with a pointer listener is waiting on accept or reject. This + * function will restart propagation of a paused touch if needed. + * + * @param dev The device to check touches for. + */ +static void +CheckOldestTouch(DeviceIntPtr dev) +{ + TouchPointInfoPtr oldest = FindOldestPointerEmulatedTouch(dev); + + if (oldest && oldest->listeners[0].state == LISTENER_AWAITING_BEGIN) + TouchPuntToNextOwner(dev, oldest, NULL); +} + /** * Process a touch rejection. * @@ -1169,6 +1238,7 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource, * finish, then we can just kill it now. */ if (ti->num_listeners == 1 && ti->pending_finish) { TouchEndTouch(sourcedev, ti); + CheckOldestTouch(sourcedev); return; } @@ -1184,6 +1254,8 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource, * the TouchOwnership or TouchBegin event to the new owner. */ if (ev && ti->num_listeners > 0 && was_owner) TouchPuntToNextOwner(sourcedev, ti, ev); + + CheckOldestTouch(sourcedev); } /** @@ -1391,6 +1463,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, !dev->button->buttonsDown && dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) { (*dev->deviceGrab.DeactivateGrab) (dev); + CheckOldestTouch(dev); return Success; } } -- cgit v1.2.3 From 12188c8a8a537b38b1ca4cf8c0de5447e19c886a Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Tue, 3 Apr 2012 17:31:01 -0700 Subject: Use touch state when querying pointer through core protocol QueryPointer is part of the core protocol. As such, it knows nothing about touch devices. Touches are converted to button 1 press, pointer motion, and button 1 release for core clients, so we should ensure the pointer state mask has button 1 set when XQueryPointer is used. Signed-off-by: Chase Douglas Signed-off-by: Peter Hutterer --- dix/events.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dix/events.c b/dix/events.c index 447094757..b9f9cfa3c 100644 --- a/dix/events.c +++ b/dix/events.c @@ -5098,8 +5098,7 @@ ProcQueryPointer(ClientPtr client) memset(&rep, 0, sizeof(xQueryPointerReply)); rep.type = X_Reply; rep.sequenceNumber = client->sequence; - rep.mask = mouse->button ? (mouse->button->state) : 0; - rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); + rep.mask = event_get_corestate(mouse, keyboard); rep.length = 0; rep.root = (GetCurrentRootWindow(mouse))->drawable.id; rep.rootX = pSprite->hot.x; -- cgit v1.2.3