summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Xi/exevents.c650
-rw-r--r--Xi/xiallowev.c10
-rw-r--r--dix/events.c24
-rw-r--r--include/inputstr.h25
4 files changed, 592 insertions, 117 deletions
diff --git a/Xi/exevents.c b/Xi/exevents.c
index 1b618d35a..a9ba99f8e 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -953,27 +953,57 @@ ProcessRawEvent(RawDeviceEvent *ev, DeviceIntPtr device)
}
}
+static Bool
+AddTouchClient(TouchPointInfoPtr ti, int client_id, WindowPtr window,
+ TouchClientType type, DeviceIntPtr dev, DeviceIntPtr sourcedev,
+ GrabPtr grab)
+{
+ TouchClientPtr client;
+
+ ti->active_clients++;
+ if (ti->active_clients >= ti->num_clients)
+ {
+ TouchClientPtr tmp;
+ tmp = realloc(ti->clients,
+ ti->num_clients * 2 * sizeof(TouchClientRec));
+ if (tmp)
+ {
+ ti->clients = tmp;
+ ti->num_clients *= 2;
+ } else {
+ LogMessage(X_ERROR, "failed to reallocate touch clients\n");
+ return TRUE;
+ }
+ }
+
+ client = &ti->clients[ti->active_clients - 1];
+ client->client = clients[client_id];
+ client->window = window;
+ client->type = type;
+ client->device = dev;
+ client->source = sourcedev;
+ client->grab = grab;
+
+ return (type == POINTER_GRAB_ASYNC);
+}
+
/**
* Ensure a window trace is present in ti->sprite, constructing one for
* TouchBegin events.
*/
static Bool
-EnsureTouchSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
- InternalEvent *ev)
+EnsureTouchClients(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
+ InternalEvent *ev)
{
TouchClassPtr t = sourcedev->touch;
SpritePtr sprite = &ti->sprite;
+ DeviceIntPtr masterdev = sourcedev->u.master;
+ WindowPtr grab_window = NullWindow;
+ Bool grab_window_seen = FALSE;
int i;
- /* We may not have a sprite if there are no applicable grabs or
- * event selections, or if they've disappeared, or if all the grab
- * owners have rejected the touch. Don't bother delivering motion
- * events if not, but TouchEnd events still need to be processed so
- * we can call FinishTouchPoint and release it for later use. */
- if (ev->any.type == ET_TouchEnd)
- return TRUE;
- else if (ev->any.type != ET_TouchBegin)
- return (sprite->spriteTraceGood > 0);
+ if (ev->any.type != ET_TouchBegin)
+ return (ti->num_clients > 0)
if (t->mode == XIDirectTouch)
{
@@ -992,22 +1022,42 @@ EnsureTouchSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
* device's sprite. */
for (i = 0; i < t->num_touches; i++)
if (!t->touches[i].pending_finish &&
- t->touches[i].sprite.spriteTraceGood > 0)
+ t->touches[i].active_clients > 0)
break;
- if (i < t->num_touches)
+ if (i < t->num_touches) {
srcsprite = &t->touches[i].sprite;
+ ti->active_clients = t->touches[i].active_clients;
+
+ if (ti->active_clients > ti->num_clients)
+ {
+ TouchClientPtr tmp;
+
+ tmp = realloc(ti->clients,
+ ti->active_clients * sizeof(TouchClientRec));
+ if (!tmp)
+ {
+ ti->active_clients = 0;
+ return FALSE;
+ }
+ ti->clients = tmp;
+ ti->num_clients = ti->active_clients;
+ }
+ memcpy(ti->clients, t->touches[i].clients,
+ ti->active_clients * sizeof(TouchClientRec));
+ }
else if (sourcedev->spriteInfo->sprite)
- srcsprite = sourcedev->spriteInfo->sprite;
+ srcprite = sourcedev->spriteInfo->sprite;
else
return FALSE;
if (srcsprite->spriteTraceGood > sprite->spriteTraceSize)
- {
+ {
trace = realloc(sprite->spriteTrace,
srcsprite->spriteTraceSize * sizeof(*trace));
if (!trace)
- {
+ {
sprite->spriteTraceGood = 0;
+ ti->active_clients = 0;
return FALSE;
}
sprite->spriteTrace = trace;
@@ -1016,22 +1066,192 @@ EnsureTouchSprite(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
memcpy(sprite->spriteTrace, srcsprite->spriteTrace,
srcsprite->spriteTraceGood * sizeof(*trace));
sprite->spriteTraceGood = srcsprite->spriteTraceGood;
+
+ if (ti->active_clients)
+ return TRUE;
}
if (sprite->spriteTraceGood <= 0)
return FALSE;
- /* Mark which grabs/event selections we're delivering to: max one grab per
- * window plus the bottom-most event selection. */
- ti->listeners = calloc(sprite->spriteTraceGood + 1, sizeof(*ti->listeners));
- if (!ti->listeners)
+ for (i = 0; i < sprite->spriteTraceGood; i++)
{
- sprite->spriteTraceGood = 0;
- return FALSE;
+ WindowPtr win = sprite->spriteTrace[i];
+ DeviceIntPtr deliverdev = sourcedev;
+ GrabPtr grab;
+ TouchClientPtr client;
+ TouchClientType type;
+ InternalEvent ev;
+
+ if (win == grab_window)
+ {
+ grab_window_seen = TRUE;
+ continue;
+ }
+ else if (grab_window && !grab_window_seen)
+ continue;
+
+ ev.any.type = ET_TouchBegin;
+ if ((grab = CheckPassiveGrabsOnWindow(win, sourcedev, ev, FALSE,
+ FALSE)))
+ {
+ if (AddTouchClient(ti, CLIENT_ID(grab->resource), win, TOUCH_GRAB,
+ sourcedev, sourcedev, grab))
+ goto done;
+ continue;
+ }
+ if (masterdev &&
+ (grab = CheckPassiveGrabsOnWindow(win, masterdev, ev, FALSE,
+ FALSE)))
+ {
+ if (AddTouchClient(ti, CLIENT_ID(grab->resource), win, TOUCH_GRAB,
+ masterdev, sourcedev, grab))
+ goto done;
+ continue;
+ }
+
+ ev.any.type = ET_ButtonPress;
+ ev.device_event.detail.button = 1;
+ if ((grab = CheckPassiveGrabsOnWindow(win, sourcedev, ev, FALSE,
+ FALSE)))
+ {
+ if (grab->pointerMode == GrabModeSync)
+ type = POINTER_GRAB_SYNC;
+ else
+ type = POINTER_GRAB_ASYNC;
+ if (AddTouchClient(ti, CLIENT_ID(grab->resource), win, type,
+ sourcedev, sourcedev, grab))
+ goto done;
+ continue;
+ }
+ if (masterdev &&
+ (grab = CheckPassiveGrabsOnWindow(win, masterdev, ev, FALSE,
+ FALSE)))
+ {
+ if (grab->pointerMode == GrabModeSync)
+ type = POINTER_GRAB_SYNC;
+ else
+ type = POINTER_GRAB_ASYNC;
+ if (AddTouchClient(ti, CLIENT_ID(grab->resource), win, type,
+ masterdev, sourcedev, grab))
+ goto done;
+ continue;
+ }
}
- ti->num_listeners = 0;
- return TRUE;
+ for (i = sprite->spriteTraceGood - 1; i >= 0; i--)
+ {
+ WindowPtr win = sprite->spriteTrace[i];
+ OtherInputMasks *inputMasks = wOtherInputMasks(win);
+ Bool select_seen = FALSE;
+
+ if (inputMasks &&
+ (BitIsOn(inputMasks->xi2mask[XIAllDevices],
+ XI_TouchMotionUnowned) ||
+ BitIsOn(inputMasks->xi2mask[sourcedev->id],
+ XI_TouchMotionUnowned) ||
+ (masterdev &&
+ (BitIsOn(inputMasks->xi2mask[XIAllMasterDevices],
+ XI_TouchMotionUnowned) ||
+ BitIsOn(inputMasks->xi2mask[masterdev->id],
+ XI_TouchMotionUnowned)))))
+ {
+ InputClientsPtr inputClients = inputMasks->inputClients;
+
+ for (inputClients = inputMasks->inputClients;
+ inputClients;
+ inputClients = inputClients->next)
+ {
+ if (BitIsOn(inputClients->xi2mask[XIAllDevices],
+ XI_TouchMotionUnowned) ||
+ BitIsOn(inputClients->xi2mask[sourcedev->id],
+ XI_TouchMotionUnowned))
+ {
+ if (AddTouchClient(ti, CLIENT_ID(inputClients->resource),
+ win, TOUCH_SELECT_UNOWNED, sourcedev,
+ sourcedev, grab))
+ goto done;
+ select_seen = TRUE;
+ continue;
+ }
+ else if (masterdev &&
+ (BitIsOn(inputClients->xi2mask[XIAllMasterDevices],
+ XI_TouchMotionUnowned) ||
+ BitIsOn(inputClients->xi2mask[masterdev->id],
+ XI_TouchMotionUnowned)))
+ {
+ if (AddTouchClient(ti, CLIENT_ID(inputClients->resource),
+ win, TOUCH_SELECT_UNOWNED, masterdev,
+ sourcedev, grab))
+ goto done;
+ select_seen = TRUE;
+ continue;
+ }
+ }
+ }
+
+ if (inputMasks &&
+ (BitIsOn(inputMasks->xi2mask[XIAllDevices], XI_TouchMotion) ||
+ BitIsOn(inputMasks->xi2mask[sourcedev->id], XI_TouchMotion) ||
+ (masterdev &&
+ (BitIsOn(inputMasks->xi2mask[XIAllMasterDevices],
+ XI_TouchMotion) ||
+ BitIsOn(inputMasks->xi2mask[masterdev->id],
+ XI_TouchMotion)))))
+ {
+ InputClientsPtr inputClients = inputMasks->inputClients;
+
+ for (inputClients = inputMasks->inputClients;
+ inputClients;
+ inputClients = inputClients->next)
+ {
+ if (BitIsOn(inputClients->xi2mask[XIAllDevices],
+ XI_TouchMotion) ||
+ BitIsOn(inputClients->xi2mask[sourcedev->id],
+ XI_TouchMotion))
+ {
+ AddTouchClient(ti, CLIENT_ID(inputClients->resource), win,
+ TOUCH_SELECT, sourcedev, sourcedev, grab);
+ goto done;
+ }
+ else if (masterdev &&
+ (BitIsOn(inputClients->xi2mask[XIAllMasterDevices],
+ XI_TouchMotion) ||
+ BitIsOn(inputClients->xi2mask[masterdev->id],
+ XI_TouchMotion)))
+ {
+ AddTouchClient(ti, CLIENT_ID(inputClients->resource), win,
+ TOUCH_SELECT, masterdev, sourcedev, grab);
+ goto done;
+ }
+ }
+ }
+
+ for (j = 0; j < 3; j++)
+ {
+ static const enum EventType events[] = {ET_ButtonPress,
+ ET_ButtonRelease,
+ ET_Motion};
+ InternalEvent ev;
+
+ ev.any.type = events[j];
+ if (EventIsDeliverable(sourcedev, &ev, win))
+ {
+ AddTouchClient(ti, 0, win, POINTER_SELECT, sourcedev,
+ sourcedev, grab);
+ goto done;
+ }
+ else if (masterdev && EventIsDeliverable(masterdev, &ev, win))
+ {
+ AddTouchClient(ti, 0, win, POINTER_SELECT, masterdev,
+ sourcedev, grab);
+ goto done;
+ }
+ }
+ }
+
+done:
+ return (ti->active_clients > 0);
}
/**
@@ -1066,8 +1286,8 @@ TouchResourceIsOwner(TouchPointInfoPtr ti, XID resource)
* Attempts to deliver a touch event to the given client.
*/
static Bool
-DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
- WindowPtr win, InternalEvent *ev)
+DeliverOneTouchEvent(TouchClientPtr client, TouchPointInfoPtr ti,
+ InternalEvent *ev)
{
int err;
xEvent *xi2;
@@ -1078,13 +1298,15 @@ DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
err = EventToXI2(ev, &xi2);
if (err != Success)
FatalError("[Xi] %s: XI2 conversion failed in DeliverOneTouchEvent"
- " (%d)\n", dev->name, err);
+ " (%d)\n", client->device->name, err);
- FixUpEventFromWindow(&ti->sprite, xi2, win, child, FALSE);
- filter = GetEventFilter(dev, xi2);
- if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
+ FixUpEventFromWindow(&ti->sprite, xi2, client->window, child, FALSE);
+ filter = GetEventFilter(client->device, xi2);
+ if (XaceHook(XACE_RECEIVE_ACCESS, client->client, client->window, xi2, 1)
+ != Success)
return FALSE;
- err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
+ err = TryClientEvents(client->client, client->device, xi2, 1, filter,
+ filter, NullGrab);
free(xi2);
/* Returning the value from TryClientEvents isn't useful, since all our
@@ -1092,6 +1314,26 @@ DeliverOneTouchEvent(ClientPtr client, DeviceIntPtr dev, TouchPointInfoPtr ti,
return TRUE;
}
+int
+DeliverTouchOwnershipEvent(TouchClientPtr client, TouchPointInfoPtr ti)
+{
+ TouchClassPtr t = pDev->touch;
+ TouchOwnershipEvent event;
+
+ memset(&event, 0, sizeof(TouchOwnershipEvent));
+ event.header = ET_Internal;
+ event.type = ET_TouchOwnership;
+ event.length = sizeof(TouchOwnershipEvent);
+ event.time = GetTimeInMillis();
+ event.deviceid = client->device->id;
+ event.sourceid = client->source->id;
+ event.touchid = ti->client_id;
+
+ DeliverOneTouchEvent(client, ti, (InternalEvent *)&event);
+
+ return 1;
+}
+
static DeviceIntPtr
CheckXI2Masks(OtherInputMasks *inputMasks, DeviceIntPtr sourcedev,
uint16_t evtype)
@@ -1306,29 +1548,6 @@ static void
TouchPointerEmulation(enum EventType evtype, DeviceIntPtr dev,
ValuatorMask *mask)
{
- EventList *emulationEvents = GetEvents();
- int i, nevents;
-
- if (evtype == ET_TouchBegin)
- {
- nevents = GetPointerEvents(emulationEvents, dev,
- MotionNotify, 0, POINTER_ABSOLUTE, mask);
- nevents += GetPointerEvents(emulationEvents + nevents, dev,
- ButtonPress, 1, POINTER_ABSOLUTE, mask);
- }
- else if (evtype == ET_TouchMotion)
- nevents = GetPointerEvents(emulationEvents, dev, MotionNotify, 0,
- POINTER_ABSOLUTE, mask);
- else if (evtype == ET_TouchEnd)
- {
- nevents = GetPointerEvents(emulationEvents, dev, MotionNotify, 0,
- POINTER_ABSOLUTE, mask);
- nevents += GetPointerEvents(emulationEvents + nevents, dev,
- ButtonRelease, 1, POINTER_ABSOLUTE, mask);
- }
-
- for (i = 0; i < nevents; i++)
- mieqEnqueue(dev, (InternalEvent*)((emulationEvents + i)->event));
}
/* Helper function to set up touch pointer emulation. */
@@ -1347,9 +1566,13 @@ SetTouchEmulationMask(InternalEvent *ev, ValuatorMask *mask, int x_axis,
/* Process touch emulation. */
static void
-EmulateTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
+EmulateTouchEvents(TouchClientPtr client, TouchPointInfoPtr ti,
+ InternalEvent *ev)
{
+ DeviceIntPtr dev = client->source;
+ EventList *emulationEvents = GetEvents();
ValuatorMask mask;
+ int nevents = 0;
int x_axis = dev->touch->x_axis;
int y_axis = dev->touch->y_axis;
@@ -1357,34 +1580,35 @@ EmulateTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
* at a time. */
dev->touch->emulate = ti;
- if (ev->any.type != ET_TouchOwnership)
+ /* Emulate a normal event. */
+ SetTouchEmulationMask(ev, &mask, x_axis, y_axis);
+
+ if (evtype == ET_TouchBegin)
{
- /* Emulate a normal event. */
- SetTouchEmulationMask(ev, &mask, x_axis, y_axis);
- TouchPointerEmulation(ev->any.type, dev, &mask);
+ nevents = GetPointerEvents(emulationEvents, dev,
+ MotionNotify, 0, POINTER_ABSOLUTE, mask);
+ nevents += GetPointerEvents(emulationEvents + nevents, dev,
+ ButtonPress, 1, POINTER_ABSOLUTE, mask);
}
- else
+ else if (evtype == ET_TouchMotion)
+ nevents = GetPointerEvents(emulationEvents, dev, MotionNotify, 0,
+ POINTER_ABSOLUTE, mask);
+ else if (evtype == ET_TouchEnd)
{
- /* If we got here, then a grabbing client rejected the touch. Replay
- all the touches buffered up. */
- ev = ti->begin_event;
-
- SetTouchEmulationMask(ev, &mask, x_axis, y_axis);
- TouchPointerEmulation(ev->any.type, dev, &mask);
+ nevents = GetPointerEvents(emulationEvents, dev, MotionNotify, 0,
+ POINTER_ABSOLUTE, mask);
+ nevents += GetPointerEvents(emulationEvents + nevents, dev,
+ ButtonRelease, 1, POINTER_ABSOLUTE, mask);
+ }
- ev = ti->first_history;
- while (ev != ti->next_history)
- {
- SetTouchEmulationMask(ev, &mask, x_axis, y_axis);
- TouchPointerEmulation(ev->any.type, dev, &mask);
+ for (i = 0; i < nevents; i++)
+ {
+ InternalEvent *event = (InternalEvent *)((emulationEvents + i)->event);
- if (ev->any.type == ET_TouchEnd)
- break;
+ event->device_event.flags |= XITouchPointer;
- ev++;
- if (ev == ti->history + ti->history_size)
- ev = ti->history;
- }
+ dev->public.processInputProc(
+ (InternalEvent*)((emulationEvents + i)->event), dev);
}
}
@@ -1396,11 +1620,8 @@ EmulateTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev)
* resource.
*/
static void
-DeliverTouchEvents(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
- InternalEvent *ev, XID resource)
+DeliverTouchEvents(TouchClientPtr client, InternalEvent *ev, DeviceIntPtr dev)
{
- SpritePtr sprite = &ti->sprite;
- DeviceIntPtr masterdev = sourcedev->u.master;
DeviceIntPtr deliverdev;
GrabPtr grab;
WindowPtr win;
@@ -1408,6 +1629,8 @@ DeliverTouchEvents(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
int i;
Bool ret;
+ ret = DeliverOneTouchEvent(clients[client], dev, ti, client->window, ev);
+
/* First, deliver to all grabbing clients, going from the root window down
* to the deepest child window. */
for (i = 0; i < sprite->spriteTraceGood; i++)
@@ -1629,6 +1852,166 @@ ProcessTouchOwnershipEvent(DeviceIntPtr sourcedev, TouchPointInfoPtr ti,
}
}
+void
+RemoveTouchPointerEvents()
+{
+ QdEventPtr qe;
+ QdEventPtr prev_qe = NULL;
+
+ for (qe = syncEvents.pending; qe; qe->next)
+ {
+ InternalEvent *ev = qe->event;
+
+ if ((ev->any.type == ET_ButtonPress ||
+ ev->any.type == ET_ButtonRelease ||
+ ev->any.type == ET_Motion) &&
+ (ev->device_event.flags & XITouchPointer))
+ {
+ if (prev_qe)
+ prev_qe->next = qe->next;
+ else
+ syncEvents.pending = qe->next;
+ free(qe);
+ }
+ else
+ prev_qe = qe;
+ }
+ syncEvents.pendtail = prev_qe;
+}
+
+Bool
+FindNextGrab(DevIntPtr dev, TouchPointInfoPtr ti, WindowPtr start_win)
+{
+ Bool seen_win = FALSE;
+ DeviceIntPtr master = dev->u.master;
+ InternalEvent p_event;
+ InternalEvent t_event;
+ int i, j;
+
+ if (dev->deviceGrab.grab)
+ return TRUE;
+
+ p_event->any.type == ET_ButtonPress;
+ t_event->any.type == ET_TouchBegin;
+
+ j = ti->owner;
+
+ for (i = 0; i < ti->sprite.spriteTraceGood; i++)
+ {
+ WindowPtr win = ti->sprite.spriteTrace[i];
+ TouchClientPtr client = ti->clients[j];
+
+ if (win == start_win)
+ seen_win = TRUE;
+ else if (!seen_win)
+ goto next;
+
+ if (win == client->window && client->type == TOUCH_GRAB)
+ {
+ client->device->deviceGrab.ActivateGrab(client->device,
+ client->grab,
+ currentTime, TRUE);
+ ti->owner = j;
+ return TRUE;
+ }
+
+ if (CheckPassiveGrabsOnWindow(win, dev, &p_event, TRUE,
+ TRUE) ||
+ (master && CheckPassiveGrabsOnWindow(win, master, &p_event, TRUE,
+ TRUE)))
+ return TRUE;
+
+next:
+ if (win == client->window)
+ j++;
+ }
+
+ return FALSE;
+}
+
+void
+ProcessTouchOwnership(DevIntPtr dev, TouchPointInfoPtr ti, uint8_t reason)
+{
+ Bool touch_grab = TRUE;
+
+ if (!ti) {
+ ti = dev->emulate_touch;
+ touch_grab = FALSE;
+ }
+
+ if (reason == XITouchOwnerAccept)
+ {
+ DeviceEvent event;
+ int i;
+
+ if (!touch_grab)
+ {
+ ti->active_clients = 0;
+ return;
+ }
+
+ init_event(client->device, &event, GetTimeInMillis());
+ event.type = ET_TouchEnd;
+ event.detail = ti->client_id;
+
+ for (i = ti->owner + 1; i < ti->active_clients; i++)
+ {
+ TouchClientPtr client = ti->clients[i];
+
+ if (client->type == TOUCH_GRAB ||
+ client->type == TOUCH_SELECT_UNOWNED)
+ {
+ event.deviceid = client->device->id;
+ event.sourceid = client->source->id;
+
+ DeliverOneTouchEvent(client, ti, (InternalEvent *)&ev);
+ }
+ }
+ ti->active_clients = ti->owner + 1;
+
+ RemoveTouchPointerEvents();
+ } else {
+ TouchClientPtr client = &ti->clients[ti->owner];
+
+ if (touch_grab)
+ {
+ DeviceIntPtr master = client->source->u.master;
+ DeviceEvent event;
+
+ init_event(client->device, &event, GetTimeInMillis());
+ event.type = ET_TouchEnd;
+ event.detail = ti->client_id;
+ event.deviceid = client->device->id;
+ event.sourceid = client->source->id;
+
+ DeliverOneTouchEvent(client, ti, (InternalEvent *)&ev);
+
+ ti->owner++;
+
+ dev->deviceGrab.DeactivateGrab(dev, FALSE);
+ }
+
+ if (ti->owner >= ti->active_clients)
+ ti->active_clients = 0;
+ else {
+ if (FindNextGrab(client->device, ti, client->window))
+ return;
+
+ client = &ti->clients[ti->owner];
+
+ if (client->type == TOUCH_SELECT_UNOWNED)
+ {
+ DeliverTouchOwnershipEvent(client, ti);
+ RemoveTouchPointerEvents();
+ }
+ else if (client->type == TOUCH_SELECT)
+ RemoveTouchPointerEvents();
+ else
+ ti->active_clients = 0;
+ }
+ }
+}
+
/**
* Processes and delivers a TouchBegin, TouchMotion, TouchMotionOwned, or a
* TouchEnd event.
@@ -1645,6 +2028,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr sourcedev)
TouchPointInfoPtr ti;
SpritePtr sprite;
uint32_t touchid;
+ Bool emulated = FALSE;
/* We handle deliveries to MDs through the SD, rather than copying
* the event and processing it twice. */
@@ -1690,10 +2074,7 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr sourcedev)
sourcedev->name, t->num_touches * 2);
}
- if (ev->any.type == ET_TouchOwnership)
- touchid = ev->touch_ownership_event.touchid;
- else
- touchid = ev->device_event.detail.touch;
+ touchid = ev->device_event.detail.touch;
ti = FindTouchPointByClientID(sourcedev, touchid);
if (!ti)
{
@@ -1701,35 +2082,92 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr sourcedev)
sourcedev->name, touchid);
return;
}
- sprite = &ti->sprite;
-
- /* We only send TouchEnd events when no client will ever receive any more
- * events from that touch stream. If there are still open grabs, just
- * set the PendingFinish flag until they've all accepted or rejected the
- * touch. */
- if (ev->any.type == ET_TouchEnd && ti->num_grabs > 0)
- {
- ev->any.type = ET_TouchMotion;
- ev->device_event.flags |= XITouchPendingFinish;
- ti->pending_finish = TRUE;
- }
/* Make sure we have a valid window trace for event delivery; must be
* called after event type mutation. */
- if (!EnsureTouchSprite(sourcedev, ti, ev))
+ if (!EnsureTouchClients(sourcedev, ti, ev))
+ {
+ EmulateTouchEvents(sourcedev, ti, ev);
return;
+ }
- /* TouchOwnership events are handled separately from the rest, as they
- * have more complex semantics. */
- if (ev->any.type == ET_TouchOwnership)
+ if (ev->any.type == ET_TouchBegin)
+ FindNextGrab(sourcedev, ti, ev->device_event.root);
+
+ client = &ti->clients[ti->owner];
+
+ if (client->type == TOUCH_GRAB)
{
- ProcessTouchOwnershipEvent(sourcedev, ti, &ev->touch_ownership_event);
+ if (ev->any.type == ET_TouchEnd)
+ {
+ ev->any.type = ET_TouchMotion;
+ ev->device_event.flags |= XITouchPendingFinish;
+ }
+
+ ev->device_event.deviceid = client->device;
+ ev->device_event.deviceid = client->source;
+
+ DeliverOneTouchEvent(client, ti, (InternalEvent *)ev);
+ if (ev->any.type == ET_TouchBegin && !client->device->deviceGrab.grab)
+ DeliverTouchOwnershipEvent(client, ti);
}
- else
+ else if (client->type == TOUCH_SELECT ||
+ client->type == TOUCH_SELECT_UNOWNED ||
+ client->type == POINTER_SELECT)
{
- DeliverTouchEvents(sourcedev, ti, (InternalEvent *) ev, 0);
- if (ev->any.type == ET_TouchEnd && ti->num_listeners == 0)
- EndTouchPoint(sourcedev, ti);
+ for (i = ti->owner; i < ti->active_clients; i++)
+ {
+ client = &ti->clients[ti->owner];
+
+ ev->device_event.deviceid = client->device;
+ ev->device_event.deviceid = client->source;
+
+ if (client->type == TOUCH_SELECT)
+ DeliverOneTouchEvent(client, ti, (InternalEvent *)ev);
+ else if (client->type == TOUCH_SELECT_UNOWNED)
+ {
+ DeliverOneTouchEvent(client, ti, (InternalEvent *)ev);
+ if (ev->any.type == ET_TouchBegin)
+ DeliverTouchOwnershipEvent(client, ti);
+ }
+ else
+ EmulateTouchEvents(sourcedev, ti, InternalEvent *ev);
+
+ return;
+ }
+ }
+ else if (client->type == POINTER_GRAB_SYNC ||
+ client->type == POINTER_GRAB_ASYNC)
+ {
+ EmulateTouchEvents(sourcedev, ti, InternalEvent *ev);
+ emulated = TRUE;
+ }
+
+ if (ev->any.type == ET_TouchMotion)
+ ev->any.type = ET_TouchMotionUnowned;
+ else if (ev->any.type == ET_TouchEnd ||
+ (ev->device_event.flags & XITouchPendingFinish))
+ {
+ ev->any.type = ET_TouchMotionUnowned;
+ ev->device_event.flags |= XITouchPendingFinish;
+ }
+
+ for (i = ti->owner + 1; i < ti->active_clients; i++)
+ {
+ TouchClientPtr client = &ti->clients[i];
+
+ ev->device_event.deviceid = client->device;
+ ev->device_event.deviceid = client->source;
+
+ if (client->type == TOUCH_GRAB ||
+ client->type == TOUCH_SELECT_UNOWNED)
+ DeliverOneTouchEvent(client, ti, (InternalEvent *)ev);
+ else if (!emulated && (client->type == POINTER_GRAB_SYNC ||
+ client->type == POINTER_GRAB_ASYNC))
+ {
+ EmulateTouchEvents(sourcedev, ti, InternalEvent *ev);
+ emulated = TRUE;
+ }
}
}
diff --git a/Xi/xiallowev.c b/Xi/xiallowev.c
index c7056efbe..eb2dfd761 100644
--- a/Xi/xiallowev.c
+++ b/Xi/xiallowev.c
@@ -181,15 +181,7 @@ ProcXIAllowTouchEvents(ClientPtr client)
return BadValue;
}
- nev = GetTouchOwnershipEvents(events, dev, ti, reason, ti->listeners[0], 0);
- if (nev == 0)
- return BadAlloc;
- for (i = 0; i < nev; i++)
- {
- ev = (InternalEvent *)((events + i)->event);
- mieqProcessDeviceEvent(dev, ev, NULL);
- }
- ProcessInputEvents();
+ ProcessTouchOwnership(dev, ti, reason);
return Success;
}
diff --git a/dix/events.c b/dix/events.c
index 733bf333f..d64b615d7 100644
--- a/dix/events.c
+++ b/dix/events.c
@@ -1287,8 +1287,12 @@ ComputeFreezes(void)
if (replayDev->focus && !IsPointerEvent((InternalEvent*)event))
DeliverFocusedEvent(replayDev, (InternalEvent*)event, w);
else
+ {
DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab,
NullWindow, replayDev);
+ if (event->flags & XITouchPointer)
+ ProcessTouchOwnership(replayDev, NULL, XITouchOwnerAccept);
+ }
}
}
for (dev = inputInfo.devices; dev; dev = dev->next)
@@ -1488,6 +1492,7 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
DeviceIntPtr dev;
Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab &&
mouse->deviceGrab.implicitGrab);
+ QdEventPtr qe;
mouse->valuator->motionHintWindow = NullWindow;
mouse->deviceGrab.grab = NullGrab;
@@ -1510,6 +1515,25 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
if (!wasImplicit && grab->grabtype == GRABTYPE_XI2)
ReattachToOldMaster(mouse);
+ for (qe = syncEvents.pending; qe; qe = qe->next)
+ {
+ if ((qe->event->any.type == ET_ButtonPress ||
+ qe->event->any.type == ET_ButtonRelease ||
+ qe->event->any.type == ET_Motion) &&
+ (qe->event->device_event.flags & XITouchPointer))
+ {
+ ProcessTouchOwnership(mouse, NULL, XITouchOwnerReject);
+ return;
+ }
+ }
+
+ if (mouse->touch)
+ {
+ ProcessTouchOwnership(mouse, NULL, XITouchOwnerReject);
+ if (mouse->deviceGrab.grab)
+ return;
+ }
+
ComputeFreezes();
}
diff --git a/include/inputstr.h b/include/inputstr.h
index bdab35884..e3c9fd7bd 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -289,13 +289,33 @@ typedef struct _ValuatorClassRec {
ValuatorAccelerationRec accelScheme;
} ValuatorClassRec, *ValuatorClassPtr;
+typedef enum {
+ TOUCH_GRAB,
+ TOUCH_SELECT,
+ TOUCH_SELECT_UNOWNED,
+ POINTER_GRAB_SYNC,
+ POINTER_GRAB_ASYNC,
+ POINTER_SELECT
+} TouchClientType;
+
+typedef struct _TouchClientRec {
+ ClientPtr client;
+ WindowPtr window;
+ TouchClientType type;
+ DeviceIntPtr device;
+ DeviceIntPtr source;
+ GrabPtr grab;
+} TouchClientRec, *TouchClientPtr;
+
typedef struct _TouchPointInfo {
Bool active; /* whether or not the touch is active */
Bool pending_finish; /* true if the touch is physically inactive
* but still owned by a grab */
uint32_t client_id; /* touch ID as seen in client events */
uint32_t ddx_id; /* touch ID given by the DDX */
- SpriteRec sprite; /* window trace for delivery */
+ TouchClientPtr clients;
+ int num_clients;
+ int active_clients;
int *valuators; /* last recorded axis values */
int num_valuators; /* == TouchClassInfo::num_axes */
XID *listeners; /* grabs/event selection IDs receiving
@@ -513,7 +533,8 @@ typedef struct _GrabInfoRec {
TimeStamp /*time*/,
Bool /*autoGrab*/);
void (*DeactivateGrab)(
- DeviceIntPtr /*device*/);
+ DeviceIntPtr /*device*/,
+ Bool /* computeFreezes */);
struct {
Bool frozen;
int state;