From 9cc45c18ad1511adf3fb163dd4cefbef106edb23 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 13 Feb 2013 10:49:23 +1000 Subject: [PATCH 01/28] 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 --- Xi/exevents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 30882570d..fae747c4c 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; From 363b6387da6e669099a2da3861c73a29808295a6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 13 Feb 2013 11:26:11 +1000 Subject: [PATCH 02/28] 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 --- 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 From 81554d274f04951c55ea7f2e38d0455e2025e08d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 25 Feb 2013 11:21:07 +1000 Subject: [PATCH 03/28] 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 --- Xi/exevents.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index fae747c4c..0cadf43f0 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); From d08bae297f9d7651edb1923d6b0d6b14b3d674fc Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 13:08:27 +1000 Subject: [PATCH 04/28] 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 --- Xi/exevents.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 0cadf43f0..27551dd09 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; } From 8b0d21044956f3810199d5e2f38ce33069e97be7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 13:04:36 +1000 Subject: [PATCH 05/28] 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 --- Xi/exevents.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 27551dd09..b1df0cb43 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"); } From d905348134c80f19793eefb761731b00559ddf3a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 15:28:46 +1000 Subject: [PATCH 06/28] 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 --- Xi/exevents.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index b1df0cb43..0f37d6b74 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; } From 026627fe19aad007544eccf209f0dea05e67a7a7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 09:15:37 +1000 Subject: [PATCH 07/28] 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 --- Xi/exevents.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 0f37d6b74..97fec3541 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); } From 214d11d3fcdac51fc7afbf3770516ec14f9e13c1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 27 Feb 2013 15:05:54 +1000 Subject: [PATCH 08/28] 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 --- Xi/exevents.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 97fec3541..9d999de5b 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) From a7d989d335f903ffd8b168cd2beeb82c78d30c21 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 13:07:26 +1000 Subject: [PATCH 09/28] 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 --- 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 9d999de5b..f4804735a 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 */ }; /** From 0eb9390f6048049136347d5a5834d88bfc67cc09 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 10:41:01 +1000 Subject: [PATCH 10/28] 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 --- Xi/exevents.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Xi/exevents.c b/Xi/exevents.c index f4804735a..f500669ad 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; From e7f79c48b0faea910dc881034c00eb807fcd6210 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 1 Mar 2013 12:52:35 +1000 Subject: [PATCH 11/28] dix: move EmitTouchEnd to touch.c No functional changes, this just enables it to be re-used easier. Signed-off-by: Peter Hutterer --- 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 f500669ad..2495adee5 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 304895ffc..ef8191b60 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); From 5174b1f98204beee79eba74c4cda5f2be0a60a8f Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Feb 2013 11:02:40 +1000 Subject: [PATCH 12/28] 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 --- 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 051205233..da9bd3821 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1742,6 +1742,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 ef8191b60..1745e9ade 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); From a71a283934406d870bcd8dc376eb1c9ce1c8bbb4 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Apr 2013 20:13:34 +1000 Subject: [PATCH 13/28] 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 --- 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; } From 7dbf61817d3bd4b1fc71710677e56c5d8cfcdb4e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Apr 2013 20:14:56 +1000 Subject: [PATCH 14/28] dix: use a tmp variable for the to-be-removed touch listener No functional changes. Signed-off-by: Peter Hutterer --- 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--; } From 5363433a5cc64e2f83859aa1c32a89e5e1ddf9e4 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 18 Apr 2013 10:32:11 +1000 Subject: [PATCH 15/28] 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 --- 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 9b6faee23..c514d7756 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 da9bd3821..e2e94a5f6 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1490,8 +1490,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); @@ -1554,6 +1555,8 @@ DeactivatePointerGrab(DeviceIntPtr mouse) ReattachToOldMaster(mouse); ComputeFreezes(); + + FreeGrab(grab); } /** @@ -1591,8 +1594,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, @@ -1638,6 +1642,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 */ , From ccfa0f2d5de557546815a5e4f59552e2af46b578 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 23 Apr 2013 15:39:32 +1000 Subject: [PATCH 16/28] dix: use a temporary variable for listeners[0] no functional changes Signed-off-by: Peter Hutterer --- dix/events.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dix/events.c b/dix/events.c index e2e94a5f6..dc503118a 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1427,21 +1427,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; } } } From 4980bcef9973ba1f90f53028f061669ee5d2661b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 23 Apr 2013 15:46:04 +1000 Subject: [PATCH 17/28] dix: freeing a null grab is a bug, complain if doing so Signed-off-by: Peter Hutterer --- 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); From 925e35122ebad877395bcf13676e9dbeb254bdfa Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 23 Apr 2013 15:52:18 +1000 Subject: [PATCH 18/28] dix: AllocGrab can copy if an argument is passed in Signed-off-by: Peter Hutterer --- 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 2495adee5..2feddd3b3 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -2844,7 +2844,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 dc503118a..cd2d9397e 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1492,8 +1492,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); @@ -1596,8 +1595,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, @@ -1991,7 +1989,7 @@ ActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win, else return FALSE; - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return FALSE; tempGrab->next = NULL; @@ -3898,7 +3896,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 */ @@ -5087,7 +5085,7 @@ GrabDevice(ClientPtr client, DeviceIntPtr dev, else { GrabPtr tempGrab; - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); tempGrab->next = NULL; tempGrab->window = pWin; @@ -5443,7 +5441,7 @@ ProcUngrabKey(ClientPtr client) client->errorValue = stuff->modifiers; return BadValue; } - tempGrab = AllocGrab(); + tempGrab = AllocGrab(NULL); if (!tempGrab) return BadAlloc; tempGrab->resource = client->clientAsMask; @@ -5637,7 +5635,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); From 395124bd2782823de37e5c5b2f15dba49cff05f6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 17 Apr 2013 20:15:35 +1000 Subject: [PATCH 19/28] 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 --- 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 2feddd3b3..ae2e5aeb0 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 cd2d9397e..76bc55564 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1442,7 +1442,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; From 34c9b39d9937c2e19c2dffc9748605f90d40f965 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Apr 2013 12:53:52 +1000 Subject: [PATCH 20/28] dix: remove all listeners when freeing a touch Signed-off-by: Peter Hutterer --- 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; From 5b00fc52270e9cfdfe7ac1838a21defe50fc3d31 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Apr 2013 14:40:31 +1000 Subject: [PATCH 21/28] 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 --- 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 1363f223d..51d0de25f 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -3399,6 +3399,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); From 2566bdd8bc996cccde77b846819808c6239a89d2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Apr 2013 14:46:06 +1000 Subject: [PATCH 22/28] 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 --- Xi/exevents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index ae2e5aeb0..a99821f0d 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1919,7 +1919,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; From 3093f78d17e48a506aab170a9089cd10e21af299 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 3 May 2013 15:02:05 +1000 Subject: [PATCH 23/28] 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 --- dix/events.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dix/events.c b/dix/events.c index 76bc55564..7464db586 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1468,6 +1468,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; @@ -1500,6 +1501,8 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, UpdateTouchesForGrab(mouse); CheckGrabForSyncs(mouse, (Bool) grab->pointerMode, (Bool) grab->keyboardMode); + if (oldgrab) + FreeGrab(oldgrab); } /** @@ -1570,6 +1573,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. */ @@ -1595,12 +1599,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); } /** From 481702101b86fff003430e952dc65fb41eb56400 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 3 May 2013 15:07:58 +1000 Subject: [PATCH 24/28] 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 --- dix/events.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/dix/events.c b/dix/events.c index 7464db586..8124ca93d 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1491,9 +1491,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; @@ -1552,8 +1549,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); @@ -4860,7 +4855,6 @@ ProcGrabPointer(ClientPtr client) GrabPtr grab; GrabMask mask; WindowPtr confineTo; - CursorPtr oldCursor; BYTE status; REQUEST(xGrabPointerReq); @@ -4883,15 +4877,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; @@ -4901,9 +4890,6 @@ ProcGrabPointer(ClientPtr client) if (rc != Success) return rc; - if (oldCursor && status == GrabSuccess) - FreeCursor(oldCursor, (Cursor) 0); - rep = (xGrabPointerReply) { .type = X_Reply, .status = status, @@ -5107,6 +5093,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); From fd5ea0237db6d725a48f76b706135df9d3246b82 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 13 May 2013 15:22:12 +1000 Subject: [PATCH 25/28] Xi: fix warning - remove unused 'rc' Signed-off-by: Peter Hutterer --- Xi/exevents.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index a99821f0d..2bbc6f091 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; From 8b9dc2628115dcb3f3601ad19b1ae157df21b9ee Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 14 May 2013 07:46:25 +1000 Subject: [PATCH 26/28] dix: devices must have valuators before touch is initialized Signed-off-by: Peter Hutterer --- dix/devices.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dix/devices.c b/dix/devices.c index c514d7756..c514cfeb3 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -1647,6 +1647,7 @@ InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches, BUG_RETURN_VAL(device == NULL, FALSE); BUG_RETURN_VAL(device->touch != NULL, FALSE); + BUG_RETURN_VAL(device->valuator == NULL, FALSE); /* Check the mode is valid, and at least X and Y axes. */ BUG_RETURN_VAL(mode != XIDirectTouch && mode != XIDependentTouch, FALSE); From 35c2e263db01b2b61354298e5e85aa3cae8ac317 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 14 May 2013 14:51:31 +1000 Subject: [PATCH 27/28] 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 --- 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 From 9a5ad65330693b3273972b63d10f2907d9ab954a Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 15 May 2013 19:01:11 +1000 Subject: [PATCH 28/28] 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 --- 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 8124ca93d..e5db348c6 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); } } @@ -3210,11 +3209,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); @@ -3293,9 +3291,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; @@ -4945,9 +4941,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); @@ -5092,9 +5086,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 a9297f3c8..8950f9766 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 @@ -3323,8 +3321,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; @@ -3412,8 +3409,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; @@ -3421,8 +3417,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 d32aac1cf..860704e1c 100644 --- a/hw/xfree86/ramdac/xf86Cursor.c +++ b/hw/xfree86/ramdac/xf86Cursor.c @@ -271,7 +271,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); @@ -285,7 +285,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, @@ -322,37 +322,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 90a026b28..753d5f7bc 100644 --- a/xfixes/cursor.c +++ b/xfixes/cursor.c @@ -613,12 +613,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); } }