Merge remote-tracking branch 'whot/for-keith'

Touch input changes from Chase
This commit is contained in:
Keith Packard 2012-04-19 10:45:07 -05:00
commit e6308e32fe
5 changed files with 191 additions and 88 deletions

View File

@ -1234,14 +1234,6 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource,
}
}
/* If there are no other listeners left, and the touchpoint is pending
* finish, then we can just kill it now. */
if (ti->num_listeners == 1 && ti->pending_finish) {
TouchEndTouch(sourcedev, ti);
CheckOldestTouch(sourcedev);
return;
}
/* 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)) {
@ -1254,6 +1246,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);
else if (ti->num_listeners == 0)
TouchEndTouch(sourcedev, ti);
CheckOldestTouch(sourcedev);
}
@ -1273,9 +1267,18 @@ ProcessTouchOwnershipEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
if (ev->reason == XIRejectTouch)
TouchRejected(dev, ti, ev->resource, ev);
else if (ev->reason == XIAcceptTouch) {
int i;
/* Go through the motions of ending the touch if the listener has
* already seen the end. This ensures that the touch record is ended in
* the server. */
if (ti->listeners[0].state == LISTENER_HAS_END)
EmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener);
/* The touch owner has accepted the touch. Send TouchEnd events to
* everyone else, and truncate the list of listeners. */
EmitTouchEnd(dev, ti, TOUCH_ACCEPT, 0);
for (i = 1; i < ti->num_listeners; i++)
EmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener);
while (ti->num_listeners > 1)
TouchRemoveListener(ti, ti->listeners[1].listener);
@ -1327,6 +1330,7 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
{
int rc;
InputClients *iclients = NULL;
*mask = NULL;
if (listener->type == LISTENER_GRAB ||
listener->type == LISTENER_POINTER_GRAB) {
@ -1377,6 +1381,9 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
BUG_WARN(!iclients);
if (!iclients)
return FALSE;
*mask = iclients->xi2mask;
*client = rClient(iclients);
}
else if (listener->level == XI) {
int xi_type = GetXIType(TouchGetPointerEventType(ev));
@ -1389,21 +1396,24 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
BUG_WARN(!iclients);
if (!iclients)
return FALSE;
*client = rClient(iclients);
}
else {
int coretype = GetCoreType(TouchGetPointerEventType(ev));
Mask core_filter = event_get_filter_from_type(dev, coretype);
OtherClients *oclients;
/* all others */
nt_list_for_each_entry(iclients,
(InputClients *) wOtherClients(*win), next)
if (iclients->mask[XIAllDevices] & core_filter)
break;
/* if owner selected, iclients is NULL */
nt_list_for_each_entry(oclients,
(OtherClients *) wOtherClients(*win), next)
if (oclients->mask & core_filter)
break;
/* if owner selected, oclients is NULL */
*client = oclients ? rClient(oclients) : wClient(*win);
}
*client = iclients ? rClient(iclients) : wClient(*win);
*mask = iclients ? iclients->xi2mask : NULL;
*grab = NULL;
}
@ -1459,7 +1469,14 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
if (!deliveries)
DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype);
/* We must accept the touch sequence once a pointer listener has
* received one event past ButtonPress. */
if (deliveries && ev->any.type != ET_TouchBegin &&
!(ev->device_event.flags & TOUCH_CLIENT_ID))
TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch);
if (ev->any.type == ET_TouchEnd &&
!(ev->device_event.flags & TOUCH_CLIENT_ID) &&
!dev->button->buttonsDown &&
dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) {
(*dev->deviceGrab.DeactivateGrab) (dev);
@ -1580,6 +1597,9 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
else
touchid = ev->device_event.touchid;
if (emulate_pointer)
UpdateDeviceState(dev, &ev->device_event);
if (type == ET_TouchBegin) {
ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid,
emulate_pointer);
@ -1587,6 +1607,34 @@ 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 &&
(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;
}
TouchBuildSprite(dev, ti, ev);
TouchSetupListeners(dev, ti, ev);
}
if (!ti) {
DebugF("[Xi] %s: Failed to get event %d for touchpoint %d\n",
dev->name, type, touchid);
@ -1602,9 +1650,11 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev)
CheckMotion(&ev->device_event, dev);
/* Make sure we have a valid window trace for event delivery; must be
* called after event type mutation. */
* called after event type mutation. Touch end events are always processed
* in order to end touch records. */
/* FIXME: check this */
if (!TouchEnsureSprite(dev, ti, ev))
if ((type == ET_TouchBegin && !TouchBuildSprite(dev, ti, ev)) ||
(type != ET_TouchEnd && ti->sprite.spriteTraceGood == 0))
return;
/* TouchOwnership events are handled separately from the rest, as they
@ -1834,7 +1884,8 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev,
if (ti->num_listeners > 1) {
ev->any.type = ET_TouchUpdate;
ev->device_event.flags |= TOUCH_PENDING_END;
ti->pending_finish = TRUE;
if (!(ev->device_event.flags & TOUCH_CLIENT_ID))
ti->pending_finish = TRUE;
}
goto out;
@ -1948,9 +1999,6 @@ DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
DeliverTouchEvent(dev, ti, ev, listener, client, win, grab, mask);
}
if (ti->emulate_pointer)
UpdateDeviceState(dev, &ev->device_event);
}
int

View File

@ -214,7 +214,7 @@ UpdateCurrentTimeIf(void)
systime.milliseconds = GetTimeInMillis();
if (systime.milliseconds < currentTime.milliseconds)
systime.months++;
if (*checkForInput[0] == *checkForInput[1])
if (CompareTimeStamps(systime, currentTime) == LATER)
currentTime = systime;
}
@ -393,6 +393,9 @@ Dispatch(void)
}
/* now, finally, deal with client requests */
/* Update currentTime so request time checks, such as for input
* device grabs, are calculated correctly */
UpdateCurrentTimeIf();
result = ReadRequestFromClient(client);
if (result <= 0) {
if (result < 0)
@ -413,8 +416,8 @@ Dispatch(void)
if (XSERVER_REQUEST_START_ENABLED())
XSERVER_REQUEST_START(LookupMajorName(client->majorOp),
client->majorOp,
((xReq *) client->requestBuffer)->
length, client->index,
((xReq *) client->requestBuffer)->length,
client->index,
client->requestBuffer);
#endif
if (result > (maxBigRequestSize << 2))

View File

@ -1273,18 +1273,11 @@ ComputeFreezes(void)
event->root_x, event->root_y);
if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) {
if (IsTouchEvent((InternalEvent *) event)) {
InternalEvent *events = InitEventList(GetMaximumEventsNum());
int i, nev;
TouchPointInfoPtr ti =
TouchFindByClientID(replayDev, event->touchid);
BUG_WARN(!ti);
nev =
GetTouchOwnershipEvents(events, replayDev, ti,
XIRejectTouch,
ti->listeners[0].listener, 0);
for (i = 0; i < nev; i++)
mieqProcessDeviceEvent(replayDev, events + i, NULL);
ProcessInputEvents();
TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
}
else if (replayDev->focus &&
!IsPointerEvent((InternalEvent *) event))
@ -1415,6 +1408,38 @@ ReattachToOldMaster(DeviceIntPtr dev)
}
}
/**
* Update touch records when an explicit grab is activated. Any touches owned by
* the grabbing client are updated so the listener state reflects the new grab.
*/
static void
UpdateTouchesForGrab(DeviceIntPtr mouse)
{
int i;
if (!mouse->touch || mouse->deviceGrab.fromPassiveGrab)
return;
for (i = 0; i < mouse->touch->num_touches; i++) {
TouchPointInfoPtr ti = mouse->touch->touches + i;
GrabPtr grab = mouse->deviceGrab.grab;
if (ti->active &&
CLIENT_BITS(ti->listeners[0].listener) == grab->resource) {
ti->listeners[0].listener = grab->resource;
ti->listeners[0].level = grab->grabtype;
ti->listeners[0].state = LISTENER_IS_OWNER;
ti->listeners[0].window = grab->window;
if (grab->grabtype == CORE || grab->grabtype == XI ||
!xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
ti->listeners[0].type = LISTENER_POINTER_GRAB;
else
ti->listeners[0].type = LISTENER_GRAB;
}
}
}
/**
* Activate a pointer grab on the given device. A pointer grab will cause all
* core pointer events of this device to be delivered to the grabbing client only.
@ -1464,6 +1489,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
grabinfo->fromPassiveGrab = isPassive;
grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
PostNewCursor(mouse);
UpdateTouchesForGrab(mouse);
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
(Bool) grab->keyboardMode);
}
@ -1480,6 +1506,8 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
DeviceIntPtr dev;
Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
mouse->deviceGrab.implicitGrab);
XID grab_resource = grab->resource;
int i;
TouchRemovePointerGrab(mouse);
@ -1504,6 +1532,15 @@ 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);
}
}
/**

View File

@ -364,14 +364,6 @@ TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti)
{
if (ti->emulate_pointer) {
GrabPtr grab;
DeviceEvent ev;
memset(&ev, 0, sizeof(ev));
ev.type = ET_TouchEnd;
ev.detail.button = 1;
ev.touchid = ti->client_id;
ev.flags = TOUCH_POINTER_EMULATED | TOUCH_END;
UpdateDeviceState(dev, &ev);
if ((grab = dev->deviceGrab.grab)) {
if (dev->deviceGrab.fromPassiveGrab &&
@ -482,10 +474,22 @@ TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource)
flags = TOUCH_CLIENT_ID | TOUCH_REPLAYING;
if (ti->emulate_pointer)
flags |= TOUCH_POINTER_EMULATED;
/* send fake begin event to next owner */
/* Generate events based on a fake touch begin event to get DCCE events if
* needed */
/* FIXME: This needs to be cleaned up */
nev = GetTouchEvents(tel, dev, ti->client_id, XI_TouchBegin, flags, mask);
for (i = 0; i < nev; i++)
DeliverTouchEvents(dev, ti, tel + i, resource);
for (i = 0; i < nev; i++) {
/* Send saved touch begin event */
if (tel[i].any.type == ET_TouchBegin) {
DeviceEvent *ev = &ti->history[0];
ev->flags |= TOUCH_REPLAYING;
DeliverTouchEvents(dev, ti, (InternalEvent*)ev, resource);
}
else {/* Send DCCE event */
tel[i].any.time = ti->history[0].time;
DeliverTouchEvents(dev, ti, tel + i, resource);
}
}
valuator_mask_free(&mask);
FreeEventList(tel, GetMaximumEventsNum());
@ -542,22 +546,12 @@ TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite)
* TouchBegin events.
*/
Bool
TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
InternalEvent *ev)
TouchBuildSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
InternalEvent *ev)
{
TouchClassPtr t = sourcedev->touch;
SpritePtr sprite = &ti->sprite;
/* We may not have a sprite if there are no applicable grabs or
* event selections, or if they've disappeared, or if all the grab
* owners have rejected the touch. Don't bother delivering motion
* events if not, but TouchEnd events still need to be processed so
* we can call FinishTouchPoint and release it for later use. */
if (ev->any.type == ET_TouchEnd)
return TRUE;
else if (ev->any.type != ET_TouchBegin)
return (sprite->spriteTraceGood > 0);
if (t->mode == XIDirectTouch) {
/* Focus immediately under the touchpoint in direct touch mode.
* XXX: Do we need to handle crossing screens here? */
@ -821,6 +815,7 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
if (mask & EVENT_CORE_MASK) {
int coretype = GetCoreType(TouchGetPointerEventType(ev));
Mask core_filter = event_get_filter_from_type(dev, coretype);
OtherClients *oclients;
/* window owner */
if (IsMaster(dev) && (win->eventMask & core_filter)) {
@ -832,13 +827,12 @@ TouchAddRegularListener(DeviceIntPtr dev, TouchPointInfoPtr ti,
}
/* all others */
nt_list_for_each_entry(iclients, (InputClients *) wOtherClients(win),
next) {
if (!(iclients->mask[XIAllDevices] & core_filter))
nt_list_for_each_entry(oclients, wOtherClients(win), next) {
if (!(oclients->mask & core_filter))
continue;
TouchEventHistoryAllocate(ti);
TouchAddListener(ti, iclients->resource, CORE,
TouchAddListener(ti, oclients->resource, CORE,
type, LISTENER_AWAITING_BEGIN, win);
return TRUE;
}
@ -874,6 +868,11 @@ TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
if (dev->deviceGrab.grab)
TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab);
/* We set up an active touch listener for existing touches, but not any
* passive grab or regular listeners. */
if (ev->any.type != ET_TouchBegin)
return;
/* First, find all grabbing clients from the root window down
* to the deepest child window. */
for (i = 0; i < sprite->spriteTraceGood; i++) {
@ -959,16 +958,49 @@ TouchListenerGone(XID resource)
FreeEventList(events, GetMaximumEventsNum());
}
int
TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti, int listener,
int mode)
{
InternalEvent *events;
int nev;
int i;
if (listener > 0) {
if (mode == XIRejectTouch)
TouchRejected(dev, ti, ti->listeners[listener].listener, NULL);
else
ti->listeners[listener].state = LISTENER_EARLY_ACCEPT;
return Success;
}
events = InitEventList(GetMaximumEventsNum());
if (!events) {
BUG_WARN_MSG(TRUE, "Failed to allocate touch ownership events\n");
return BadAlloc;
}
nev = GetTouchOwnershipEvents(events, dev, ti, mode,
ti->listeners[0].listener, 0);
BUG_WARN_MSG(nev == 0, "Failed to get touch ownership events\n");
for (i = 0; i < nev; i++)
mieqProcessDeviceEvent(dev, events + i, NULL);
ProcessInputEvents();
FreeEventList(events, GetMaximumEventsNum());
return nev ? Success : BadMatch;
}
int
TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
uint32_t touchid, Window grab_window, XID *error)
{
TouchPointInfoPtr ti;
int nev, i;
InternalEvent *events = InitEventList(GetMaximumEventsNum());
if (!events)
return BadAlloc;
int i;
if (!dev->touch) {
*error = dev->id;
@ -989,24 +1021,5 @@ TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
if (i == ti->num_listeners)
return BadAccess;
if (i > 0) {
if (mode == XIRejectTouch)
TouchRejected(dev, ti, ti->listeners[i].listener, NULL);
else
ti->listeners[i].state = LISTENER_EARLY_ACCEPT;
return Success;
}
nev = GetTouchOwnershipEvents(events, dev, ti, mode,
ti->listeners[0].listener, 0);
if (nev == 0)
return BadAlloc;
for (i = 0; i < nev; i++)
mieqProcessDeviceEvent(dev, events + i, NULL);
ProcessInputEvents();
FreeEventList(events, GetMaximumEventsNum());
return Success;
return TouchListenerAcceptReject(dev, ti, i, mode);
}

View File

@ -563,8 +563,8 @@ extern void TouchAddListener(TouchPointInfoPtr ti, XID resource,
extern Bool TouchRemoveListener(TouchPointInfoPtr ti, XID resource);
extern void TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti,
InternalEvent *ev);
extern Bool TouchEnsureSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
InternalEvent *ev);
extern Bool TouchBuildSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
InternalEvent *ev);
extern Bool TouchBuildDependentSpriteTrace(DeviceIntPtr dev, SpritePtr sprite);
extern int TouchConvertToPointerEvent(const InternalEvent *ev,
InternalEvent *motion,
@ -572,6 +572,8 @@ extern int TouchConvertToPointerEvent(const InternalEvent *ev,
extern int TouchGetPointerEventType(const InternalEvent *ev);
extern void TouchRemovePointerGrab(DeviceIntPtr dev);
extern void TouchListenerGone(XID resource);
extern int TouchListenerAcceptReject(DeviceIntPtr dev, TouchPointInfoPtr ti,
int listener, int mode);
extern int TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode,
uint32_t touchid, Window grab_window, XID *error);