From 34f5ca3a70e966d6fe232179a47c3dc660773ad5 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 08:26:06 +1000 Subject: Xi: use a temp variable for the new listener Instead of accessing ti->listener[0] all the time. No functional changes. Signed-off-by: Peter Hutterer Reviewed-by: Keith Packard (cherry picked from commit fc504a44d12d537d4e07f659f1863f200a0272ad) --- Xi/exevents.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index d39cf89a7..77c705f7a 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1126,20 +1126,22 @@ static void TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, TouchOwnershipEvent *ev) { + TouchListener *listener = &ti->listeners[0]; /* new owner */ + /* Deliver the ownership */ - if (ti->listeners[0].state == LISTENER_AWAITING_OWNER || - ti->listeners[0].state == LISTENER_EARLY_ACCEPT) + if (listener->state == LISTENER_AWAITING_OWNER || + listener->state == LISTENER_EARLY_ACCEPT) 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 @@ -1150,7 +1152,7 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, return; } - if (ti->listeners[0].state == LISTENER_EARLY_ACCEPT) + if (listener->state == LISTENER_EARLY_ACCEPT) ActivateEarlyAccept(dev, ti); } -- cgit v1.2.3 From 87e027726f2d9223ce2fef2e4d26c18ae680a05e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 13 Feb 2013 10:49:23 +1000 Subject: Xi: not having an ownership mask does not mean automatic acceptance If we only have a single touch-grabbing client, setting the client as owner would clean up the touch once the TouchEnd was processed. If the client then calls XIAllowTouches() it will receive a BadValue for the touch ID (since the internal record is already cleaned up). Signed-off-by: Peter Hutterer (cherry picked from commit 9cc45c18ad1511adf3fb163dd4cefbef106edb23) --- Xi/exevents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 77c705f7a..9a7c1cba5 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1867,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; -- cgit v1.2.3 From 636647bc7f9ed10918cbb228f7d448c8cf733667 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 13 Feb 2013 11:26:11 +1000 Subject: dix: don't prepend an activated passive grab to the listeners If the device is currently grabbed as the result of a passive grab activating, do not prepend that grab to the listeners (unlike active grabs). Otherwise, a client with a passive pointer grab will prevent touch grabs from activating higher up in the window stack. Signed-off-by: Peter Hutterer (cherry picked from commit 363b6387da6e669099a2da3861c73a29808295a6) --- dix/touch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dix/touch.c b/dix/touch.c index 3027bbbf2..5d6e2a796 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -874,7 +874,7 @@ TouchSetupListeners(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev) SpritePtr sprite = &ti->sprite; WindowPtr win; - if (dev->deviceGrab.grab) + if (dev->deviceGrab.grab && !dev->deviceGrab.fromPassiveGrab) TouchAddActiveGrabListener(dev, ti, ev, dev->deviceGrab.grab); /* We set up an active touch listener for existing touches, but not any -- cgit v1.2.3 From a7ec834d5e8c351cfa5d87b7902fa061826e3097 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 25 Feb 2013 11:21:07 +1000 Subject: Xi: if we delivered a TouchEnd to a passive grab, end it ef64b5ee97099618cf2e2cbbd3e471095695ae24 (which introduced the TOUCH_CLIENT_ID check) has a wrong assumption that generated touch events (TOUCH_CLIENT_ID) should not terminate passive grabs. This is untrue, a TouchEnd may be generated in response to a TouchReject higher up. If we _deliver_ an event to a client, terminate the passive grab. This requires us to count the actually delivered events too (first hunk). Signed-off-by: Peter Hutterer (cherry picked from commit 81554d274f04951c55ea7f2e38d0455e2025e08d) --- Xi/exevents.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 9a7c1cba5..2fdeaf460 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1417,7 +1417,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. */ @@ -1425,8 +1425,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); -- cgit v1.2.3 From 000d469dd4d97424c72d82e4383ec295e31ffd34 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 13:08:27 +1000 Subject: Xi: update the core listener state if we delivered the touch event If a TouchBegin is sent to a core client, that client is now the owner. By the time the TouchEnd is being processed, the client cannot replay anymore, so we can assume that this is the final touch end and we can clean up the touch record. Note: DeliverTouchEmulatedEvent is called for all listeners and immediately bails out if the client is not the owner and thus shouldn't yet get the event. Thus, check the return code. Signed-off-by: Peter Hutterer (cherry picked from commit d08bae297f9d7651edb1923d6b0d6b14b3d674fc) --- Xi/exevents.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 2fdeaf460..d07581596 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1849,6 +1849,8 @@ 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; goto out; } @@ -1889,13 +1891,13 @@ DeliverTouchEndEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev, 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; - } - + /* 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; } -- cgit v1.2.3 From 18346911ab0ce1ad66986b83f9afefadec25555e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 13:04:36 +1000 Subject: Xi: fix lookup in ActivateEarlyAccept ActivateEarlyAccept() can only be called from a grabbing client, so we can ignore the rest. And it's easy enough to get the client from that since 9ad0fdb135a1c336771aee1f6eab75a6ad874aff. Signed-off-by: Peter Hutterer (cherry picked from commit 8b0d21044956f3810199d5e2f38ce33069e97be7) --- Xi/exevents.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index d07581596..180f4b558 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1039,17 +1039,16 @@ 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"); } -- cgit v1.2.3 From 7343d05e3a502216532aa9901c3a8948ea118c78 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 15:28:46 +1000 Subject: Xi: if a passive async grab is activated from an emulated touch, accept Async grabs cannot replay events, they cannot reject, so we can do an early accept here. Signed-off-by: Peter Hutterer (cherry picked from commit d905348134c80f19793eefb761731b00559ddf3a) --- Xi/exevents.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 180f4b558..f1081cf3f 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1848,8 +1848,14 @@ DeliverTouchBeginEvent(DeviceIntPtr dev, TouchPointInfoPtr ti, listener->type == LISTENER_POINTER_GRAB) { rc = DeliverTouchEmulatedEvent(dev, ti, ev, listener, client, win, grab, xi2mask); - if (rc == Success) + 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; } -- cgit v1.2.3 From e1c908f3931aa82c7c5f14aa162e02f3abf98faf Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 09:15:37 +1000 Subject: Xi: save state for early acceptance Delivering an event changes the state to LISTENER_IS_OWNER and we thus lose the information of early acceptance. Signed-off-by: Peter Hutterer (cherry picked from commit 026627fe19aad007544eccf209f0dea05e67a7a7) --- Xi/exevents.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index f1081cf3f..14b0cec2e 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1126,10 +1126,10 @@ 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 (listener->state == LISTENER_AWAITING_OWNER || - listener->state == LISTENER_EARLY_ACCEPT) + if (listener->state == LISTENER_AWAITING_OWNER || accepted_early) DeliverTouchEvents(dev, ti, (InternalEvent *) ev, listener->listener); else if (listener->state == LISTENER_AWAITING_BEGIN) { @@ -1151,7 +1151,7 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, return; } - if (listener->state == LISTENER_EARLY_ACCEPT) + if (accepted_early) ActivateEarlyAccept(dev, ti); } -- cgit v1.2.3 From 2fcf86036f95128e9b90ddbd5ffc6edbacd3de9f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 27 Feb 2013 15:05:54 +1000 Subject: Xi: when punting to a new owner, always create TouchEnd events If a touch is pending_finish and we just punted it to the next owner, that client must receive a TouchEnd event. If we just punted to the last owner and that owner not a touch grab, we need to end the touch since this is the last event to be sent, and the client cannot accept/reject this. Signed-off-by: Peter Hutterer (cherry picked from commit 214d11d3fcdac51fc7afbf3770516ec14f9e13c1) --- Xi/exevents.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 14b0cec2e..a8b3ee62e 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1143,12 +1143,21 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, 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) { + /* New owner has Begin/Update but not end. If touch is pending_finish, + * emulate the TouchEnd now */ + if (ti->pending_finish) { EmitTouchEnd(dev, ti, 0, 0); - TouchEndTouch(dev, ti); - return; + + /* 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 (accepted_early) -- cgit v1.2.3 From c8a48358065ff94b8307d8aedfe58e54f34ba84f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 13:07:26 +1000 Subject: Xi: use public.processInputProc to replay the touch history If a device is frozen in results to a grab, we need to enqueue the events. This makes things complicated, and hard to follow since touch events are now replayed in the history, pushed into EnqueueEvent, then replayed later during PlayReleasedEvents in response to an XAllowEvents. While the device is frozen, no touch events are processed, so if there is a touch client with ownership mask _below_ the grab this will delay the delivery and potentially screw gesture recognition. However, this is the behaviour we have already anyway if the top-most client is a sync pgrab or there is a sync grab active on the device when the TouchBegin was generated. (also note, such a client would only reliably work in case of ReplayPointer anyway) Signed-off-by: Peter Hutterer (cherry picked from commit a7d989d335f903ffd8b168cd2beeb82c78d30c21) --- Xi/exevents.c | 8 +++++--- dix/touch.c | 16 +++++++++++++++- include/eventstr.h | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index a8b3ee62e..7975a404b 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1554,7 +1554,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); } @@ -1621,7 +1621,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; @@ -1629,7 +1631,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); diff --git a/dix/touch.c b/dix/touch.c index 5d6e2a796..76592e72a 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -474,7 +474,21 @@ TouchEventHistoryReplay(TouchPointInfoPtr ti, DeviceIntPtr dev, XID resource) DeviceEvent *ev = &ti->history[i]; ev->flags |= TOUCH_REPLAYING; - DeliverTouchEvents(dev, ti, (InternalEvent *) ev, resource); + ev->resource = resource; + /* FIXME: + We're replaying ti->history which contains the TouchBegin + + all TouchUpdates for ti. This needs to be passed on to the next + listener. If that is a touch listener, everything is dandy. + If the TouchBegin however triggers a sync passive grab, the + TouchUpdate events must be sent to EnqueueEvent so the events end + up in syncEvents.pending to be forwarded correctly in a + subsequent ComputeFreeze(). + + However, if we just send them to EnqueueEvent the sync'ing device + prevents handling of touch events for ownership listeners who + want the events right here, right now. + */ + dev->public.processInputProc((InternalEvent*)ev, dev); } } diff --git a/include/eventstr.h b/include/eventstr.h index 5c1adc459..3950584d5 100644 --- a/include/eventstr.h +++ b/include/eventstr.h @@ -123,6 +123,7 @@ struct _DeviceEvent { int corestate; /**< Core key/button state BEFORE the event */ int key_repeat; /**< Internally-generated key repeat event */ uint32_t flags; /**< Flags to be copied into the generated event */ + uint32_t resource; /**< Touch event resource, only for TOUCH_REPLAYING */ }; /** -- cgit v1.2.3 From 4dac09796ca7ec19c1a9b17f338babd51c999e2e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 10:41:01 +1000 Subject: Xi: Don't emit a TouchEnd event to a frozen device EmitTouchEnd calls DeliverTouchEvents directly instead of through public.processInputProc. If a device is frozen, the TouchEnd is processed while the device is waiting for a XAllowEvents and thus ends the touch point (and the grab) before the client decided what to do with it. In the case of ReplayPointer, this loses the event. This is a hack, but making EmitTouchEnd use processInputProc breaks approximately everything, especially the touch point is cleaned up during ProcessTouchEvents. Working around that is a bigger hack than this. Signed-off-by: Peter Hutterer (cherry picked from commit 0eb9390f6048049136347d5a5834d88bfc67cc09) --- Xi/exevents.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Xi/exevents.c b/Xi/exevents.c index 7975a404b..10fb8105f 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1067,6 +1067,10 @@ EmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource) { InternalEvent event; + /* We're not processing a touch end for a frozen device */ + if (dev->deviceGrab.sync.frozen) + return; + flags |= TOUCH_CLIENT_ID; if (ti->emulate_pointer) flags |= TOUCH_POINTER_EMULATED; -- cgit v1.2.3 From 8666395484d0ff68526b1afd0044329ca3e9c907 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 12:52:35 +1000 Subject: dix: move EmitTouchEnd to touch.c No functional changes, this just enables it to be re-used easier. Signed-off-by: Peter Hutterer (cherry picked from commit e7f79c48b0faea910dc881034c00eb807fcd6210) --- Xi/exevents.c | 35 ++++------------------------------- dix/touch.c | 27 +++++++++++++++++++++++++++ include/input.h | 1 + 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 10fb8105f..c33a92248 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1052,33 +1052,6 @@ ActivateEarlyAccept(DeviceIntPtr dev, TouchPointInfoPtr ti) 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; - - /* We're not processing a touch end for a frozen device */ - if (dev->deviceGrab.sync.frozen) - return; - - 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. * @@ -1150,7 +1123,7 @@ TouchPuntToNextOwner(DeviceIntPtr dev, TouchPointInfoPtr ti, /* New owner has Begin/Update but not end. If touch is pending_finish, * emulate the TouchEnd now */ if (ti->pending_finish) { - EmitTouchEnd(dev, ti, 0, 0); + 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. @@ -1208,7 +1181,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; } } @@ -1255,12 +1228,12 @@ ProcessTouchOwnershipEvent(TouchOwnershipEvent *ev, * 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); + 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); diff --git a/dix/touch.c b/dix/touch.c index 76592e72a..f7112fca9 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -1075,3 +1075,30 @@ TouchEndPhysicallyActiveTouches(DeviceIntPtr dev) FreeEventList(eventlist, GetMaximumEventsNum()); } + +/** + * 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. + */ +void +TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource) +{ + InternalEvent event; + + /* We're not processing a touch end for a frozen device */ + if (dev->deviceGrab.sync.frozen) + return; + + 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); +} diff --git a/include/input.h b/include/input.h index 5c65597e4..866879bd8 100644 --- a/include/input.h +++ b/include/input.h @@ -590,6 +590,7 @@ extern int TouchAcceptReject(ClientPtr client, DeviceIntPtr dev, int mode, extern void TouchEndPhysicallyActiveTouches(DeviceIntPtr dev); extern void TouchDeliverDeviceClassesChangedEvent(TouchPointInfoPtr ti, Time time, XID resource); +extern void TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource); /* misc event helpers */ extern Mask GetEventMask(DeviceIntPtr dev, xEvent *ev, InputClientsPtr clients); -- cgit v1.2.3 From 4081b00d36d074eedf5c8d04196998d23cff28cf Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 11:02:40 +1000 Subject: dix: XAllowEvents() on a touch event means accepting it A sync grab is the owner once it gets events. If it doesn't replay the event it will get all events from this touch, equivalent to accepting it. If the touch has ended before XAllowEvents() is called, we also now need to send the TouchEnd event and clean-up since we won't see anything more from this touch. Signed-off-by: Peter Hutterer (cherry picked from commit 5174b1f98204beee79eba74c4cda5f2be0a60a8f) --- dix/events.c | 10 ++++++++++ dix/touch.c | 14 ++++++++++++++ include/input.h | 1 + 3 files changed, 25 insertions(+) diff --git a/dix/events.c b/dix/events.c index 2682ecd46..7772c0bf8 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1739,6 +1739,16 @@ AllowSome(ClientPtr client, TimeStamp time, DeviceIntPtr thisDev, int newState) } break; } + + /* We've unfrozen the grab. If the grab was a touch grab, we're now the + * owner and expected to accept/reject it. Reject == ReplayPointer which + * we've handled in ComputeFreezes() (during DeactivateGrab) above, + * anything else is accept. + */ + if (newState != NOT_GRABBED /* Replay */ && + IsTouchEvent((InternalEvent*)grabinfo->sync.event)) { + TouchAcceptAndEnd(thisDev, grabinfo->sync.event->touchid); + } } /** diff --git a/dix/touch.c b/dix/touch.c index f7112fca9..0cbc2eb01 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -1102,3 +1102,17 @@ TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resourc GetDixTouchEnd(&event, dev, ti, flags); DeliverTouchEvents(dev, ti, &event, resource); } + +void +TouchAcceptAndEnd(DeviceIntPtr dev, int touchid) +{ + TouchPointInfoPtr ti = TouchFindByClientID(dev, touchid); + if (!ti) + return; + + TouchListenerAcceptReject(dev, ti, 0, XIAcceptTouch); + if (ti->pending_finish) + TouchEmitTouchEnd(dev, ti, 0, 0); + if (ti->num_listeners <= 1) + TouchEndTouch(dev, ti); +} diff --git a/include/input.h b/include/input.h index 866879bd8..7eed60bcf 100644 --- a/include/input.h +++ b/include/input.h @@ -591,6 +591,7 @@ extern void TouchEndPhysicallyActiveTouches(DeviceIntPtr dev); extern void TouchDeliverDeviceClassesChangedEvent(TouchPointInfoPtr ti, Time time, XID resource); extern void TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resource); +extern void TouchAcceptAndEnd(DeviceIntPtr dev, int touchid); /* misc event helpers */ extern Mask GetEventMask(DeviceIntPtr dev, xEvent *ev, InputClientsPtr clients); -- cgit v1.2.3 From 88273287e1d7b3c06313f77d450f87a31bf53780 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Apr 2013 20:13:34 +1000 Subject: dix: invert a loop condition Change the single if condition in the loop body to a if (!foo) continue; and re-indent the rest. No functional changes. Signed-off-by: Peter Hutterer (cherry picked from commit a71a283934406d870bcd8dc376eb1c9ce1c8bbb4) --- dix/touch.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/dix/touch.c b/dix/touch.c index 0cbc2eb01..be4a7de00 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -718,21 +718,22 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource) int i; for (i = 0; i < ti->num_listeners; i++) { - if (ti->listeners[i].listener == resource) { - int j; + int j; - if (ti->listeners[i].grab) { - ti->listeners[i].grab = NULL; - ti->num_grabs--; - } + if (ti->listeners[i].listener != resource) + continue; - for (j = i; j < ti->num_listeners - 1; j++) - ti->listeners[j] = ti->listeners[j + 1]; - ti->num_listeners--; - ti->listeners[ti->num_listeners].listener = 0; - ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN; - return TRUE; + 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--; + ti->listeners[ti->num_listeners].listener = 0; + ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN; + return TRUE; } return FALSE; } -- cgit v1.2.3 From 25b641bb324c33226313c15448592b785043eaba Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Apr 2013 20:14:56 +1000 Subject: dix: use a tmp variable for the to-be-removed touch listener No functional changes. Signed-off-by: Peter Hutterer (cherry picked from commit 7dbf61817d3bd4b1fc71710677e56c5d8cfcdb4e) --- dix/touch.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dix/touch.c b/dix/touch.c index be4a7de00..01a554e0c 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -719,12 +719,13 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource) for (i = 0; i < ti->num_listeners; i++) { int j; + TouchListener *listener = &ti->listeners[i]; - if (ti->listeners[i].listener != resource) + if (listener->listener != resource) continue; - if (ti->listeners[i].grab) { - ti->listeners[i].grab = NULL; + if (listener->grab) { + listener->grab = NULL; ti->num_grabs--; } -- cgit v1.2.3 From d8c0cc9bab1fe159f58c2b5e8056c2d94a623789 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 18 Apr 2013 10:32:11 +1000 Subject: dix: drop DeviceIntRec's activeGrab struct Obsolete since 4bc2761ad5ec2d0668aec639780ffb136605fbc8. This struct existed so copying a passive grab could be simply done by activeGrab = *grab and thus have a copy of the GrabPtr we'd get from various sources but still be able to check device->grab for NULL. Since 4bc2761 activeGrab is a pointer itself and points to the same memory as grabinfo->grab, leaving us with the potential of dangling pointers if either calls FreeGrab() and doesn't reset the other one. There is no reader of activeGrab anyway, so simply removing it is sufficient. Note: field is merely renamed to keep the ABI. Should be removed in the future. Signed-off-by: Peter Hutterer (cherry picked from commit 5363433a5cc64e2f83859aa1c32a89e5e1ddf9e4) --- dix/devices.c | 4 ++-- dix/events.c | 14 ++++++++++---- include/inputstr.h | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/dix/devices.c b/dix/devices.c index a0d545a96..9ef32bb24 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -281,7 +281,6 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) dev->deviceGrab.grabTime = currentTime; dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - dev->deviceGrab.activeGrab = AllocGrab(); dev->deviceGrab.sync.event = calloc(1, sizeof(DeviceEvent)); XkbSetExtension(dev, ProcessKeyboardEvent); @@ -977,7 +976,8 @@ CloseDevice(DeviceIntPtr dev) } } - FreeGrab(dev->deviceGrab.activeGrab); + if (dev->deviceGrab.grab) + FreeGrab(dev->deviceGrab.grab); free(dev->deviceGrab.sync.event); free(dev->config_info); /* Allocated in xf86ActivateDevice. */ free(dev->last.scroll); diff --git a/dix/events.c b/dix/events.c index 7772c0bf8..9ac879296 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1487,8 +1487,9 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, grabinfo->grabTime = time; if (grab->cursor) grab->cursor->refcnt++; - CopyGrab(grabinfo->activeGrab, grab); - grabinfo->grab = grabinfo->activeGrab; + BUG_WARN(grabinfo->grab != NULL); + grabinfo->grab = AllocGrab(); + CopyGrab(grabinfo->grab, grab); grabinfo->fromPassiveGrab = isPassive; grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; PostNewCursor(mouse); @@ -1551,6 +1552,8 @@ DeactivatePointerGrab(DeviceIntPtr mouse) ReattachToOldMaster(mouse); ComputeFreezes(); + + FreeGrab(grab); } /** @@ -1588,8 +1591,9 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, grabinfo->grabTime = syncEvents.time; else grabinfo->grabTime = time; - CopyGrab(grabinfo->activeGrab, grab); - grabinfo->grab = grabinfo->activeGrab; + BUG_WARN(grabinfo->grab != NULL); + grabinfo->grab = AllocGrab(); + CopyGrab(grabinfo->grab, grab); grabinfo->fromPassiveGrab = passive; grabinfo->implicitGrab = passive & ImplicitGrabMask; CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode, @@ -1635,6 +1639,8 @@ DeactivateKeyboardGrab(DeviceIntPtr keybd) ReattachToOldMaster(keybd); ComputeFreezes(); + + FreeGrab(grab); } void diff --git a/include/inputstr.h b/include/inputstr.h index de96faeda..85be885a0 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -485,7 +485,7 @@ typedef struct _GrabInfoRec { TimeStamp grabTime; Bool fromPassiveGrab; /* true if from passive grab */ Bool implicitGrab; /* implicit from ButtonPress */ - GrabPtr activeGrab; + GrabPtr unused; /* Kept for ABI stability, remove soon */ GrabPtr grab; CARD8 activatingKey; void (*ActivateGrab) (DeviceIntPtr /*device */ , -- cgit v1.2.3 From 27752301377698124634d48b62ba7fcf8310caab Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 23 Apr 2013 15:39:32 +1000 Subject: dix: use a temporary variable for listeners[0] no functional changes Signed-off-by: Peter Hutterer (cherry picked from commit ccfa0f2d5de557546815a5e4f59552e2af46b578) --- dix/events.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dix/events.c b/dix/events.c index 9ac879296..0216502a2 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1424,21 +1424,22 @@ UpdateTouchesForGrab(DeviceIntPtr mouse) for (i = 0; i < mouse->touch->num_touches; i++) { TouchPointInfoPtr ti = mouse->touch->touches + i; + TouchListener *listener = &ti->listeners[0]; 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; + CLIENT_BITS(listener->listener) == grab->resource) { + listener->listener = grab->resource; + listener->level = grab->grabtype; + listener->state = LISTENER_IS_OWNER; + listener->window = grab->window; if (grab->grabtype == CORE || grab->grabtype == XI || !xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin)) - ti->listeners[0].type = LISTENER_POINTER_GRAB; + listener->type = LISTENER_POINTER_GRAB; else - ti->listeners[0].type = LISTENER_GRAB; - ti->listeners[0].grab = grab; + listener->type = LISTENER_GRAB; + listener->grab = grab; } } } -- cgit v1.2.3 From 479f8bf236d17e2a2093d349d2ef6471ff089a53 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 23 Apr 2013 15:46:04 +1000 Subject: dix: freeing a null grab is a bug, complain if doing so Signed-off-by: Peter Hutterer (cherry picked from commit 4980bcef9973ba1f90f53028f061669ee5d2661b) --- dix/grabs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dix/grabs.c b/dix/grabs.c index 3b02352df..0a2111d8a 100644 --- a/dix/grabs.c +++ b/dix/grabs.c @@ -249,6 +249,8 @@ CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice, void FreeGrab(GrabPtr pGrab) { + BUG_RETURN(!pGrab); + if (pGrab->grabtype == XI2 && pGrab->type == XI_TouchBegin) TouchListenerGone(pGrab->resource); -- cgit v1.2.3 From 6bd9badc780ec9d1fb147dfa0c671979c75b722c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 23 Apr 2013 15:52:18 +1000 Subject: dix: AllocGrab can copy if an argument is passed in Signed-off-by: Peter Hutterer (cherry picked from commit 925e35122ebad877395bcf13676e9dbeb254bdfa) --- Xi/exevents.c | 2 +- Xi/ungrdevb.c | 2 +- Xi/ungrdevk.c | 2 +- Xi/xipassivegrab.c | 2 +- dix/events.c | 16 +++++++--------- dix/grabs.c | 10 ++++++++-- include/dixgrabs.h | 2 +- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index c33a92248..ff32e0248 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -2845,7 +2845,7 @@ CheckDeviceGrabAndHintWindow(WindowPtr pWin, int type, (deliveryMask & DeviceButtonGrabMask)) { GrabPtr tempGrab; - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return; diff --git a/Xi/ungrdevb.c b/Xi/ungrdevb.c index c4632fadc..b02510ea0 100644 --- a/Xi/ungrdevb.c +++ b/Xi/ungrdevb.c @@ -127,7 +127,7 @@ ProcXUngrabDeviceButton(ClientPtr client) (stuff->modifiers & ~AllModifiersMask)) return BadValue; - temporaryGrab = AllocGrab(); + temporaryGrab = AllocGrab(NULL); if (!temporaryGrab) return BadAlloc; diff --git a/Xi/ungrdevk.c b/Xi/ungrdevk.c index 3273878d3..f98117168 100644 --- a/Xi/ungrdevk.c +++ b/Xi/ungrdevk.c @@ -134,7 +134,7 @@ ProcXUngrabDeviceKey(ClientPtr client) (stuff->modifiers & ~AllModifiersMask)) return BadValue; - temporaryGrab = AllocGrab(); + temporaryGrab = AllocGrab(NULL); if (!temporaryGrab) return BadAlloc; diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c index 62a3a469f..eccec0ab8 100644 --- a/Xi/xipassivegrab.c +++ b/Xi/xipassivegrab.c @@ -307,7 +307,7 @@ ProcXIPassiveUngrabDevice(ClientPtr client) mod_dev = (IsFloating(dev)) ? dev : GetMaster(dev, MASTER_KEYBOARD); - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return BadAlloc; diff --git a/dix/events.c b/dix/events.c index 0216502a2..6a8e7a64a 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1489,8 +1489,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, if (grab->cursor) grab->cursor->refcnt++; BUG_WARN(grabinfo->grab != NULL); - grabinfo->grab = AllocGrab(); - CopyGrab(grabinfo->grab, grab); + grabinfo->grab = AllocGrab(grab); grabinfo->fromPassiveGrab = isPassive; grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; PostNewCursor(mouse); @@ -1593,8 +1592,7 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, else grabinfo->grabTime = time; BUG_WARN(grabinfo->grab != NULL); - grabinfo->grab = AllocGrab(); - CopyGrab(grabinfo->grab, grab); + grabinfo->grab = AllocGrab(grab); grabinfo->fromPassiveGrab = passive; grabinfo->implicitGrab = passive & ImplicitGrabMask; CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode, @@ -1988,7 +1986,7 @@ ActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win, else return FALSE; - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return FALSE; tempGrab->next = NULL; @@ -3895,7 +3893,7 @@ CheckPassiveGrabsOnWindow(WindowPtr pWin, if (!grab) return NULL; - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); /* Fill out the grab details, but leave the type for later before * comparing */ @@ -5084,7 +5082,7 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, else { GrabPtr tempGrab; - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); tempGrab->next = NULL; tempGrab->window = pWin; @@ -5440,7 +5438,7 @@ ProcUngrabKey(ClientPtr client) client->errorValue = stuff->modifiers; return BadValue; } - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return BadAlloc; tempGrab->resource = client->clientAsMask; @@ -5634,7 +5632,7 @@ ProcUngrabButton(ClientPtr client) ptr = PickPointer(client); - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return BadAlloc; tempGrab->resource = client->clientAsMask; diff --git a/dix/grabs.c b/dix/grabs.c index 0a2111d8a..f46a6b23a 100644 --- a/dix/grabs.c +++ b/dix/grabs.c @@ -189,7 +189,7 @@ UngrabAllDevices(Bool kill_client) } GrabPtr -AllocGrab(void) +AllocGrab(const GrabPtr src) { GrabPtr grab = calloc(1, sizeof(GrabRec)); @@ -201,6 +201,12 @@ AllocGrab(void) } } + if (src && !CopyGrab(grab, src)) { + free(grab->xi2mask); + free(grab); + grab = NULL; + } + return grab; } @@ -213,7 +219,7 @@ CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice, { GrabPtr grab; - grab = AllocGrab(); + grab = AllocGrab(NULL); if (!grab) return (GrabPtr) NULL; grab->resource = FakeClientID(client); diff --git a/include/dixgrabs.h b/include/dixgrabs.h index eccec77f8..ca3c95be7 100644 --- a/include/dixgrabs.h +++ b/include/dixgrabs.h @@ -31,7 +31,7 @@ struct _GrabParameters; extern void PrintDeviceGrabInfo(DeviceIntPtr dev); extern void UngrabAllDevices(Bool kill_client); -extern GrabPtr AllocGrab(void); +extern GrabPtr AllocGrab(const GrabPtr src); extern void FreeGrab(GrabPtr grab); extern Bool CopyGrab(GrabPtr dst, const GrabPtr src); -- cgit v1.2.3 From ab76a3a3fc56cf8f530e5ab9b6389b09da1cdc12 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Apr 2013 20:15:35 +1000 Subject: dix: always copy grabs, don't reference them Introduced in xorg-server-1.13.99.901-2-g9ad0fdb. Storing the grab pointer in the listener turns out to be a bad idea. If the grab is not an active grab or an implicit grab, the pointer stored is the one to the grab attached on the window. This grab may be removed if the client calls UngrabButton or similar while the touch is still active, leaving a dangling pointer. To avoid this, copy the grab wherever we need to reference it later. This is also what we do for pointer/keyboard grabs, where we copy the grab as soon as it becomes active. Reported-by: Maarten Lankhorst Signed-off-by: Peter Hutterer (cherry picked from commit 395124bd2782823de37e5c5b2f15dba49cff05f6) --- Xi/exevents.c | 7 +++++-- dix/events.c | 3 ++- dix/touch.c | 19 +++++++++++++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index ff32e0248..90cbcc538 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1429,8 +1429,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; @@ -1439,8 +1442,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) diff --git a/dix/events.c b/dix/events.c index 6a8e7a64a..8745c1135 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1439,7 +1439,8 @@ UpdateTouchesForGrab(DeviceIntPtr mouse) listener->type = LISTENER_POINTER_GRAB; else listener->type = LISTENER_GRAB; - listener->grab = grab; + FreeGrab(listener->grab); + listener->grab = AllocGrab(grab); } } } diff --git a/dix/touch.c b/dix/touch.c index 01a554e0c..fb218d4b1 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -365,6 +365,8 @@ TouchBeginTouch(DeviceIntPtr dev, int sourceid, uint32_t touchid, void TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti) { + int i; + if (ti->emulate_pointer) { GrabPtr grab; @@ -376,6 +378,9 @@ TouchEndTouch(DeviceIntPtr dev, TouchPointInfoPtr ti) } } + for (i = 0; i < ti->num_listeners; i++) + TouchRemoveListener(ti, ti->listeners[0].listener); + ti->active = FALSE; ti->pending_finish = FALSE; ti->sprite.spriteTraceGood = 0; @@ -692,15 +697,23 @@ void TouchAddListener(TouchPointInfoPtr ti, XID resource, int resource_type, enum InputLevel level, enum TouchListenerType type, enum TouchListenerState state, WindowPtr window, - GrabPtr grab) + const GrabPtr grab) { + GrabPtr g = NULL; + + /* We need a copy of the grab, not the grab itself since that may be + * deleted by a UngrabButton request and leaves us with a dangling + * pointer */ + if (grab) + g = AllocGrab(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; + ti->listeners[ti->num_listeners].grab = g; if (grab) ti->num_grabs++; ti->num_listeners++; @@ -725,6 +738,7 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource) continue; if (listener->grab) { + FreeGrab(listener->grab); listener->grab = NULL; ti->num_grabs--; } @@ -734,6 +748,7 @@ TouchRemoveListener(TouchPointInfoPtr ti, XID resource) ti->num_listeners--; ti->listeners[ti->num_listeners].listener = 0; ti->listeners[ti->num_listeners].state = LISTENER_AWAITING_BEGIN; + return TRUE; } return FALSE; -- cgit v1.2.3 From 6c880c143f6a32d3bbc529e4a0ab1663ddecf0a0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Apr 2013 12:53:52 +1000 Subject: dix: remove all listeners when freeing a touch Signed-off-by: Peter Hutterer (cherry picked from commit 34c9b39d9937c2e19c2dffc9748605f90d40f965) --- dix/touch.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dix/touch.c b/dix/touch.c index fb218d4b1..009991433 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -263,6 +263,7 @@ void TouchFreeTouchPoint(DeviceIntPtr device, int index) { TouchPointInfoPtr ti; + int i; if (!device->touch || index >= device->touch->num_touches) return; @@ -271,6 +272,9 @@ TouchFreeTouchPoint(DeviceIntPtr device, int index) if (ti->active) TouchEndTouch(device, ti); + for (i = 0; i < ti->num_listeners; i++) + TouchRemoveListener(ti, ti->listeners[0].listener); + valuator_mask_free(&ti->valuators); free(ti->sprite.spriteTrace); ti->sprite.spriteTrace = NULL; -- cgit v1.2.3 From f3d63710d57aea0184ae07f0422a76b0fd6d415f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Apr 2013 14:40:31 +1000 Subject: Move TouchListenerGone call to CloseDownClient TouchListenerGone cleans up if a client disappears. Having this in FreeGrab() triggers cyclic removal of grabs, emitting wrong events. In particular, it would clean up a passive grab record while that grab is active. Move it to CloseDownClient() instead, cleaning up before we go. Signed-off-by: Peter Hutterer (cherry picked from commit 5b00fc52270e9cfdfe7ac1838a21defe50fc3d31) --- dix/dispatch.c | 1 + dix/grabs.c | 3 --- dix/touch.c | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dix/dispatch.c b/dix/dispatch.c index 8d6173525..20f241467 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -3398,6 +3398,7 @@ CloseDownClient(ClientPtr client) clientinfo.setup = (xConnSetup *) NULL; CallCallbacks((&ClientStateCallback), (pointer) &clientinfo); } + TouchListenerGone(client->clientAsMask); FreeClientResources(client); /* Disable client ID tracking. This must be done after * ClientStateCallback. */ diff --git a/dix/grabs.c b/dix/grabs.c index f46a6b23a..b254ddcf1 100644 --- a/dix/grabs.c +++ b/dix/grabs.c @@ -257,9 +257,6 @@ FreeGrab(GrabPtr pGrab) { BUG_RETURN(!pGrab); - if (pGrab->grabtype == XI2 && pGrab->type == XI_TouchBegin) - TouchListenerGone(pGrab->resource); - free(pGrab->modifiersDetail.pMask); free(pGrab->detail.pMask); diff --git a/dix/touch.c b/dix/touch.c index 009991433..110b1cce2 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -989,11 +989,11 @@ TouchListenerGone(XID resource) continue; for (j = 0; j < ti->num_listeners; j++) { - if (ti->listeners[j].listener != resource) + if (CLIENT_BITS(ti->listeners[j].listener) != resource) continue; nev = GetTouchOwnershipEvents(events, dev, ti, XIRejectTouch, - resource, 0); + ti->listeners[j].listener, 0); for (k = 0; k < nev; k++) mieqProcessDeviceEvent(dev, events + k, NULL); -- cgit v1.2.3 From ef0fff102d1feb5bccffc918da5c0dc7c0d28f3b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Apr 2013 14:46:06 +1000 Subject: Xi: check for HAS_ACCEPTED only for grab listeners If we have one listener left but it's not a grab, it cannot be in LISTENER_HAS_ACCEPTED state. Signed-off-by: Peter Hutterer (cherry picked from commit 2566bdd8bc996cccde77b846819808c6239a89d2) --- Xi/exevents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 90cbcc538..e1945b937 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1917,7 +1917,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; -- cgit v1.2.3 From 0ee9704f3c70fa7cf77edef55d158ad78df72a25 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 3 May 2013 15:02:05 +1000 Subject: dix: free the old grab when activating a new grab A client may call XIGrabDevice twice, overwriting the existing grab. Thus, make sure we free the old copy after we copied it. Free it last, to make sure our refcounts don't run to 0 and inadvertantly free something on the way. Signed-off-by: Peter Hutterer (cherry picked from commit 3093f78d17e48a506aab170a9089cd10e21af299) --- dix/events.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dix/events.c b/dix/events.c index 8745c1135..24fd6b921 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1465,6 +1465,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, TimeStamp time, Bool autoGrab) { GrabInfoPtr grabinfo = &mouse->deviceGrab; + GrabPtr oldgrab = grabinfo->grab; WindowPtr oldWin = (grabinfo->grab) ? grabinfo->grab->window : mouse->spriteInfo->sprite->win; Bool isPassive = autoGrab & ~ImplicitGrabMask; @@ -1497,6 +1498,8 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, UpdateTouchesForGrab(mouse); CheckGrabForSyncs(mouse, (Bool) grab->pointerMode, (Bool) grab->keyboardMode); + if (oldgrab) + FreeGrab(oldgrab); } /** @@ -1567,6 +1570,7 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive) { GrabInfoPtr grabinfo = &keybd->deviceGrab; + GrabPtr oldgrab = grabinfo->grab; WindowPtr oldWin; /* slave devices need to float for the duration of the grab. */ @@ -1592,12 +1596,13 @@ ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, grabinfo->grabTime = syncEvents.time; else grabinfo->grabTime = time; - BUG_WARN(grabinfo->grab != NULL); grabinfo->grab = AllocGrab(grab); grabinfo->fromPassiveGrab = passive; grabinfo->implicitGrab = passive & ImplicitGrabMask; CheckGrabForSyncs(keybd, (Bool) grab->keyboardMode, (Bool) grab->pointerMode); + if (oldgrab) + FreeGrab(oldgrab); } /** -- cgit v1.2.3 From 5c32bd0e2c104deaa2820c62289916fff6a4e3cd Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 3 May 2013 15:07:58 +1000 Subject: dix: fix cursor refcounting The cursor is referenced during CopyGrab(), thus doesn't need to be handled manually anymore. It does need to be refcounted for temp grabs though. The oldGrab handling in ProcGrabPointer is a leftover from the cursor in the grab being refcounted, but the grab itself being a static struct in the DeviceIntRec. Now that all grabs are copied, this lead to a double-free of the cursor (Reproduced in Thunderbird, dragging an email twice (or more often) causes a crash). Signed-off-by: Peter Hutterer (cherry picked from commit 481702101b86fff003430e952dc65fb41eb56400) --- dix/events.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/dix/events.c b/dix/events.c index 24fd6b921..64a8f15ed 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1488,9 +1488,6 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, grabinfo->grabTime = syncEvents.time; else grabinfo->grabTime = time; - if (grab->cursor) - grab->cursor->refcnt++; - BUG_WARN(grabinfo->grab != NULL); grabinfo->grab = AllocGrab(grab); grabinfo->fromPassiveGrab = isPassive; grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; @@ -1549,8 +1546,6 @@ DeactivatePointerGrab(DeviceIntPtr mouse) if (grab->confineTo) ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE); PostNewCursor(mouse); - if (grab->cursor) - FreeCursor(grab->cursor, (Cursor) 0); if (!wasImplicit && grab->grabtype == XI2) ReattachToOldMaster(mouse); @@ -4857,7 +4852,6 @@ ProcGrabPointer(ClientPtr client) GrabPtr grab; GrabMask mask; WindowPtr confineTo; - CursorPtr oldCursor; BYTE status; REQUEST(xGrabPointerReq); @@ -4880,15 +4874,10 @@ ProcGrabPointer(ClientPtr client) return rc; } - oldCursor = NullCursor; grab = device->deviceGrab.grab; - if (grab) { - if (grab->confineTo && !confineTo) - ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, - FALSE); - oldCursor = grab->cursor; - } + if (grab && grab->confineTo && !confineTo) + ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, FALSE); mask.core = stuff->eventMask; @@ -4898,9 +4887,6 @@ ProcGrabPointer(ClientPtr client) if (rc != Success) return rc; - if (oldCursor && status == GrabSuccess) - FreeCursor(oldCursor, (Cursor) 0); - rep = (xGrabPointerReply) { .type = X_Reply, .status = status, @@ -5104,6 +5090,8 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, xi2mask_merge(tempGrab->xi2mask, mask->xi2mask); tempGrab->device = dev; tempGrab->cursor = cursor; + if (cursor) + tempGrab->cursor->refcnt++; tempGrab->confineTo = confineTo; tempGrab->grabtype = grabtype; (*grabInfo->ActivateGrab) (dev, tempGrab, time, FALSE); -- cgit v1.2.3 From c0be1168fd3dd2eb01187789ddc30d7aab909a98 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 14 May 2013 14:51:31 +1000 Subject: dix: call UpdateDeviceState() for emulated TouchEndEvents ProcessTouchEvents() calls UDS for all touch events, but if the event type was switched to TouchUpdate(pending end) UDS is a noop. Daniel Drake found this can cause stuck buttons if a touch grab is activated, rejected and the touch event is passed to a regular listener. This sequence causes the TouchEnd to be changed to TouchUpdate(pending end). The actual TouchEnd event is later generated by the server once it is passed to the next listener. UDS is never called for this event, thus the button remains logically down. A previous patch suggested for UDS to handle TouchUpdate events [1], however this would release the button when the first TouchEvent is processed, not when the last grab has been released (as is the case for sync pointer grabs). A client may thus have the grab on the device, receive a ButtonPress but see the button logically up in an XQueryPointer request. This patch adds a call to UDS to TouchEmitTouchEnd(). The device state must be updated once a TouchEnd event was sent to the last grabbing listener and the number of grabs on the touchpoint is 0. [1] http://patchwork.freedesktop.org/patch/13464/ Signed-off-by: Peter Hutterer (cherry picked from commit 35c2e263db01b2b61354298e5e85aa3cae8ac317) --- dix/touch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dix/touch.c b/dix/touch.c index 110b1cce2..a4b6d7eea 100644 --- a/dix/touch.c +++ b/dix/touch.c @@ -1122,6 +1122,8 @@ TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags, XID resourc TouchDeliverDeviceClassesChangedEvent(ti, GetTimeInMillis(), resource); GetDixTouchEnd(&event, dev, ti, flags); DeliverTouchEvents(dev, ti, &event, resource); + if (ti->num_grabs == 0) + UpdateDeviceState(dev, &event.device_event); } void -- cgit v1.2.3 From 1e29b269fd712ae1e3552eeddd3529015baee7ae Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 15 May 2013 19:01:11 +1000 Subject: Abstract cursor refcounting Too many callers relied on the refcnt being handled correctly. Use a simple wrapper to handle that case. Signed-off-by: Peter Hutterer (cherry picked from commit 9a5ad65330693b3273972b63d10f2907d9ab954a) --- Xext/saver.c | 8 ++++---- dix/cursor.c | 33 ++++++++++++++++++++++++++++++++- dix/events.c | 20 ++++++-------------- dix/grabs.c | 8 ++------ dix/window.c | 15 +++++---------- hw/xfree86/modes/xf86Cursors.c | 4 ++-- hw/xfree86/ramdac/xf86Cursor.c | 28 ++++++++++++++-------------- include/cursor.h | 4 ++++ render/animcur.c | 3 +-- xfixes/cursor.c | 6 +++--- 10 files changed, 73 insertions(+), 56 deletions(-) diff --git a/Xext/saver.c b/Xext/saver.c index 8de043f8e..fe81bc4d7 100644 --- a/Xext/saver.c +++ b/Xext/saver.c @@ -531,15 +531,16 @@ CreateSaverWindow(ScreenPtr pScreen) mask |= CWBorderPixmap; } if (pAttr->pCursor) { + CursorPtr cursor; if (!pWin->optional) if (!MakeWindowOptional(pWin)) { FreeResource(pWin->drawable.id, RT_NONE); return FALSE; } - pAttr->pCursor->refcnt++; + cursor = RefCursor(pAttr->pCursor); if (pWin->optional->cursor) FreeCursor(pWin->optional->cursor, (Cursor) 0); - pWin->optional->cursor = pAttr->pCursor; + pWin->optional->cursor = cursor; pWin->cursorIsNone = FALSE; CheckWindowOptionalNeed(pWin); mask |= CWCursor; @@ -1065,8 +1066,7 @@ ScreenSaverSetAttributes(ClientPtr client) client->errorValue = cursorID; goto PatchUp; } - pCursor->refcnt++; - pAttr->pCursor = pCursor; + pAttr->pCursor = RefCursor(pCursor); pAttr->mask &= ~CWCursor; } break; diff --git a/dix/cursor.c b/dix/cursor.c index 1ee127ac5..0820b18ad 100644 --- a/dix/cursor.c +++ b/dix/cursor.c @@ -114,9 +114,13 @@ FreeCursor(pointer value, XID cid) ScreenPtr pscr; DeviceIntPtr pDev = NULL; /* unused anyway */ - if (--pCurs->refcnt != 0) + + UnrefCursor(pCurs); + if (CursorRefCount(pCurs) != 0) return Success; + BUG_WARN(CursorRefCount(pCurs) < 0); + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { pscr = screenInfo.screens[nscr]; (void) (*pscr->UnrealizeCursor) (pDev, pscr, pCurs); @@ -127,6 +131,33 @@ FreeCursor(pointer value, XID cid) return Success; } +CursorPtr +RefCursor(CursorPtr cursor) +{ + ErrorF("%s ::::: cursor is %p", __func__, cursor); + if (cursor) { + xorg_backtrace(); + cursor->refcnt++; + } + ErrorF("\n"); + return cursor; +} + +CursorPtr +UnrefCursor(CursorPtr cursor) +{ + if (cursor) + cursor->refcnt--; + return cursor; +} + +int +CursorRefCount(const CursorPtr cursor) +{ + return cursor ? cursor->refcnt : 0; +} + + /* * We check for empty cursors so that we won't have to display them */ diff --git a/dix/events.c b/dix/events.c index 64a8f15ed..4d50a2471 100644 --- a/dix/events.c +++ b/dix/events.c @@ -931,8 +931,7 @@ ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) (*pScreen->DisplayCursor) (pDev, pScreen, cursor); FreeCursor(pSprite->current, (Cursor) 0); - pSprite->current = cursor; - pSprite->current->refcnt++; + pSprite->current = RefCursor(cursor); } } @@ -3207,11 +3206,10 @@ InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin) pSprite->pEnqueueScreen = screenInfo.screens[0]; pSprite->pDequeueScreen = pSprite->pEnqueueScreen; } - if (pCursor) - pCursor->refcnt++; + pCursor = RefCursor(pCursor); if (pSprite->current) FreeCursor(pSprite->current, None); - pSprite->current = pCursor; + pSprite->current = RefCursor(pCursor); if (pScreen) { (*pScreen->RealizeCursor) (pDev, pScreen, pSprite->current); @@ -3290,9 +3288,7 @@ UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen) pSprite->hotLimits.x2 = pScreen->width; pSprite->hotLimits.y2 = pScreen->height; pSprite->win = win; - pCursor = wCursor(win); - if (pCursor) - pCursor->refcnt++; + pCursor = RefCursor(wCursor(win)); if (pSprite->current) FreeCursor(pSprite->current, 0); pSprite->current = pCursor; @@ -4942,9 +4938,7 @@ ProcChangeActivePointerGrab(ClientPtr client) (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) return Success; oldCursor = grab->cursor; - grab->cursor = newCursor; - if (newCursor) - newCursor->refcnt++; + grab->cursor = RefCursor(newCursor); PostNewCursor(device); if (oldCursor) FreeCursor(oldCursor, (Cursor) 0); @@ -5089,9 +5083,7 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, else xi2mask_merge(tempGrab->xi2mask, mask->xi2mask); tempGrab->device = dev; - tempGrab->cursor = cursor; - if (cursor) - tempGrab->cursor->refcnt++; + tempGrab->cursor = RefCursor(cursor); tempGrab->confineTo = confineTo; tempGrab->grabtype = grabtype; (*grabInfo->ActivateGrab) (dev, tempGrab, time, FALSE); diff --git a/dix/grabs.c b/dix/grabs.c index b254ddcf1..a03897af4 100644 --- a/dix/grabs.c +++ b/dix/grabs.c @@ -241,13 +241,11 @@ CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice, grab->detail.exact = keybut; grab->detail.pMask = NULL; grab->confineTo = confineTo; - grab->cursor = cursor; + grab->cursor = RefCursor(cursor); grab->next = NULL; if (grabtype == XI2) xi2mask_merge(grab->xi2mask, mask->xi2mask); - if (cursor) - cursor->refcnt++; return grab; } @@ -274,9 +272,6 @@ CopyGrab(GrabPtr dst, const GrabPtr src) Mask *details_mask = NULL; XI2Mask *xi2mask; - if (src->cursor) - src->cursor->refcnt++; - if (src->modifiersDetail.pMask) { int len = MasksPerDetailMask * sizeof(Mask); @@ -314,6 +309,7 @@ CopyGrab(GrabPtr dst, const GrabPtr src) dst->modifiersDetail.pMask = mdetails_mask; dst->detail.pMask = details_mask; dst->xi2mask = xi2mask; + dst->cursor = RefCursor(src->cursor); xi2mask_merge(dst->xi2mask, src->xi2mask); diff --git a/dix/window.c b/dix/window.c index a5b28a630..8e61779e7 100644 --- a/dix/window.c +++ b/dix/window.c @@ -547,8 +547,7 @@ InitRootWindow(WindowPtr pWin) (*pScreen->PositionWindow) (pWin, 0, 0); pWin->cursorIsNone = FALSE; - pWin->optional->cursor = rootCursor; - rootCursor->refcnt++; + pWin->optional->cursor = RefCursor(rootCursor); if (party_like_its_1989) { MakeRootTile(pWin); @@ -1416,8 +1415,7 @@ ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client) else if (pWin->parent && pCursor == wCursor(pWin->parent)) checkOptional = TRUE; pOldCursor = pWin->optional->cursor; - pWin->optional->cursor = pCursor; - pCursor->refcnt++; + pWin->optional->cursor = RefCursor(pCursor); pWin->cursorIsNone = FALSE; /* * check on any children now matching the new cursor @@ -3321,8 +3319,7 @@ MakeWindowOptional(WindowPtr pWin) parentOptional = FindWindowWithOptional(pWin)->optional; optional->visual = parentOptional->visual; if (!pWin->cursorIsNone) { - optional->cursor = parentOptional->cursor; - optional->cursor->refcnt++; + optional->cursor = RefCursor(parentOptional->cursor); } else { optional->cursor = None; @@ -3410,8 +3407,7 @@ ChangeWindowDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev, CursorPtr pCursor) if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor)) pNode->cursor = None; else { - pNode->cursor = pCursor; - pCursor->refcnt++; + pNode->cursor = RefCursor(pCursor); } pNode = pPrev = NULL; @@ -3419,8 +3415,7 @@ ChangeWindowDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev, CursorPtr pCursor) for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) { if (pNode->cursor == None) { /* inherited from parent */ - pNode->cursor = pOldCursor; - pOldCursor->refcnt++; + pNode->cursor = RefCursor(pOldCursor); } else if (pNode->cursor == pCursor) { pNode->cursor = None; diff --git a/hw/xfree86/modes/xf86Cursors.c b/hw/xfree86/modes/xf86Cursors.c index 634ee3fe0..2b0db3492 100644 --- a/hw/xfree86/modes/xf86Cursors.c +++ b/hw/xfree86/modes/xf86Cursors.c @@ -481,7 +481,7 @@ xf86_use_hw_cursor(ScreenPtr screen, CursorPtr cursor) xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; - ++cursor->refcnt; + cursor = RefCursor(cursor); if (xf86_config->cursor) FreeCursor(xf86_config->cursor, None); xf86_config->cursor = cursor; @@ -500,7 +500,7 @@ xf86_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor) xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; - ++cursor->refcnt; + cursor = RefCursor(cursor); if (xf86_config->cursor) FreeCursor(xf86_config->cursor, None); xf86_config->cursor = cursor; diff --git a/hw/xfree86/ramdac/xf86Cursor.c b/hw/xfree86/ramdac/xf86Cursor.c index 8d48a7542..f30bd33c7 100644 --- a/hw/xfree86/ramdac/xf86Cursor.c +++ b/hw/xfree86/ramdac/xf86Cursor.c @@ -272,7 +272,7 @@ xf86CursorRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs) (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates, xf86CursorScreenKey); - if (pCurs->refcnt <= 1) + if (CursorRefCount(pCurs) <= 1) dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen, NULL); @@ -286,7 +286,7 @@ xf86CursorUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs) (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates, xf86CursorScreenKey); - if (pCurs->refcnt <= 1) { + if (CursorRefCount(pCurs) <= 1) { free(dixLookupScreenPrivate (&pCurs->devPrivates, CursorScreenKey, pScreen)); dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen, @@ -323,37 +323,37 @@ xf86CursorSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCurs, /* only update for VCP, otherwise we get cursor jumps when removing a sprite. The second cursor is never HW rendered anyway. */ if (GetMaster(pDev, MASTER_POINTER) == inputInfo.pointer) { - pCurs->refcnt++; + CursorPtr cursor = RefCursor(pCurs); if (ScreenPriv->CurrentCursor) FreeCursor(ScreenPriv->CurrentCursor, None); - ScreenPriv->CurrentCursor = pCurs; + ScreenPriv->CurrentCursor = cursor; ScreenPriv->x = x; ScreenPriv->y = y; ScreenPriv->CursorToRestore = NULL; - ScreenPriv->HotX = pCurs->bits->xhot; - ScreenPriv->HotY = pCurs->bits->yhot; + ScreenPriv->HotX = cursor->bits->xhot; + ScreenPriv->HotY = cursor->bits->yhot; if (!infoPtr->pScrn->vtSema) - ScreenPriv->SavedCursor = pCurs; + ScreenPriv->SavedCursor = cursor; if (infoPtr->pScrn->vtSema && xorg_list_is_empty(&pScreen->pixmap_dirty_list) && (ScreenPriv->ForceHWCursorCount || (( #ifdef ARGB_CURSOR - pCurs->bits->argb && + cursor->bits->argb && infoPtr->UseHWCursorARGB && - (*infoPtr->UseHWCursorARGB)(pScreen, pCurs)) || - (pCurs->bits->argb == 0 && + (*infoPtr->UseHWCursorARGB)(pScreen, cursor)) || + (cursor->bits->argb == 0 && #endif - (pCurs->bits->height <= infoPtr->MaxHeight) && - (pCurs->bits->width <= infoPtr->MaxWidth) && - (!infoPtr->UseHWCursor || (*infoPtr->UseHWCursor) (pScreen, pCurs)))))) { + (cursor->bits->height <= infoPtr->MaxHeight) && + (cursor->bits->width <= infoPtr->MaxWidth) && + (!infoPtr->UseHWCursor || (*infoPtr->UseHWCursor) (pScreen, cursor)))))) { if (ScreenPriv->SWCursor) /* remove the SW cursor */ (*ScreenPriv->spriteFuncs->SetCursor) (pDev, pScreen, NullCursor, x, y); - xf86SetCursor(pScreen, pCurs, x, y); + xf86SetCursor(pScreen, cursor, x, y); ScreenPriv->SWCursor = FALSE; ScreenPriv->isUp = TRUE; diff --git a/include/cursor.h b/include/cursor.h index 082325123..89a650fc5 100644 --- a/include/cursor.h +++ b/include/cursor.h @@ -71,6 +71,10 @@ extern _X_EXPORT CursorPtr rootCursor; extern _X_EXPORT int FreeCursor(pointer /*pCurs */ , XID /*cid */ ); +extern _X_EXPORT CursorPtr RefCursor(CursorPtr /* cursor */); +extern _X_EXPORT CursorPtr UnrefCursor(CursorPtr /* cursor */); +extern _X_EXPORT int CursorRefCount(const CursorPtr /* cursor */); + extern _X_EXPORT int AllocARGBCursor(unsigned char * /*psrcbits */ , unsigned char * /*pmaskbits */ , CARD32 * /*argb */ , diff --git a/render/animcur.c b/render/animcur.c index 9cbba83fa..038c5b9be 100644 --- a/render/animcur.c +++ b/render/animcur.c @@ -383,8 +383,7 @@ AnimCursorCreate(CursorPtr *cursors, CARD32 *deltas, int ncursor, ac->elts = (AnimCurElt *) (ac + 1); for (i = 0; i < ncursor; i++) { - cursors[i]->refcnt++; - ac->elts[i].pCursor = cursors[i]; + ac->elts[i].pCursor = RefCursor(cursors[i]); ac->elts[i].delay = deltas[i]; } diff --git a/xfixes/cursor.c b/xfixes/cursor.c index 568e717fa..cc6e059b9 100644 --- a/xfixes/cursor.c +++ b/xfixes/cursor.c @@ -619,12 +619,12 @@ ReplaceCursorLookup(pointer value, XID id, pointer closure) } if (pCursor && pCursor != rcl->pNew) { if ((*rcl->testCursor) (pCursor, rcl->closure)) { - rcl->pNew->refcnt++; + CursorPtr curs = RefCursor(rcl->pNew); /* either redirect reference or update resource database */ if (pCursorRef) - *pCursorRef = rcl->pNew; + *pCursorRef = curs; else - ChangeResourceValue(id, RT_CURSOR, rcl->pNew); + ChangeResourceValue(id, RT_CURSOR, curs); FreeCursor(pCursor, cursor); } } -- cgit v1.2.3 From 54a7ae04a8475df6ce87e52ff995de22fafc7c92 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 27 May 2013 13:46:49 +1000 Subject: dix: remove logspam in RefCursor() This shouldn't have been in the patch Reported-by: Colin Harrison Signed-off-by: Peter Hutterer Reviewed-by: Keith Packard Signed-off-by: Keith Packard (cherry picked from commit c21344add2fc589df83b29be5831c36a372201bd) --- dix/cursor.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dix/cursor.c b/dix/cursor.c index 0820b18ad..cd8305c6c 100644 --- a/dix/cursor.c +++ b/dix/cursor.c @@ -134,12 +134,8 @@ FreeCursor(pointer value, XID cid) CursorPtr RefCursor(CursorPtr cursor) { - ErrorF("%s ::::: cursor is %p", __func__, cursor); - if (cursor) { - xorg_backtrace(); + if (cursor) cursor->refcnt++; - } - ErrorF("\n"); return cursor; } -- cgit v1.2.3 From ecd178e632a99ae2f12d2d9b6e9a48eaa421335d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 9 Jul 2013 13:27:19 +1000 Subject: dix: when ungrabbing an active grab, accept pointer grabs (#66720) Ungrabbing a device during an active touch grab rejects the grab. Ungrabbing a device during an active pointer grab accepts the grab. Rejection is not really an option for a pointer-emulated grab, if a client has a button mask on the window it would get a ButtonPress emulated after UngrabDevice. That is against the core grab behaviour. X.Org Bug 66720 Signed-off-by: Peter Hutterer Reviewed-by: Jasper St. Pierre (cherry picked from commit 8eeaa74bc241acb41f1d3ed64971e0b01e794776) --- Xi/exevents.c | 35 +++++++++++++++++++++++------------ dix/events.c | 11 +++++++++-- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index e1945b937..30e48f0c3 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1224,9 +1224,13 @@ 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) TouchEmitTouchEnd(dev, ti, TOUCH_ACCEPT, ti->listeners[0].listener); @@ -1884,16 +1888,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); - - /* 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; + /* 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; } diff --git a/dix/events.c b/dix/events.c index 4d50a2471..f9b2ed766 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1519,13 +1519,20 @@ DeactivatePointerGrab(DeviceIntPtr mouse) 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)) { + int mode = XIRejectTouch; /* 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)) + !xi2mask_isset(mouse->deviceGrab.grab->xi2mask, mouse, XI_TouchBegin)) { + mode = XIAcceptTouch; + /* NOTE: we set the state here, but + * ProcessTouchOwnershipEvent() will still call + * TouchEmitTouchEnd for this listener. The other half of + * this hack is in DeliverTouchEndEvent */ ti->listeners[0].state = LISTENER_HAS_END; - TouchListenerAcceptReject(mouse, ti, 0, XIRejectTouch); + } + TouchListenerAcceptReject(mouse, ti, 0, mode); } } -- cgit v1.2.3 From 93f063c40dc4b339ae9114551071c57b52d98dba Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 12 Jul 2013 14:10:10 +1000 Subject: dix: UpdateTouchesForGrab must only free the listener grab if it is non-NULL If a client calls XIGrabDevice in response to a ButtonPress event (regular event selection), the device will have a grab, but listener->grab is NULL. Check for that, to avoid logspam. [ 26293.863] (EE) BUG: triggered 'if (!pGrab)' [ 26293.863] (EE) BUG: grabs.c:256 in FreeGrab() [ 26293.863] (EE) [ 26293.863] (EE) Backtrace: [ 26293.864] (EE) 0: /usr/bin/Xorg (FreeGrab+0x54) [0x45d3fc] [ 26293.864] (EE) 1: /usr/bin/Xorg (UpdateTouchesForGrab+0x135) [0x447d4e] [ 26293.864] (EE) 2: /usr/bin/Xorg (ActivatePointerGrab+0x1ba) [0x447f3d] [ 26293.864] (EE) 3: /usr/bin/Xorg (GrabDevice+0x3e6) [0x4503bc] [ 26293.864] (EE) 4: /usr/bin/Xorg (ProcXIGrabDevice+0x1f9) [0x5981b1] [ 26293.865] (EE) 5: /usr/bin/Xorg (ProcIDispatch+0x78) [0x58aa17] [ 26293.865] (EE) 6: /usr/bin/Xorg (Dispatch+0x30d) [0x43347e] [ 26293.865] (EE) 7: /usr/bin/Xorg (main+0x61d) [0x498175] [ 26293.865] (EE) 8: /lib64/libc.so.6 (__libc_start_main+0xf5) [0x3df5621b75] [ 26293.865] (EE) 9: /usr/bin/Xorg (_start+0x29) [0x423a19] [ 26293.866] (EE) 10: ? (?+0x29) [0x29] [ 26293.866] (EE) Signed-off-by: Peter Hutterer Reviewed-by: Keith Packard (cherry picked from commit 0e3be0b25fcfeff386bad132526352c2e45f1932) --- dix/events.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dix/events.c b/dix/events.c index f9b2ed766..c079f9756 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1438,7 +1438,8 @@ UpdateTouchesForGrab(DeviceIntPtr mouse) listener->type = LISTENER_POINTER_GRAB; else listener->type = LISTENER_GRAB; - FreeGrab(listener->grab); + if (listener->grab) + FreeGrab(listener->grab); listener->grab = AllocGrab(grab); } } -- cgit v1.2.3 From c203568905bcbb65fb1e079b626d2c1e90ecb72d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 13 May 2013 15:22:12 +1000 Subject: Xi: fix warning - remove unused 'rc' Signed-off-by: Peter Hutterer (cherry picked from commit fd5ea0237db6d725a48f76b706135df9d3246b82) --- Xi/exevents.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 30e48f0c3..91281ae94 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1036,7 +1036,6 @@ 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; -- cgit v1.2.3 From 2cd62dc02b67c70d2417b2ccd307ead9596a2967 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 08:43:58 +1000 Subject: Xi: return !Success from DeliverTouchEmulatedEvent if we didn't deliver All callers currently ignore the new value, so this patch has no effect. Inverse call graph: DeliverTouchEmulatedEvent DeliverEmulatedMotionEvent Ignores value DeliverTouchBeginEvent DeliverTouchEvent DeliverTouchEvents Ignores value DeliverTouchEndEvent DeliverTouchEvent DeliverTouchEvents Ignores value Signed-off-by: Peter Hutterer Reviewed-by: Keith Packard (cherry picked from commit 9978b57b8d94f061d72a67b99a02b0ba16a11429) --- Xi/exevents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 91281ae94..067e6b3e5 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1373,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); @@ -1395,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; -- cgit v1.2.3