diff options
Diffstat (limited to 'Xi/exevents.c')
-rw-r--r-- | Xi/exevents.c | 155 |
1 files changed, 82 insertions, 73 deletions
diff --git a/Xi/exevents.c b/Xi/exevents.c index d39cf89a7..067e6b3e5 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1036,47 +1036,22 @@ DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti, static void ActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti) { - int rc; ClientPtr client; XID error; + GrabPtr grab = ti->listeners[0].grab; - rc = dixLookupClient(&client, ti->listeners[0].listener, serverClient, - DixSendAccess); - if (rc != Success) { - ErrorF("[Xi] Failed to lookup early accepting client.\n"); - return; - } + BUG_RETURN(ti->listeners[0].type != LISTENER_GRAB && + ti->listeners[0].type != LISTENER_POINTER_GRAB); + BUG_RETURN(!grab); + + client = rClient(grab); if (TouchAcceptReject(client, dev, XIAcceptTouch, ti->client_id, - ti->listeners[0].window->drawable.id, &error) != - Success) + ti->listeners[0].window->drawable.id, &error) != Success) ErrorF("[Xi] Failed to accept touch grab after early acceptance.\n"); } /** - * Generate and deliver a TouchEnd event. - * - * @param dev The device to deliver the event for. - * @param ti The touch point record to deliver the event for. - * @param flags Internal event flags. The called does not need to provide - * TOUCH_CLIENT_ID and TOUCH_POINTER_EMULATED, this function will ensure - * they are set appropriately. - * @param resource The client resource to deliver to, or 0 for all clients. - */ -static void -EmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource) -{ - InternalEvent event; - - flags |= TOUCH_CLIENT_ID; - if (ti->emulate_pointer) - flags |= TOUCH_POINTER_EMULATED; - TouchDeliverDeviceClassesChangedEvent(ti, GetTimeInMillis(), resource); - GetDixTouchEnd(&event, dev, ti, flags); - DeliverTouchEvents(dev, ti, &event, resource); -} - -/** * Find the oldest touch that still has a pointer emulation client. * * Pointer emulation can only be performed for the oldest touch. Otherwise, the @@ -1126,31 +1101,42 @@ static void TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, TouchOwnershipEvent *ev) { + TouchListener *listener = &ti->listeners[0]; /* new owner */ + int accepted_early = listener->state == LISTENER_EARLY_ACCEPT; + /* Deliver the ownership */ - if (ti->listeners[0].state == LISTENER_AWAITING_OWNER || - ti->listeners[0].state == LISTENER_EARLY_ACCEPT) + if (listener->state == LISTENER_AWAITING_OWNER || accepted_early) DeliverTouchEvents(dev, ti, (InternalEvent *) ev, - ti->listeners[0].listener); - else if (ti->listeners[0].state == LISTENER_AWAITING_BEGIN) { + listener->listener); + else if (listener->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) && + if ((listener->type == LISTENER_POINTER_GRAB || + listener->type == LISTENER_POINTER_REGULAR) && ti != FindOldestPointerEmulatedTouch(dev)) return; - TouchEventHistoryReplay(ti, dev, ti->listeners[0].listener); + TouchEventHistoryReplay(ti, dev, listener->listener); } - /* If we've just removed the last grab and the touch has physically - * ended, send a TouchEnd event too and finalise the touch. */ - if (ti->num_listeners == 1 && ti->num_grabs == 0 && ti->pending_finish) { - EmitTouchEnd(dev, ti, 0, 0); - TouchEndTouch(dev, ti); - return; + /* New owner has Begin/Update but not end. If touch is pending_finish, + * emulate the TouchEnd now */ + if (ti->pending_finish) { + TouchEmitTouchEnd(dev, ti, 0, 0); + + /* If the last owner is not a touch grab, finalise the touch, we + won't get more correspondence on this. + */ + if (ti->num_listeners == 1 && + (ti->num_grabs == 0 || + listener->grab->grabtype != XI2 || + !xi2mask_isset(listener->grab->xi2mask, dev, XI_TouchBegin))) { + TouchEndTouch(dev, ti); + return; + } } - if (ti->listeners[0].state == LISTENER_EARLY_ACCEPT) + if (accepted_early) ActivateEarlyAccept(dev, ti); } @@ -1194,7 +1180,7 @@ TouchRejected(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, XID resource, for (i = 0; i < ti->num_listeners; i++) { if (ti->listeners[i].listener == resource) { if (ti->listeners[i].state != LISTENER_HAS_END) - EmitTouchEnd(sourcedev, ti, TOUCH_REJECT, resource); + TouchEmitTouchEnd(sourcedev, ti, TOUCH_REJECT, resource); break; } } @@ -1237,16 +1223,20 @@ ProcessTouchOwnershipEvent(TouchOwnershipEvent *ev, else if (ev->reason == XIAcceptTouch) { int i; - /* Go through the motions of ending the touch if the listener has + + /* For pointer-emulated listeners that ungrabbed the active grab, + * the state was forced to LISTENER_HAS_END. Still 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. */ + * the server. + */ if (ti->listeners[0].state == LISTENER_HAS_END) - EmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener); + TouchEmitTouchEnd(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. */ for (i = 1; i < ti->num_listeners; i++) - EmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener); + TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[i].listener); while (ti->num_listeners > 1) TouchRemoveListener(ti, ti->listeners[1].listener); @@ -1383,7 +1373,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, /* We don't deliver pointer events to non-owners */ if (!TouchResourceIsOwner(ti, listener->listener)) - return Success; + return !Success; nevents = TouchConvertToPointerEvent(ev, &motion, &button); BUG_RETURN_VAL(nevents == 0, BadValue); @@ -1405,7 +1395,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, /* 'grab' is the passive grab, but if the grab isn't active, * don't deliver */ if (!dev->deviceGrab.grab) - return Success; + return !Success; if (grab->ownerEvents) { WindowPtr focus = NullWindow; @@ -1415,7 +1405,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, } if (!deliveries) - DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype); + deliveries = DeliverOneGrabbedEvent(ptrev, dev, grab->grabtype); /* We must accept the touch sequence once a pointer listener has * received one event past ButtonPress. */ @@ -1423,8 +1413,7 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, !(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) && + if (deliveries && ev->any.type == ET_TouchEnd && !dev->button->buttonsDown && dev->deviceGrab.fromPassiveGrab && GrabIsPointerGrab(grab)) { (*dev->deviceGrab.DeactivateGrab) (dev); @@ -1443,8 +1432,11 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, */ if (!devgrab && dev->deviceGrab.grab && dev->deviceGrab.implicitGrab) { TouchListener *l; + GrabPtr g; devgrab = dev->deviceGrab.grab; + g = AllocGrab(devgrab); + BUG_WARN(!g); *dev->deviceGrab.sync.event = ev->device_event; @@ -1453,8 +1445,8 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, * event selection. Thus, we update the last listener in the array. */ l = &ti->listeners[ti->num_listeners - 1]; - l->listener = devgrab->resource; - l->grab = devgrab; + l->listener = g->resource; + l->grab = g; //l->resource_type = RT_NONE; if (devgrab->grabtype != XI2 || devgrab->type != XI_TouchBegin) @@ -1545,7 +1537,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev) touchid = ev->device_event.touchid; - if (type == ET_TouchBegin) { + if (type == ET_TouchBegin && !(ev->device_event.flags & TOUCH_REPLAYING)) { ti = TouchBeginTouch(dev, ev->device_event.sourceid, touchid, emulate_pointer); } @@ -1612,7 +1604,9 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev) * called after event type mutation. Touch end events are always processed * in order to end touch records. */ /* FIXME: check this */ - if ((type == ET_TouchBegin && !TouchBuildSprite(dev, ti, ev)) || + if ((type == ET_TouchBegin && + !(ev->device_event.flags & TOUCH_REPLAYING) && + !TouchBuildSprite(dev, ti, ev)) || (type != ET_TouchEnd && ti->sprite.spriteTraceGood == 0)) return; @@ -1620,7 +1614,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev) /* WARNING: the event type may change to TouchUpdate in * DeliverTouchEvents if a TouchEnd was delivered to a grabbing * owner */ - DeliverTouchEvents(dev, ti, (InternalEvent *) ev, 0); + DeliverTouchEvents(dev, ti, ev, ev->device_event.resource); if (ev->any.type == ET_TouchEnd) TouchEndTouch(dev, ti); @@ -1848,6 +1842,14 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, listener->type == LISTENER_POINTER_GRAB) { rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab, xi2mask); + if (rc == Success) { + listener->state = LISTENER_IS_OWNER; + /* async grabs cannot replay, so automatically accept this touch */ + if (dev->deviceGrab.grab && + dev->deviceGrab.fromPassiveGrab && + dev->deviceGrab.grab->pointerMode == GrabModeAsync) + ActivateEarlyAccept(dev, ti); + } goto out; } @@ -1865,7 +1867,7 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, if (has_ownershipmask) TouchSendOwnershipEvent(dev, ti, 0, listener->listener); - if (!has_ownershipmask || listener->type == LISTENER_REGULAR) + if (listener->type == LISTENER_REGULAR) state = LISTENER_HAS_ACCEPTED; else state = LISTENER_IS_OWNER; @@ -1885,16 +1887,23 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev, if (listener->type == LISTENER_POINTER_REGULAR || 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; - if (!(ev->device_event.flags & TOUCH_CLIENT_ID)) - ti->pending_finish = TRUE; + /* Note: If the active grab was ungrabbed, we already changed the + * state to LISTENER_HAS_END but still get here. So we mustn't + * actually send the event. + * This is part two of the hack in DeactivatePointerGrab + */ + if (listener->state != LISTENER_HAS_END) { + rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, + grab, xi2mask); + + /* Once we send a TouchEnd to a legacy listener, we're already well + * past the accepting/rejecting stage (can only happen on + * GrabModeSync + replay. This listener now gets the end event, + * and we can continue. + */ + if (rc == Success) + listener->state = LISTENER_HAS_END; } - goto out; } @@ -1918,7 +1927,7 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev, rc = DeliverOneTouchEvent(client, dev, ti, grab, win, ev); if ((ti->num_listeners > 1 || - listener->state != LISTENER_HAS_ACCEPTED) && + (ti->num_grabs > 0 && listener->state != LISTENER_HAS_ACCEPTED)) && (ev->device_event.flags & (TOUCH_ACCEPT | TOUCH_REJECT)) == 0) { ev->any.type = ET_TouchUpdate; ev->device_event.flags |= TOUCH_PENDING_END; @@ -2849,7 +2858,7 @@ CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type, (deliveryMask & DeviceButtonGrabMask)) { GrabPtr tempGrab; - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return; |