diff options
author | 2011-10-29 21:43:27 +0200 | |
---|---|---|
committer | 2011-10-29 21:43:27 +0200 | |
commit | c920e8daaa4a4a4a601f606eaa4764750fe80639 (patch) | |
tree | 6ee77ae8a68b6a41965a39bdef398543731d3b35 /x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch | |
parent | Update patch with latest nathy release (diff) | |
download | sabotageandi-c920e8daaa4a4a4a601f606eaa4764750fe80639.tar.gz sabotageandi-c920e8daaa4a4a4a601f606eaa4764750fe80639.tar.bz2 sabotageandi-c920e8daaa4a4a4a601f606eaa4764750fe80639.zip |
update versions
Diffstat (limited to 'x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch')
-rw-r--r-- | x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch | 4603 |
1 files changed, 4603 insertions, 0 deletions
diff --git a/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch new file mode 100644 index 0000000..26be6ef --- /dev/null +++ b/x11-base/xorg-server/files/xorg-server-1.10.4-r2-xi2.1.patch @@ -0,0 +1,4603 @@ +Index: xorg-server/Xi/allowev.c +=================================================================== +--- xorg-server.orig/Xi/allowev.c 2011-08-24 12:52:43.965647120 +0300 ++++ xorg-server/Xi/allowev.c 2011-08-24 12:56:49.845650625 +0300 +@@ -125,5 +125,24 @@ + client->errorValue = stuff->mode; + return BadValue; + } ++ ++ /* If this is a master pointer with an active touch emulation and the touch ++ * has physically ceased, end the touchpoint state. */ ++ if (thisdev->emulate_dev) ++ { ++ DeviceIntPtr sourcedev = thisdev->emulate_dev; ++ TouchPointInfoPtr ti = sourcedev->touch->emulate; ++ ++ if (ti->pending_finish && ti->owner < 0) ++ EndTouchPoint(sourcedev, ti); ++ else if (ti->pending_finish) ++ { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED) ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ + return Success; + } +Index: xorg-server/Xi/exevents.c +=================================================================== +--- xorg-server.orig/Xi/exevents.c 2011-08-24 12:56:49.835650626 +0300 ++++ xorg-server/Xi/exevents.c 2011-08-24 12:56:49.855650623 +0300 +@@ -44,6 +44,31 @@ + + ********************************************************/ + ++/* ++ * Copyright © 2010 Collabora Ltd. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Author: Daniel Stone <daniel@fooishbar.org> ++ */ ++ + /******************************************************************** + * + * Routines to register and initialize extension input devices. +@@ -77,6 +102,9 @@ + #include "xiquerydevice.h" /* For List*Info */ + #include "eventconvert.h" + #include "eventstr.h" ++#include "xserver-properties.h" ++#include "inpututils.h" ++#include "mi.h" + + #include <X11/extensions/XKBproto.h> + #include "xkbsrv.h" +@@ -127,6 +155,20 @@ + return FALSE; + } + ++Bool ++IsTouchEvent(InternalEvent* event) ++{ ++ switch(event->any.type) ++ { ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ return TRUE; ++ default: ++ return FALSE; ++ } ++} ++ + /** + * @return the device matching the deviceid of the device set in the event, or + * NULL if the event is not an XInput event. +@@ -722,6 +764,46 @@ + XISendDeviceChangedEvent(slave, device, dce); + } + ++#define DEFAULT 0 ++#define DONT_PROCESS 1 ++int ++ReleaseButton(DeviceIntPtr device, int button) ++{ ++ ButtonClassPtr b = device->button; ++ int i; ++ ++ if (IsMaster(device)) { ++ DeviceIntPtr sd; ++ ++ /* ++ * Leave the button down if any slave has the ++ * button still down. Note that this depends on the ++ * event being delivered through the slave first ++ */ ++ for (sd = inputInfo.devices; sd; sd = sd->next) { ++ if (IsMaster(sd) || sd->u.master != device) ++ continue; ++ if (!sd->button) ++ continue; ++ for (i = 1; i <= sd->button->numButtons; i++) ++ if (sd->button->map[i] == button && ++ button_is_down(sd, i, BUTTON_PROCESSED)) ++ return DONT_PROCESS; ++ } ++ } ++ set_button_up(device, button, BUTTON_PROCESSED); ++ if (device->valuator) ++ device->valuator->motionHintWindow = NullWindow; ++ if (!b->map[button]) ++ return DONT_PROCESS; ++ if (b->buttonsDown >= 1 && !--b->buttonsDown) ++ b->motionMask = 0; ++ if (b->map[button] <= 5) ++ b->state &= ~((Button1Mask >> 1) << b->map[button]); ++ ++ return DEFAULT; ++} ++ + /** + * Update the device state according to the data in the event. + * +@@ -729,8 +811,6 @@ + * DEFAULT ... process as normal + * DONT_PROCESS ... return immediately from caller + */ +-#define DEFAULT 0 +-#define DONT_PROCESS 1 + int + UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event) + { +@@ -854,34 +934,9 @@ + + if (!button_is_down(device, key, BUTTON_PROCESSED)) + return DONT_PROCESS; +- if (IsMaster(device)) { +- DeviceIntPtr sd; + +- /* +- * Leave the button down if any slave has the +- * button still down. Note that this depends on the +- * event being delivered through the slave first +- */ +- for (sd = inputInfo.devices; sd; sd = sd->next) { +- if (IsMaster(sd) || sd->u.master != device) +- continue; +- if (!sd->button) +- continue; +- for (i = 1; i <= sd->button->numButtons; i++) +- if (sd->button->map[i] == key && +- button_is_down(sd, i, BUTTON_PROCESSED)) +- return DONT_PROCESS; +- } +- } +- set_button_up(device, key, BUTTON_PROCESSED); +- if (device->valuator) +- device->valuator->motionHintWindow = NullWindow; +- if (!b->map[key]) ++ if (ReleaseButton(device, key) == DONT_PROCESS) + return DONT_PROCESS; +- if (b->buttonsDown >= 1 && !--b->buttonsDown) +- b->motionMask = 0; +- if (b->map[key] <= 5) +- b->state &= ~((Button1Mask >> 1) << b->map[key]); + + /* Add state and motionMask to the filter for this event */ + mask = DevicePointerMotionMask | b->state | b->motionMask; +@@ -897,6 +952,955 @@ + } + + /** ++ * Add a touch client to the list of clients for the touch point. Return TRUE ++ * if the caller should stop processing touch clients. ++ */ ++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) ++ { ++ int num_clients = ti->num_clients ? ti->num_clients * 2 : 2; ++ ++ TouchClientPtr tmp; ++ tmp = realloc(ti->clients, num_clients * sizeof(TouchClientRec)); ++ ++ if (tmp) ++ { ++ ti->clients = tmp; ++ ti->num_clients = num_clients; ++ } 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 FALSE; ++} ++ ++/** ++ * Ensure a list of clients for a touchpoint, constructing one for TouchBegin ++ * events. Returns TRUE if a touch client exists, FALSE if none. ++ */ ++static Bool ++EnsureTouchClients(DeviceIntPtr sourcedev, TouchPointInfoPtr ti, ++ InternalEvent *ev) ++{ ++ TouchClassPtr t = sourcedev->touch; ++ SpritePtr sprite = &ti->sprite; ++ DeviceIntPtr masterdev = sourcedev->u.master; ++ int i; ++ ++ if (ev->any.type != ET_TouchBegin) ++ return (ti->active_clients > 0); ++ ++ if (ti->active_clients > 0) ++ LogMessage(X_ERROR, "Getting touch clients for active touch\n"); ++ ++ /* Create sprite trace for the touchpoint */ ++ if (t->mode == XIDirectTouch) ++ { ++ /* Focus immediately under the touchpoint in direct touch mode. ++ * XXX: Do we need to handle crossing screens here? */ ++ sprite->spriteTrace[0] = ++ sourcedev->spriteInfo->sprite->hotPhys.pScreen->root; ++ XYToWindow(sprite, ev->device_event.root_x, ev->device_event.root_y); ++ } ++ else ++ { ++ WindowPtr *trace; ++ SpritePtr srcsprite; ++ ++ /* Find and reuse an existing, physically active touch's sprite and ++ * touch client list if possible, else use the device's pointer sprite ++ * and generate a new list of touch clients. */ ++ for (i = 0; i < t->num_touches; i++) ++ if (!t->touches[i].ddx_pending_finish && ++ t->touches[i].active_clients > 0) ++ break; ++ 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; ++ ti->owner = -1; ++ 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; ++ 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; ++ ti->owner = -1; ++ return FALSE; ++ } ++ sprite->spriteTrace = trace; ++ sprite->spriteTraceSize = srcsprite->spriteTraceGood; ++ } ++ 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; ++ ++ /* Search for touch grab clients from root to child windows. */ ++ for (i = 0; i < sprite->spriteTraceGood; i++) ++ { ++ WindowPtr win = sprite->spriteTrace[i]; ++ GrabPtr grab; ++ InternalEvent ev; ++ ++ 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; ++ } ++ } ++ ++ /* Search for one touch select client from child to root windows. */ ++ for (i = sprite->spriteTraceGood - 1; i >= 0; i--) ++ { ++ WindowPtr win = sprite->spriteTrace[i]; ++ OtherInputMasks *inputMasks = wOtherInputMasks(win); ++ ++ /* Is anyone listening for unowned events on this window? */ ++ if (inputMasks && ++ (BitIsOn(inputMasks->xi2mask[XIAllDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputMasks->xi2mask[sourcedev->id], ++ XI_TouchUpdateUnowned) || ++ (masterdev && ++ (BitIsOn(inputMasks->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputMasks->xi2mask[masterdev->id], ++ XI_TouchUpdateUnowned))))) ++ { ++ InputClientsPtr inputClients = inputMasks->inputClients; ++ ++ /* Find the one client listening for unowned events. */ ++ for (inputClients = inputMasks->inputClients; ++ inputClients; ++ inputClients = inputClients->next) ++ { ++ if (BitIsOn(inputClients->xi2mask[XIAllDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputClients->xi2mask[sourcedev->id], ++ XI_TouchUpdateUnowned)) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), ++ win, TOUCH_SELECT_UNOWNED, sourcedev, ++ sourcedev, NULL); ++ goto done; ++ } ++ else if (masterdev && ++ (BitIsOn(inputClients->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdateUnowned) || ++ BitIsOn(inputClients->xi2mask[masterdev->id], ++ XI_TouchUpdateUnowned))) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), ++ win, TOUCH_SELECT_UNOWNED, masterdev, ++ sourcedev, NULL); ++ goto done; ++ } ++ } ++ } ++ ++ /* Is anyone listening for only owned events on this window? */ ++ if (inputMasks && ++ (BitIsOn(inputMasks->xi2mask[XIAllDevices], XI_TouchUpdate) || ++ BitIsOn(inputMasks->xi2mask[sourcedev->id], XI_TouchUpdate) || ++ (masterdev && ++ (BitIsOn(inputMasks->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdate) || ++ BitIsOn(inputMasks->xi2mask[masterdev->id], ++ XI_TouchUpdate))))) ++ { ++ InputClientsPtr inputClients = inputMasks->inputClients; ++ ++ /* Find the one client listening for owned events. */ ++ for (inputClients = inputMasks->inputClients; ++ inputClients; ++ inputClients = inputClients->next) ++ { ++ if (BitIsOn(inputClients->xi2mask[XIAllDevices], ++ XI_TouchUpdate) || ++ BitIsOn(inputClients->xi2mask[sourcedev->id], ++ XI_TouchUpdate)) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), win, ++ TOUCH_SELECT, sourcedev, sourcedev, NULL); ++ goto done; ++ } ++ else if (masterdev && ++ (BitIsOn(inputClients->xi2mask[XIAllMasterDevices], ++ XI_TouchUpdate) || ++ BitIsOn(inputClients->xi2mask[masterdev->id], ++ XI_TouchUpdate))) ++ { ++ AddTouchClient(ti, CLIENT_ID(inputClients->resource), win, ++ TOUCH_SELECT, masterdev, sourcedev, NULL); ++ goto done; ++ } ++ } ++ } ++ } ++ ++done: ++ return (ti->active_clients > 0); ++} ++ ++/** ++ * Attempts to deliver a touch event to the given client. ++ */ ++static Bool ++DeliverOneTouchEvent(TouchClientPtr client, TouchPointInfoPtr ti, ++ InternalEvent *ev) ++{ ++ int err; ++ xEvent *xi2; ++ Mask filter; ++ Window child = DeepestSpriteWin(&ti->sprite)->drawable.id; ++ ++ /* If we fail here, we're going to leave a client hanging. */ ++ err = EventToXI2(ev, &xi2); ++ if (err != Success) ++ FatalError("[Xi] %s: XI2 conversion failed in DeliverOneTouchEvent" ++ " (%d)\n", client->device->name, err); ++ ++ 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->client, client->device, xi2, 1, filter, ++ filter, NullGrab); ++ free(xi2); ++ ++ /* Returning the value from TryClientEvents isn't useful, since all our ++ * resource-gone cleanups will update the delivery list anyway. */ ++ return TRUE; ++} ++ ++/** ++ * Deliver touch ownership event directly to client. ++ */ ++int ++DeliverTouchOwnershipEvent(TouchClientPtr client, TouchPointInfoPtr ti) ++{ ++ 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; ++} ++ ++/* Add the given event to the history for the touch point. */ ++static void ++UpdateTouchHistory(TouchPointInfoPtr ti, InternalEvent *ev) ++{ ++ /* Copy begin events off to the side. This prevents the ring buffer ++ overrunning and erasing the begin event. */ ++ if (ev->any.type == ET_TouchBegin) ++ memcpy(ti->begin_event, ev, sizeof(InternalEvent)); ++ else ++ { ++ memcpy(ti->next_history, ev, sizeof(InternalEvent)); ++ ++ ti->next_history++; ++ if (ti->next_history == ti->history + ti->history_size) ++ ti->next_history = ti->history; ++ ++ /* If the ring overruns, advance the first pointer so we keep as many ++ events as possible. */ ++ if (ti->next_history == ti->first_history) ++ { ++ ti->first_history++; ++ if (ti->first_history == ti->history + ti->history_size) ++ ti->first_history = ti->history; ++ } ++ } ++} ++ ++/** ++ * Helper to get a static EventList for pointer emulation. ++ */ ++static EventList * ++GetEvents(void) ++{ ++ static EventList *events = NULL; ++ ++ /* Allocate twice the maximum number of events for motion and button ++ * emulation. */ ++ if (!events) ++ events = InitEventList(2 * GetMaximumEventsNum()); ++ ++ return events; ++} ++ ++/* Helper function to set up touch pointer emulation. */ ++static void ++SetTouchEmulationMask(InternalEvent *ev, ValuatorMask *mask, int x_axis, ++ int y_axis) ++{ ++ valuator_mask_zero(mask); ++ if (BitIsOn(ev->device_event.valuators.mask, x_axis)) ++ valuator_mask_set(mask, 0, ++ ev->device_event.valuators.data[x_axis]); ++ if (BitIsOn(ev->device_event.valuators.mask, y_axis)) ++ valuator_mask_set(mask, 1, ++ ev->device_event.valuators.data[y_axis]); ++} ++ ++/* Process touch emulation. */ ++static void ++EmulateTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti, InternalEvent *ev) ++{ ++ EventList *emulationEvents = GetEvents(); ++ ValuatorMask mask; ++ InternalEvent mevent; ++ DeviceIntPtr master = dev->u.master; ++ enum EventType evtype = ev->any.type; ++ int nevents = 0; ++ int x_axis = dev->touch->x_axis; ++ int y_axis = dev->touch->y_axis; ++ int i; ++ ++ /* Set the emulation touch for the device. Only one touch may be emulated ++ * at a time. */ ++ if (dev->touch->emulate != ti) ++ return; ++ ++ /* Emulate a normal event. */ ++ SetTouchEmulationMask(ev, &mask, x_axis, y_axis); ++ ++ 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); ++ } ++ ++ if (ti->emulate_pointer) ++ { ++ for (i = 0; i < nevents; i++) ++ { ++ InternalEvent *event = (InternalEvent *)((emulationEvents + i)->event); ++ ++ event->device_event.flags |= XIPointerEmulated; ++ event->device_event.touchpoint = ev->device_event.touchpoint; ++ ++ if (master) ++ { ++ master->u.lastSlave = dev; ++ ++ CopyGetMasterEvent(dev, event, &mevent); ++ ++ /* If a grab has been activated but no event has been handled ++ * yet, then the grab is a touch grab. Store the pointer ++ * emulation event for now, ready for replay when the touch grab ++ * is relinquished. */ ++ if (master->deviceGrab.sync.state == FROZEN_NO_EVENT) ++ { ++ GrabInfoPtr grabinfo = &master->deviceGrab; ++ ++ grabinfo->sync.state = FROZEN_WITH_EVENT; ++ if (!grabinfo->sync.event) ++ grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); ++ *grabinfo->sync.event = event->device_event; ++ } ++ else ++ master->public.processInputProc(&mevent, master); ++ } ++ } ++ } ++ ++ /* If there are touch clients on a pointer emulated touchpoint, send touch ++ * events through traditional device processing as well. */ ++ if (master && ti->active_clients > 0 && ++ (ev->any.type != ET_TouchEnd || ++ (ti->clients[ti->active_clients - 1].type == TOUCH_SELECT || ++ ti->clients[ti->active_clients - 1].type == TOUCH_SELECT_UNOWNED))) ++ { ++ ev->device_event.flags |= XIPointerEmulated; ++ master->u.lastSlave = dev; ++ CopyGetMasterEvent(dev, ev, &mevent); ++ master->process_touch = TRUE; ++ master->public.processInputProc(&mevent, master); ++ master->process_touch = FALSE; ++ ++ /* If grabbed by an implicit touch grab from FindFirstGrab, release it ++ * now. */ ++ if (master->deviceGrab.grab && ++ master->deviceGrab.grab->type == ET_TouchBegin && ++ master->deviceGrab.implicitGrab) ++ master->deviceGrab.DeactivateGrab(master); ++ } ++} ++ ++#define ImplicitGrabMask (1 << 7) ++/** ++ * Find the first grab of a new touchpoint. Returns TRUE if a grab was found. ++ */ ++static Bool ++FindFirstGrab(DeviceIntPtr dev, TouchPointInfoPtr ti) ++{ ++ DeviceIntPtr master = dev->u.master; ++ InternalEvent p_event; ++ InternalEvent t_event; ++ GrabRec tempGrab; ++ int i, j; ++ ++ p_event.any.type = ET_ButtonPress; ++ t_event.any.type = ET_TouchBegin; ++ ++ j = ti->owner >= 0 ? ti->owner : 0; ++ ++ for (i = 0; i < ti->sprite.spriteTraceGood; i++) ++ { ++ WindowPtr win = ti->sprite.spriteTrace[i]; ++ TouchClientPtr client = &ti->clients[j]; ++ GrabPtr grab; ++ ++ /* If master pointer is already grabbed, bypass touch grabs above. */ ++ if (ti->emulate_pointer && master->deviceGrab.grab) ++ { ++ if (win == master->deviceGrab.grab->window) ++ { ++ if (j >= ti->active_clients - 1) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } else ++ ti->owner = j + 1; ++ return TRUE; ++ } else ++ goto next; ++ } ++ ++ /* Check for a touch grab on this window. */ ++ if (j < ti->active_clients && win == client->window && ++ client->type == TOUCH_GRAB) ++ { ++ client->device->deviceGrab.ActivateGrab(client->device, ++ client->grab, currentTime, ++ TRUE); ++ ti->owner = j; ++ return TRUE; ++ } ++ ++ if (!ti->emulate_pointer) ++ goto next; ++ ++ /* Check for a passive pointer grab on this window. */ ++ grab = CheckPassiveGrabsOnWindow(win, dev, &p_event, TRUE, FALSE); ++ if (grab) ++ { ++ if (grab->pointerMode == GrabModeAsync) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } ++ ++ return TRUE; ++ } ++ else if (master) ++ { ++ grab = CheckPassiveGrabsOnWindow(win, master, &p_event, TRUE, ++ FALSE); ++ if (grab) ++ { ++ if (grab->pointerMode == GrabModeAsync) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } ++ ++ return TRUE; ++ } ++ } ++ ++next: ++ if (j < ti->active_clients && win == client->window) ++ j++; ++ } ++ ++ /* Even when there's no grabbing clients, we need to sync events so we can ++ * properly check for touch vs pointer selection in DeliverDeviceEvents. ++ * Create a temporary implicit touch grab here, and deactivate it after ++ * enqueuing emulated pointer events. */ ++ if (ti->emulate_pointer) ++ { ++ memset(&tempGrab, 0, sizeof(GrabRec)); ++ tempGrab.next = NULL; ++ tempGrab.device = master; ++ tempGrab.resource = 0; ++ tempGrab.window = ti->sprite.spriteTrace[0]; ++ tempGrab.ownerEvents = FALSE; ++ tempGrab.eventMask = 0; ++ tempGrab.keyboardMode = GrabModeAsync; ++ tempGrab.pointerMode = GrabModeSync; ++ tempGrab.confineTo = NullWindow; ++ tempGrab.cursor = NullCursor; ++ tempGrab.type = ET_TouchBegin; ++ tempGrab.grabtype = GRABTYPE_XI2; ++ tempGrab.deviceMask = 0; ++ ++ master->deviceGrab.ActivateGrab(master, &tempGrab, currentTime, ++ TRUE | ImplicitGrabMask); ++ } ++ ++ return FALSE; ++} ++ ++void ++ProcessTouchOwnership(DeviceIntPtr dev, TouchPointInfoPtr ti, uint8_t reason, ++ Bool touch_grab) ++{ ++ DeviceIntPtr sourcedev = ti->source; ++ DeviceIntPtr masterdev; ++ ++ masterdev = dev->u.master; ++ ++ if (reason == XITouchOwnerAccept) ++ { ++ TouchClientPtr client; ++ DeviceEvent event; ++ int i; ++ ++ init_event(dev, &event, GetTimeInMillis()); ++ event.type = ET_TouchEnd; ++ event.detail.touch = ti->client_id; ++ event.touchpoint = ti; ++ ++ for (i = ti->owner + 1; i < ti->active_clients; i++) ++ { ++ 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 *)&event); ++ } ++ } ++ ++ if (!touch_grab) ++ { ++ ti->active_clients = 0; ++ ti->owner = -1; ++ RemoveTouchEventsFromQueue(masterdev, TRUE, FALSE); ++ return; ++ } ++ ++ client = &ti->clients[ti->owner]; ++ ti->active_clients = ti->owner + 1; ++ ti->accepted = TRUE; ++ ++ RemoveTouchEventsFromQueue(masterdev, FALSE, FALSE); ++ RemoveTouchEventsFromQueue(masterdev, TRUE, FALSE); ++ ReleaseButton(masterdev, 1); ++ ++ if (ti->emulate_pointer) ++ masterdev->deviceGrab.DeactivateGrab(masterdev); ++ ++ ti->emulate_pointer = FALSE; ++ ++ if (ti->pending_finish) ++ { ++ event.deviceid = client->device->id; ++ event.sourceid = client->source->id; ++ ++ DeliverOneTouchEvent(client, ti, (InternalEvent *)&event); ++ EndTouchPoint(sourcedev, ti); ++ } ++ } else { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ GrabPtr grab = masterdev->deviceGrab.grab; ++ ++ if (touch_grab) ++ { ++ DeviceEvent event; ++ ++ tc = &ti->clients[ti->owner]; ++ ++ init_event(tc->device, &event, GetTimeInMillis()); ++ event.type = ET_TouchEnd; ++ event.detail.touch = ti->client_id; ++ event.deviceid = tc->device->id; ++ event.sourceid = tc->source->id; ++ event.touchpoint = ti; ++ ++ DeliverOneTouchEvent(tc, ti, (InternalEvent *)&event); ++ ++ ti->owner++; ++ } ++ ++ if (ti->owner >= ti->active_clients) ++ { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ tc = NULL; ++ } else { ++ tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT && !ti->emulate_pointer) ++ { ++ InternalEvent *ev; ++ Bool ret; ++ ++ /* Deliver the saved touch begin event. */ ++ ret = DeliverOneTouchEvent(tc, ti, ti->begin_event); ++ ++ /* Deliver all the touch motion events in the ring buffer. */ ++ ev = ti->first_history; ++ while (ret && ev != ti->next_history) ++ { ++ ret = DeliverOneTouchEvent(tc, ti, ev); ++ ++ if (ev->any.type == ET_TouchEnd) ++ { ++ ti->pending_finish = TRUE; ++ break; ++ } ++ ++ ev++; ++ if (ev == ti->history + ti->history_size) ++ ev = ti->history; ++ } ++ } else if (tc->type == TOUCH_SELECT_UNOWNED && ++ !ti->emulate_pointer) { ++ DeliverTouchOwnershipEvent(tc, ti); ++ } ++ } ++ ++ if (ti->emulate_pointer) ++ { ++ if (ti->active_clients && ++ ti->clients[ti->owner].type == TOUCH_SELECT_UNOWNED) ++ RemoveTouchEventsFromQueue(masterdev, TRUE, TRUE); ++ ++ syncEvents.replayDev = masterdev; ++ if (touch_grab) ++ syncEvents.replayWin = grab->window->parent; ++ else ++ syncEvents.replayWin = grab->window; ++ masterdev->deviceGrab.DeactivateGrab(masterdev); ++ syncEvents.replayDev = NULL; ++ } ++ ++ if (ti->pending_finish && ++ (!tc || (tc->type == TOUCH_SELECT || ++ tc->type == TOUCH_SELECT_UNOWNED)) && ++ (!ti->emulate_pointer || !masterdev->deviceGrab.grab)) ++ EndTouchPoint(sourcedev, ti); ++ } ++} ++ ++/** ++ * Processes and delivers a TouchBegin, TouchMotion, or a TouchEnd event. ++ * ++ * Due to having rather different delivery semantics (see the Xi 2.1 protocol ++ * spec for more information), this implements its own grab and event-selection ++ * delivery logic. ++ */ ++static void ++ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr sourcedev) ++{ ++ DeviceIntPtr masterdev = sourcedev->u.master; ++ TouchClassPtr t = sourcedev->touch; ++ TouchPointInfoPtr ti; ++ TouchClientPtr client; ++ uint32_t touchid; ++ int i; ++ ++ /* We handle deliveries to MDs through the SD, rather than copying ++ * the event and processing it twice. */ ++ if (IsMaster(sourcedev)) ++ return; ++ ++ if (!t) ++ return; ++ ++ /* If we hit 50% utilization of touches, double the number of touch ++ * frames. */ ++ if (t->active_touches > t->num_touches / 2) ++ { ++ void *tmp; ++ ++ tmp = realloc(t->touches, (t->num_touches * 2) * sizeof(*t->touches)); ++ if (tmp) ++ { ++ t->touches = tmp; ++ memset(t->touches + t->num_touches, 0, ++ t->num_touches * sizeof(*t->touches)); ++ ++ for (i = t->num_touches; i < t->num_touches * 2; i++) ++ { ++ if (!InitTouchPoint(t, i)) ++ { ++ LogMessage(X_ERROR, ++ "%s: failed to initialize new touchpoint %d\n", ++ sourcedev->name, i); ++ break; ++ } ++ } ++ t->num_touches = i; ++ ++ LogMessage(X_INFO, "%s: reallocated %d touches\n", sourcedev->name, ++ t->num_touches); ++ } else ++ LogMessage(X_ERROR, "%s: failed to allocate more touches (%d)\n", ++ sourcedev->name, t->num_touches * 2); ++ } ++ ++ touchid = ev->device_event.detail.touch; ++ ti = FindTouchPointByClientID(sourcedev, touchid); ++ if (!ti) ++ { ++ DebugF("[Xi] %s: Received event for inactive touchpoint %d\n", ++ sourcedev->name, touchid); ++ return; ++ } ++ ++ /* Set the emulation touch for a direct touch device. Only one touch may be ++ * emulated per master device at a time. */ ++ if (ev->any.type == ET_TouchBegin && t->mode == XIDirectTouch && ++ masterdev && !masterdev->emulate_dev) ++ { ++ ti->emulate_pointer = TRUE; ++ sourcedev->touch->emulate = ti; ++ masterdev->emulate_dev = sourcedev; ++ } ++ ++ /* Make sure we have a valid list of touch clients for event delivery. */ ++ if (!EnsureTouchClients(sourcedev, ti, ev)) ++ { ++ /* No touch clients, so only attempt to emulate a pointer. */ ++ EmulateTouchEvents(sourcedev, ti, ev); ++ ++ if (ti->active && ev->any.type == ET_TouchEnd) ++ EndTouchPoint(sourcedev, ti); ++ ++ return; ++ } ++ ++ if (ev->any.type == ET_TouchBegin) ++ { ++ if (ti->emulate_pointer) ++ { ++ if (!FindFirstGrab(sourcedev, ti)) ++ { ++ if (ti->clients[0].type == TOUCH_SELECT) ++ { ++ ti->owner = 0; ++ EmulateTouchEvents(sourcedev, ti, ev); ++ return; ++ } ++ else if (ti->clients[0].type == TOUCH_SELECT_UNOWNED) ++ { ++ ti->owner = 0; ++ client = &ti->clients[ti->owner]; ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ DeliverOneTouchEvent(client, ti, ev); ++ EmulateTouchEvents(sourcedev, ti, ev); ++ return; ++ } ++ } else if (ti->owner < 0) ++ /* Pointer grab found, check touch grab first when replayed. */ ++ ev->device_event.check_grab = TRUE; ++ } ++ else ++ ti->owner = 0; ++ } ++ ++ /* Update touch history for non-emulated touches. Emulated touch history is ++ * maintained in syncEvents queue. */ ++ if (!ti->emulate_pointer && !ti->accepted) ++ UpdateTouchHistory(ti, ev); ++ ++ EmulateTouchEvents(sourcedev, ti, ev); ++ ++ if (ti->owner >= 0) ++ client = &ti->clients[ti->owner]; ++ ++ /* Handle the special case where we are ending an emulated touch during an ++ * active pointer grab. */ ++ if (ti == t->emulate && masterdev && masterdev->deviceGrab.grab && ++ !masterdev->deviceGrab.fromPassiveGrab && ++ !masterdev->deviceGrab.implicitGrab && ev->any.type == ET_TouchEnd) ++ { ++ InternalEvent mevent; ++ ++ ev->device_event.flags |= XIPointerEmulated; ++ ++ masterdev->u.lastSlave = sourcedev; ++ CopyGetMasterEvent(sourcedev, ev, &mevent); ++ masterdev->process_touch = TRUE; ++ masterdev->public.processInputProc(&mevent, masterdev); ++ masterdev->process_touch = FALSE; ++ if (client && (client->type == TOUCH_SELECT || ++ client->type == TOUCH_SELECT_UNOWNED)) ++ EndTouchPoint(sourcedev, ti); ++ } ++ ++ /* If a touch is owned, deliver to the owning client. */ ++ if (ti->owner >= 0 && ++ (ti != t->emulate || ti->accepted || ++ ((!client->grab && !sourcedev->deviceGrab.grab && ++ !masterdev->deviceGrab.grab) || ++ (client->grab && sourcedev->deviceGrab.grab && ++ GrabMatchesSecond(sourcedev->deviceGrab.grab, client->grab, FALSE)) || ++ (client->grab && masterdev && masterdev->deviceGrab.grab && ++ GrabMatchesSecond(masterdev->deviceGrab.grab, client->grab, FALSE))))) ++ { ++ if (client->type == TOUCH_GRAB) ++ { ++ /* Mutate end event to a pending finish event for further ++ * clients. */ ++ if (ev->any.type == ET_TouchEnd && !ti->accepted) ++ { ++ ev->any.type = ET_TouchMotion; ++ ev->device_event.flags |= XITouchPendingEnd; ++ ti->pending_finish = TRUE; ++ } ++ ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ ++ DeliverOneTouchEvent(client, ti, ev); ++ if (ev->any.type == ET_TouchBegin) ++ DeliverTouchOwnershipEvent(client, ti); ++ else if (ev->any.type == ET_TouchEnd) ++ EndTouchPoint(sourcedev, ti); ++ } ++ else if (client->type == TOUCH_SELECT || ++ client->type == TOUCH_SELECT_UNOWNED) ++ { ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ ++ if (ev->any.type != ET_TouchEnd) ++ DeliverOneTouchEvent(client, ti, ev); ++ ++ else if (client->type == TOUCH_SELECT_UNOWNED && ++ ev->any.type == ET_TouchBegin) ++ DeliverTouchOwnershipEvent(client, ti); ++ ++ /* An ending emulated touchpoint must release the primary mouse ++ * button. */ ++ if (ev->any.type == ET_TouchEnd) ++ { ++ if (ti == sourcedev->touch->emulate) ++ ReleaseButton(masterdev, 1); ++ else ++ DeliverOneTouchEvent(client, ti, ev); ++ ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ } ++ ++ /* Deliver to non-owners. */ ++ if (ev->any.type == ET_TouchMotion) ++ ev->any.type = ET_TouchMotionUnowned; ++ else if (ev->any.type == ET_TouchEnd) ++ { ++ ev->any.type = ET_TouchMotionUnowned; ++ ev->device_event.flags |= XITouchPendingEnd; ++ ti->pending_finish = TRUE; ++ } ++ ++ for (i = ti->owner + 1; i < ti->active_clients; i++) ++ { ++ TouchClientPtr client = &ti->clients[i]; ++ ++ ev->device_event.deviceid = client->device->id; ++ ev->device_event.sourceid = client->source->id; ++ ++ if (client->type == TOUCH_GRAB || ++ client->type == TOUCH_SELECT_UNOWNED) ++ DeliverOneTouchEvent(client, ti, ev); ++ } ++} ++ ++/** + * Main device event processing function. + * Called from when processing the events from the event queue. + * +@@ -925,6 +1929,33 @@ + { + DeliverRawEvent(&ev->raw_event, device); + return; ++ } else if ((!syncEvents.playingEvents && !device->process_touch) && ++ (ev->any.type == ET_TouchBegin || ++ ev->any.type == ET_TouchMotion || ++ ev->any.type == ET_TouchMotionUnowned || ++ ev->any.type == ET_TouchOwnership || ++ ev->any.type == ET_TouchEnd)) ++ { ++ /* The first time through we figure out what to do with the touch. ++ * Further times through (playingEvents or process_touch), we process ++ * the event like any other. */ ++ ProcessTouchEvent(ev, device); ++ return; ++ } ++ ++ /* Ownership events are smaller than device events, so we must handle them ++ * first or we'll corrupt the heap. */ ++ if (ev->any.type == ET_TouchOwnership) ++ { ++ grab = device->deviceGrab.grab; ++ ++ if (grab) ++ DeliverGrabbedEvent(ev, device, FALSE); ++ else ++ DeliverDeviceEvents(GetSpriteWindow(device), ev, NullGrab, ++ NullWindow, device); ++ ++ return; + } + + if (IsPointerDevice(device)) +@@ -1123,6 +2154,50 @@ + dev->proximity->in_proximity = FALSE; + } + ++void ++InitTouchValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, ++ int maxval, int resolution) ++{ ++ TouchAxisInfoPtr ax; ++ ++ if (!dev || !dev->touch || minval > maxval) ++ return; ++ if (axnum >= dev->touch->num_axes) ++ return; ++ ++ ax = dev->touch->axes + axnum; ++ ++ ax->min_value = minval; ++ ax->max_value = maxval; ++ ax->resolution = resolution; ++ ax->label = label; ++ ++ if (ax->label == XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_X)) ++ { ++ dev->touch->x_axis = axnum; ++ if (dev->touch->mode == XIDirectTouch && ++ (!dev->valuator || dev->valuator->numAxes < 1 || ++ dev->valuator->axes[0].min_value != minval || ++ dev->valuator->axes[0].max_value != maxval || ++ dev->valuator->axes[0].resolution != resolution)) ++ LogMessage(X_WARNING, "Touch X valuator does not match pointer X " ++ "valuator, pointer emulation may be " ++ "incorrect\n"); ++ } ++ else if (ax->label == XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y)) ++ { ++ dev->touch->y_axis = axnum; ++ if (dev->touch->mode == XIDirectTouch && ++ (!dev->valuator || dev->valuator->numAxes < 2 || ++ dev->valuator->axes[1].min_value != minval || ++ dev->valuator->axes[1].max_value != maxval || ++ dev->valuator->axes[1].resolution != resolution)) ++ LogMessage(X_WARNING, "Touch Y valuator does not match pointer Y " ++ "valuator, pointer emulation may be " ++ "incorrect\n"); ++ } ++} ++ + static void + FixDeviceStateNotify(DeviceIntPtr dev, deviceStateNotify * ev, KeyClassPtr k, + ButtonClassPtr b, ValuatorClassPtr v, int first) +@@ -1533,6 +2608,38 @@ + return AddPassiveGrabToList(client, grab); + } + ++/* Touch grab */ ++int ++GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev, ++ GrabParameters *param, GrabMask *mask) ++{ ++ WindowPtr pWin; ++ GrabPtr grab; ++ int rc; ++ ++ rc = CheckGrabValues(client, param); ++ if (rc != Success) ++ return rc; ++ ++ rc = dixLookupWindow(&pWin, param->grabWindow, client, DixSetAttrAccess); ++ if (rc != Success) ++ return rc; ++ rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixFreezeAccess); ++ if (rc != Success) ++ return rc; ++ ++ /* Touch grabs are asynchronous in protocol, but we need to freeze the ++ * pointer device if a touch grab is activated for pointer emulation. */ ++ param->other_devices_mode = GrabModeSync; ++ ++ grab = CreateGrab(client->index, dev, mod_dev, pWin, GRABTYPE_XI2, ++ mask, param, XI_TouchBegin, 0, NullWindow, NullCursor); ++ if (!grab) ++ return BadAlloc; ++ ++ return AddPassiveGrabToList(client, grab); ++} ++ + int + SelectForWindow(DeviceIntPtr dev, WindowPtr pWin, ClientPtr client, + Mask mask, Mask exclusivemasks) +@@ -1670,10 +2777,65 @@ + } + } + ++static void ++RemoveTouchClient(DeviceIntPtr dev, TouchPointInfoPtr ti, int index) ++{ ++ TouchClientPtr tc = &ti->clients[index]; ++ int i; ++ ++ if (index == ti->owner) { ++ if (tc->grab && dev->deviceGrab.grab && ++ GrabMatchesSecond(tc->grab, dev->deviceGrab.grab, ++ FALSE)) ++ ProcessTouchOwnership(dev, ti, XITouchOwnerRejectEnd, TRUE); ++ else { ++ ti->owner++; ++ if (ti->owner >= ti->active_clients) { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ } ++ } ++ return; ++ } ++ ++ for (i = index; i < ti->active_clients - 1; i++) ++ memcpy(ti->clients + i, ti->clients + i + 1, ++ sizeof(TouchClientRec)); ++ ti->active_clients--; ++} ++ ++ + int + InputClientGone(WindowPtr pWin, XID id) + { + InputClientsPtr other, prev; ++ DeviceIntPtr dev; ++ ++ for (dev = inputInfo.devices; dev; dev = dev->next) { ++ TouchClassPtr t = dev->touch; ++ int i; ++ ++ if (!t) ++ continue; ++ ++ for (i = 0; i < t->num_touches; i++) { ++ TouchPointInfoPtr ti = &t->touches[i]; ++ int j; ++ ++ if (!ti->active || ti->active_clients == 0) ++ continue; ++ ++ j = (ti->owner < 0) ? 0 : ti->owner; ++ while (j < ti->active_clients) { ++ TouchClientPtr tc = &ti->clients[j]; ++ ++ if (clients[CLIENT_ID(id)] == tc->client) ++ RemoveTouchClient(dev, ti, j); ++ else ++ j++; ++ } ++ } ++ } + + if (!wOtherInputMasks(pWin)) + return Success; +@@ -1709,6 +2871,54 @@ + FatalError("client not on device event list"); + } + ++/** ++ * Search for window in each touch trace for each device. Remove the window ++ * and all its subwindows from the trace when found. The initial window ++ * order is preserved. ++ */ ++void WindowGone(WindowPtr win) ++{ ++ DeviceIntPtr dev; ++ ++ for (dev = inputInfo.devices; dev; dev = dev->next) { ++ TouchClassPtr t = dev->touch; ++ int i; ++ ++ if (!t) ++ continue; ++ ++ for (i = 0; i < t->num_touches; i++) { ++ SpritePtr sprite = &t->touches[i].sprite; ++ int j; ++ ++ for (j = 0; j < sprite->spriteTraceGood; j++) { ++ if (sprite->spriteTrace[j] == win) { ++ sprite->spriteTraceGood = j; ++ break; ++ } ++ } ++ } ++ ++ for (i = 0; i < t->num_touches; i++) { ++ TouchPointInfoPtr ti = &t->touches[i]; ++ int j; ++ ++ if (!ti->active || ti->active_clients == 0) ++ continue; ++ ++ j = (ti->owner < 0) ? 0 : ti->owner; ++ while (j < ti->active_clients) { ++ TouchClientPtr tc = &ti->clients[j]; ++ ++ if (win == tc->window) ++ RemoveTouchClient(dev, ti, j); ++ else ++ j++; ++ } ++ } ++ } ++} ++ + int + SendEvent(ClientPtr client, DeviceIntPtr d, Window dest, Bool propagate, + xEvent * ev, Mask mask, int count) +Index: xorg-server/Xi/extinit.c +=================================================================== +--- xorg-server.orig/Xi/extinit.c 2011-08-24 12:52:43.985647123 +0300 ++++ xorg-server/Xi/extinit.c 2011-08-24 12:56:49.855650623 +0300 +@@ -259,7 +259,8 @@ + ProcXIChangeProperty, /* 57 */ + ProcXIDeleteProperty, /* 58 */ + ProcXIGetProperty, /* 59 */ +- ProcXIGetSelectedEvents /* 60 */ ++ ProcXIGetSelectedEvents, /* 60 */ ++ ProcXIAllowTouchEvents, /* 61 */ + }; + + /* For swapped clients */ +@@ -324,7 +325,8 @@ + SProcXIChangeProperty, /* 57 */ + SProcXIDeleteProperty, /* 58 */ + SProcXIGetProperty, /* 59 */ +- SProcXIGetSelectedEvents /* 60 */ ++ SProcXIGetSelectedEvents, /* 60 */ ++ SProcXIAllowTouchEvents, /* 61 */ + }; + + /***************************************************************** +@@ -855,6 +857,21 @@ + swaps(&to->valuators_len, n); + } + ++static void STouchOwnershipEvent(xXITouchOwnershipEvent *from, ++ xXITouchOwnershipEvent *to) ++{ ++ char n; ++ ++ *to = *from; ++ swaps(&to->sequenceNumber, n); ++ swapl(&to->length, n); ++ swaps(&to->evtype, n); ++ swaps(&to->deviceid, n); ++ swapl(&to->time, n); ++ swaps(&to->sourceid, n); ++ swapl(&to->touchid, n); ++ swapl(&to->flags, n); ++} + + /** Event swapping function for XI2 events. */ + void +@@ -884,8 +901,16 @@ + case XI_KeyRelease: + case XI_ButtonPress: + case XI_ButtonRelease: ++ case XI_TouchBegin: ++ case XI_TouchUpdate: ++ case XI_TouchUpdateUnowned: ++ case XI_TouchEnd: + SDeviceEvent((xXIDeviceEvent*)from, (xXIDeviceEvent*)to); + break; ++ case XI_TouchOwnership: ++ STouchOwnershipEvent((xXITouchOwnershipEvent*)from, ++ (xXITouchOwnershipEvent*)to); ++ break; + case XI_RawMotion: + case XI_RawKeyPress: + case XI_RawKeyRelease: +Index: xorg-server/Xi/xiallowev.c +=================================================================== +--- xorg-server.orig/Xi/xiallowev.c 2011-08-24 12:52:44.025647122 +0300 ++++ xorg-server/Xi/xiallowev.c 2011-08-24 12:56:49.855650623 +0300 +@@ -35,11 +35,15 @@ + + #include "inputstr.h" /* DeviceIntPtr */ + #include "windowstr.h" /* window structure */ ++#include "eventstr.h" ++#include "mi.h" + #include <X11/extensions/XI2.h> + #include <X11/extensions/XI2proto.h> + + #include "exglobals.h" /* BadDevice */ + #include "xiallowev.h" ++#include "exevents.h" ++#include "dixgrabs.h" + + int + SProcXIAllowEvents(ClientPtr client) +@@ -98,6 +102,113 @@ + ret = BadValue; + } + ++ /* If this is a master pointer with an active touch emulation and the touch ++ * has physically ceased, end the touchpoint state. */ ++ if (dev->emulate_dev) ++ { ++ DeviceIntPtr sourcedev = dev->emulate_dev; ++ TouchPointInfoPtr ti = sourcedev->touch->emulate; ++ ++ if (ti->pending_finish && ti->owner < 0) ++ EndTouchPoint(sourcedev, ti); ++ else if (ti->pending_finish) ++ { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED) ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ + return ret; + } + ++int ++SProcXIAllowTouchEvents(ClientPtr client) ++{ ++ char n; ++ ++ REQUEST(xXIAllowTouchEventsReq); ++ ++ swaps(&stuff->length, n); ++ swaps(&stuff->deviceid, n); ++ swapl(&stuff->touchid, n); ++ ++ return ProcXIAllowTouchEvents(client); ++} ++ ++int ++ProcXIAllowTouchEvents(ClientPtr client) ++{ ++ DeviceIntPtr dev; ++ TouchClassPtr t; ++ TouchPointInfoPtr ti; ++ TouchClientPtr tc; ++ int ret; ++ EventList *events = InitEventList(GetMaximumEventsNum()); ++ ++ REQUEST(xXIAllowTouchEventsReq); ++ REQUEST_SIZE_MATCH(xXIAllowTouchEventsReq); ++ ++ if (!events) ++ return BadAlloc; ++ ++ ret = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); ++ if (ret != Success) ++ return ret; ++ ++ if (!dev->touch) ++ { ++ client->errorValue = stuff->deviceid; ++ return BadDevice; ++ } ++ ++ t = dev->touch; ++ ++ ti = FindTouchPointByClientID(dev, stuff->touchid); ++ if (!ti) ++ { ++ client->errorValue = stuff->touchid; ++ return BadValue; ++ } ++ ++ tc = &ti->clients[ti->owner]; ++ ++ if (client != tc->client || !tc->grab) ++ return BadAccess; ++ ++ if (ti == t->emulate) ++ { ++ DeviceIntPtr master = dev->u.master; ++ ++ if (!master || !master->deviceGrab.grab || ++ !GrabMatchesSecond(master->deviceGrab.grab, tc->grab, FALSE)) ++ return BadAccess; ++ } ++ ++ if (stuff->mode & XITouchOwnerAccept) ++ { ++ if (stuff->mode & ~XITouchOwnerAccept) ++ { ++ client->errorValue = stuff->mode; ++ return BadValue; ++ } ++ } ++ else if (stuff->mode & XITouchOwnerRejectEnd) ++ { ++ if (stuff->mode & ~XITouchOwnerRejectEnd) ++ { ++ client->errorValue = stuff->mode; ++ return BadValue; ++ } ++ } ++ else ++ { ++ client->errorValue = stuff->mode; ++ return BadValue; ++ } ++ ++ ProcessTouchOwnership(dev, ti, stuff->mode, TRUE); ++ ++ return Success; ++} +Index: xorg-server/Xi/xiallowev.h +=================================================================== +--- xorg-server.orig/Xi/xiallowev.h 2011-08-24 12:52:43.975647121 +0300 ++++ xorg-server/Xi/xiallowev.h 2011-08-24 12:56:49.855650623 +0300 +@@ -32,5 +32,7 @@ + + int ProcXIAllowEvents(ClientPtr client); + int SProcXIAllowEvents(ClientPtr client); ++int ProcXIAllowTouchEvents(ClientPtr client); ++int SProcXIAllowTouchEvents(ClientPtr client); + + #endif /* XIALLOWEV_H */ +Index: xorg-server/Xi/xipassivegrab.c +=================================================================== +--- xorg-server.orig/Xi/xipassivegrab.c 2011-08-24 12:52:43.995647122 +0300 ++++ xorg-server/Xi/xipassivegrab.c 2011-08-24 12:56:49.855650623 +0300 +@@ -110,19 +110,30 @@ + if (stuff->grab_type != XIGrabtypeButton && + stuff->grab_type != XIGrabtypeKeycode && + stuff->grab_type != XIGrabtypeEnter && +- stuff->grab_type != XIGrabtypeFocusIn) ++ stuff->grab_type != XIGrabtypeFocusIn && ++ stuff->grab_type != XIGrabtypeTouchBegin) + { + client->errorValue = stuff->grab_type; + return BadValue; + } + + if ((stuff->grab_type == XIGrabtypeEnter || +- stuff->grab_type == XIGrabtypeFocusIn) && stuff->detail != 0) ++ stuff->grab_type == XIGrabtypeFocusIn || ++ stuff->grab_type == XIGrabtypeTouchBegin) && ++ stuff->detail != 0) + { + client->errorValue = stuff->detail; + return BadValue; + } + ++ if (stuff->grab_type == XIGrabtypeTouchBegin && ++ (stuff->grab_mode != GrabModeAsync || ++ stuff->paired_device_mode != GrabModeAsync)) ++ { ++ client->errorValue = GrabModeSync; ++ return BadValue; ++ } ++ + if (XICheckInvalidMaskBits(client, (unsigned char*)&stuff[1], + stuff->mask_len * 4) != Success) + return BadValue; +@@ -192,6 +203,9 @@ + status = GrabWindow(client, dev, stuff->grab_type, + ¶m, &mask); + break; ++ case XIGrabtypeTouchBegin: ++ status = GrabTouch(client, dev, mod_dev, ¶m, &mask); ++ break; + } + + if (status != GrabSuccess) +Index: xorg-server/Xi/xiquerydevice.c +=================================================================== +--- xorg-server.orig/Xi/xiquerydevice.c 2011-08-24 12:52:43.955647122 +0300 ++++ xorg-server/Xi/xiquerydevice.c 2011-08-24 12:56:49.855650623 +0300 +@@ -235,6 +235,12 @@ + if (dev->valuator) + len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; + ++ if (dev->touch) ++ { ++ len += sizeof(xXITouchInfo); ++ len += sizeof(xXITouchValuatorInfo) * dev->touch->num_axes; ++ } ++ + return len; + } + +@@ -376,6 +382,73 @@ + swaps(&info->sourceid, n); + } + ++/** ++ * List multitouch information ++ * ++ * @return The number of bytes written into info. ++ */ ++int ++ListTouchInfo(DeviceIntPtr dev, xXITouchInfo *touch) ++{ ++ touch->type = XITouchClass; ++ touch->length = sizeof(xXITouchInfo) >> 2; ++ touch->sourceid = dev->id; ++ touch->mode = dev->touch->mode; ++ touch->num_touches = dev->touch->num_touches; ++ ++ return touch->length << 2; ++} ++ ++static void ++SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo* touch) ++{ ++ char n; ++ swaps(&touch->type, n); ++ swaps(&touch->length, n); ++ swaps(&touch->sourceid, n); ++} ++ ++/** ++ * List multitouch axis information ++ * ++ * @return The number of bytes written into info. ++ */ ++int ++ListTouchValuatorInfo(DeviceIntPtr dev, xXITouchValuatorInfo* val, ++ int axisnumber) ++{ ++ TouchClassPtr t = dev->touch; ++ ++ val->type = XITouchValuatorClass; ++ val->length = sizeof(xXITouchValuatorInfo) >> 2; ++ val->sourceid = dev->id; ++ val->number = axisnumber; ++ val->label = t->axes[axisnumber].label; ++ val->min.integral = t->axes[axisnumber].min_value; ++ val->min.frac = 0; ++ val->max.integral = t->axes[axisnumber].max_value; ++ val->max.frac = 0; ++ val->resolution = t->axes[axisnumber].resolution; ++ ++ return val->length << 2; ++} ++ ++static void ++SwapTouchValuatorInfo(DeviceIntPtr dev, xXITouchValuatorInfo* val) ++{ ++ char n; ++ swaps(&val->type, n); ++ swaps(&val->length, n); ++ swaps(&val->sourceid, n); ++ swaps(&val->number, n); ++ swapl(&val->label, n); ++ swapl(&val->min.integral, n); ++ swapl(&val->min.frac, n); ++ swapl(&val->max.integral, n); ++ swapl(&val->max.frac, n); ++ swapl(&val->resolution, n); ++} ++ + int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) + { + DeviceIntPtr master = dev->u.master; +@@ -465,6 +538,22 @@ + total_len += len; + } + ++ if (dev->touch) ++ { ++ (*nclasses)++; ++ len = ListTouchInfo(dev, (xXITouchInfo*)any); ++ any += len; ++ total_len += len; ++ ++ for (i = 0; i < dev->touch->num_axes; i++) ++ { ++ (*nclasses)++; ++ len = ListTouchValuatorInfo(dev, (xXITouchValuatorInfo*)any, i); ++ any += len; ++ total_len += len; ++ } ++ } ++ + return total_len; + } + +@@ -492,6 +581,12 @@ + case XIValuatorClass: + SwapValuatorInfo(dev, (xXIValuatorInfo*)any); + break; ++ case XITouchClass: ++ SwapTouchInfo(dev, (xXITouchInfo*)any); ++ break; ++ case XITouchValuatorClass: ++ SwapTouchValuatorInfo(dev, (xXITouchValuatorInfo*)any); ++ break; + } + + any += len * 4; +Index: xorg-server/Xi/xiquerydevice.h +=================================================================== +--- xorg-server.orig/Xi/xiquerydevice.h 2011-08-24 12:52:44.015647121 +0300 ++++ xorg-server/Xi/xiquerydevice.h 2011-08-24 12:56:49.855650623 +0300 +@@ -44,4 +44,7 @@ + int ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info); + int ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, + int axisnumber, Bool reportState); ++int ListTouchInfo(DeviceIntPtr dev, xXITouchInfo* info); ++int ListTouchValuatorInfo(DeviceIntPtr dev, xXITouchValuatorInfo* val, ++ int axisnumber); + #endif /* QUERYDEV_H */ +Index: xorg-server/Xi/xiselectev.c +=================================================================== +--- xorg-server.orig/Xi/xiselectev.c 2011-08-24 12:52:44.005647120 +0300 ++++ xorg-server/Xi/xiselectev.c 2011-08-24 12:56:49.855650623 +0300 +@@ -152,6 +152,60 @@ + } + } + ++ if (evmask->mask_len >= 1) ++ { ++ unsigned char *bits = (unsigned char*)&evmask[1]; ++ ++ /* Check validity of touch selections */ ++ if (BitIsOn(bits, XI_TouchBegin) || ++ BitIsOn(bits, XI_TouchUpdate) || ++ BitIsOn(bits, XI_TouchEnd)) ++ { ++ /* All three touch events must be selected at once */ ++ if (!BitIsOn(bits, XI_TouchBegin) || ++ !BitIsOn(bits, XI_TouchUpdate) || ++ !BitIsOn(bits, XI_TouchEnd)) ++ { ++ client->errorValue = XI_TouchBegin; ++ return BadValue; ++ } ++ ++ /* Unowned and ownership events must both be selected */ ++ if ((BitIsOn(bits, XI_TouchUpdateUnowned) || ++ BitIsOn(bits, XI_TouchOwnership)) && ++ (!BitIsOn(bits, XI_TouchUpdateUnowned) || ++ !BitIsOn(bits, XI_TouchOwnership))) ++ { ++ client->errorValue = XI_TouchBegin; ++ return BadValue; ++ } ++ } ++ ++ /* Only one client per window may select for touch events on the ++ * same devices, including master devices. ++ * XXX: This breaks if a device goes from floating to attached. */ ++ if (BitIsOn(bits, XI_TouchBegin)) ++ { ++ OtherInputMasks *inputMasks = wOtherInputMasks(win); ++ InputClients *iclient = NULL; ++ if (inputMasks) ++ iclient = inputMasks->inputClients; ++ for (; iclient; iclient = iclient->next) ++ { ++ if (CLIENT_ID(iclient->resource) == client->index) ++ continue; ++ if (BitIsOn(iclient->xi2mask[evmask->deviceid], ++ XI_TouchBegin) || ++ BitIsOn(iclient->xi2mask[XIAllDevices], ++ XI_TouchBegin) || ++ (dev && (IsMaster(dev) || dev->u.master) && ++ BitIsOn(iclient->xi2mask[XIAllMasterDevices], ++ XI_TouchBegin))) ++ return BadAccess; ++ } ++ } ++ } ++ + if (XICheckInvalidMaskBits(client, (unsigned char*)&evmask[1], + evmask->mask_len * 4) != Success) + return BadValue; +Index: xorg-server/configure.ac +=================================================================== +--- xorg-server.orig/configure.ac 2011-08-24 12:56:49.795650626 +0300 ++++ xorg-server/configure.ac 2011-08-24 12:57:14.755650981 +0300 +@@ -795,7 +795,7 @@ + APPLEWMPROTO="applewmproto >= 1.4" + + dnl Core modules for most extensions, et al. +-SDK_REQUIRED_MODULES="[xproto >= 7.0.17] [randrproto >= 1.2.99.3] [renderproto >= 0.11] [xextproto >= 7.1.99] [inputproto >= 1.9.99.902] [kbproto >= 1.0.3] fontsproto" ++SDK_REQUIRED_MODULES="[xproto >= 7.0.17] [randrproto >= 1.2.99.3] [renderproto >= 0.11] [xextproto >= 7.1.99] [inputproto >= 2.0.2] [kbproto >= 1.0.3] fontsproto" + # Make SDK_REQUIRED_MODULES available for inclusion in xorg-server.pc + AC_SUBST(SDK_REQUIRED_MODULES) + +Index: xorg-server/dix/devices.c +=================================================================== +--- xorg-server.orig/dix/devices.c 2011-08-24 12:52:43.855647120 +0300 ++++ xorg-server/dix/devices.c 2011-08-24 12:56:49.855650623 +0300 +@@ -754,6 +754,20 @@ + free((*v)); + break; + } ++ case XITouchClass: ++ { ++ TouchClassPtr *t = (TouchClassPtr*)class; ++ int i; ++ ++ for (i = 0; i < (*t)->num_touches; i++) ++ { ++ free((*t)->touches[i].sprite.spriteTrace); ++ free((*t)->touches[i].clients); ++ } ++ ++ free((*t)); ++ break; ++ } + case FocusClass: + { + FocusClassPtr *f = (FocusClassPtr*)class; +@@ -862,6 +876,7 @@ + + FreeDeviceClass(KeyClass, (pointer)&classes->key); + FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator); ++ FreeDeviceClass(XITouchClass, (pointer)&classes->touch); + FreeDeviceClass(ButtonClass, (pointer)&classes->button); + FreeDeviceClass(FocusClass, (pointer)&classes->focus); + FreeDeviceClass(ProximityClass, (pointer)&classes->proximity); +@@ -1574,6 +1589,151 @@ + InitPtrFeedbackClassDeviceStruct(dev, controlProc)); + } + ++Bool ++InitTouchPoint(TouchClassPtr t, int index) ++{ ++ TouchPointInfoPtr ti; ++ ++ if (!index >= t->num_touches) ++ return FALSE; ++ ti = &t->touches[index]; ++ ++ ti->valuators = calloc(t->num_axes, sizeof(*ti->valuators)); ++ if (!ti->valuators) ++ return FALSE; ++ ti->num_valuators = t->num_axes; ++ ++ ti->sprite.spriteTrace = calloc(32, sizeof(*ti->sprite.spriteTrace)); ++ if (!ti->sprite.spriteTrace) ++ { ++ free(ti->valuators); ++ ti->valuators = NULL; ++ ti->num_valuators = 0; ++ return FALSE; ++ } ++ ti->sprite.spriteTraceSize = 32; ++ ti->sprite.spriteTrace[0] = screenInfo.screens[0]->root; ++ ti->sprite.hot.pScreen = screenInfo.screens[0]; ++ ti->sprite.hotPhys.pScreen = screenInfo.screens[0]; ++ ++ ti->ddx_id = -1; ++ ti->client_id = -1; ++ ++ ti->history_size = GetMotionHistorySize(); ++ ti->begin_event = malloc((ti->history_size + 1) * sizeof(InternalEvent)); ++ if (!ti->begin_event) ++ { ++ free(ti->sprite.spriteTrace); ++ free(ti->valuators); ++ ti->sprite.spriteTrace = NULL; ++ ti->valuators = NULL; ++ ti->num_valuators = 0; ++ return FALSE; ++ } ++ ti->history = ti->begin_event + 1; ++ ti->first_history = ti->history; ++ ti->next_history = ti->history; ++ ++ return TRUE; ++} ++ ++void ++FreeTouchPoint(DeviceIntPtr device, int index) ++{ ++ TouchPointInfoPtr ti; ++ ++ if (!device->touch || index >= device->touch->num_touches) ++ return; ++ ti = &device->touch->touches[index]; ++ ++ if (ti->active) ++ EndTouchPoint(device, ti); ++ ++ free(ti->valuators); ++ ti->valuators = NULL; ++ ti->num_valuators = 0; ++ free(ti->sprite.spriteTrace); ++ ti->sprite.spriteTrace = NULL; ++ free(ti->begin_event); ++ ti->begin_event = NULL; ++ free(ti->clients); ++ ti->clients = NULL; ++ ti->num_clients = 0; ++} ++ ++/** ++ * Sets up multitouch capabilities on @device. ++ * ++ * @max_touches The maximum number of simultaneous touches, or 0 for unlimited. ++ * @mode The mode of the touch device (XIDirectTouch or XIDependentTouch). ++ * @num_axes The number of touch valuator axes. ++ */ ++Bool ++InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches, ++ unsigned int mode, unsigned int num_axes) ++{ ++ TouchClassPtr touch; ++ int i; ++ ++ if (device->touch) ++ return FALSE; ++ ++ /* Check the mode is valid, and at least X and Y axes. */ ++ if (mode != XIDirectTouch && mode != XIDependentTouch) ++ return FALSE; ++ if (num_axes < 2) ++ return FALSE; ++ ++ if (num_axes > MAX_VALUATORS) ++ { ++ LogMessage(X_WARNING, ++ "Device '%s' has %d touch axes, only using first %d.\n", ++ device->name, num_axes, MAX_VALUATORS); ++ num_axes = MAX_VALUATORS; ++ } ++ ++ touch = calloc(1, sizeof(*touch)); ++ if (!touch) ++ return FALSE; ++ ++ touch->axes = calloc(num_axes, sizeof(*touch->axes)); ++ if (!touch->axes) ++ goto err; ++ touch->num_axes = num_axes; ++ ++ touch->max_touches = max_touches; ++ if (max_touches == 0) ++ max_touches = 5; /* arbitrary number plucked out of the air */ ++ ++ /* Need cushion for clients who may hold on to touches after they physically ++ * end. So double the initial allocation of touches. */ ++ touch->touches = calloc(max_touches * 2, sizeof(*touch->touches)); ++ if (!touch->touches) ++ goto err; ++ touch->num_touches = max_touches * 2; ++ for (i = 0; i < touch->num_touches; i++) ++ InitTouchPoint(touch, i); ++ ++ touch->mode = mode; ++ touch->x_axis = -1; ++ touch->y_axis = -1; ++ touch->next_client_id = 1; ++ ++ device->touch = touch; ++ ++ return TRUE; ++ ++err: ++ for (i = 0; i < touch->num_touches; i++) ++ FreeTouchPoint(device, i); ++ ++ free(touch->touches); ++ free(touch->axes); ++ free(touch); ++ ++ return FALSE; ++} ++ + /* + * Check if the given buffer contains elements between low (inclusive) and + * high (inclusive) only. +@@ -2446,6 +2606,58 @@ + FreeEventList(eventlist, GetMaximumEventsNum()); + } + ++static void ++DropTouchSelectionsOnWindow(DeviceIntPtr dev, WindowPtr win) ++{ ++ WindowPtr child; ++ ++ if (wOtherInputMasks(win) && ++ BitIsOn(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchBegin)) ++ { ++ InputClientsPtr client = wOtherInputMasks(win)->inputClients; ++ ++ /* Don't bother deleting client record if there are no other ++ * selections. The client will likely reselect when it gets the ++ * HierarchyChange event. */ ++ while (client) ++ { ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchBegin); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchEnd); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchOwnership); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdate); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdateUnowned); ++ ++ client = client->next; ++ } ++ ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchBegin); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchEnd); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchOwnership); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdate); ++ ClearBit(wOtherInputMasks(win)->xi2mask[dev->id], XI_TouchUpdateUnowned); ++ } ++ ++ child = win->firstChild; ++ while (child) ++ { ++ DropTouchSelectionsOnWindow(dev, child); ++ child = child->nextSib; ++ } ++} ++ ++static void ++DropTouchSelections(DeviceIntPtr dev) ++{ ++ int i; ++ ++ for (i = 0; i < screenInfo.numScreens; i++) ++ { ++ WindowPtr win = screenInfo.screens[i]->root; ++ ++ DropTouchSelectionsOnWindow(dev, win); ++ } ++} ++ + /** + * Attach device 'dev' to device 'master'. + * Client is set to the client that issued the request, or NULL if it comes +@@ -2511,6 +2723,12 @@ + dev->spriteInfo->spriteOwner = FALSE; + + RecalculateMasterButtons(master); ++ ++ /* Only one client may select for touch events from a device on a window ++ * at any time. Reattaching could break this, so drop all touch event ++ * selections for this specific slave device on all windows. */ ++ if (dev->touch) ++ DropTouchSelections(dev); + } + + /* XXX: in theory, the MD should change back to its old, original +Index: xorg-server/dix/eventconvert.c +=================================================================== +--- xorg-server.orig/dix/eventconvert.c 2011-08-24 12:52:43.825647118 +0300 ++++ xorg-server/dix/eventconvert.c 2011-08-24 12:56:49.855650623 +0300 +@@ -55,6 +55,7 @@ + static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce); + static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi); + static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi); ++static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi); + + /* Do not use, read comments below */ + BOOL EventIsKeyRepeat(xEvent *event); +@@ -139,6 +140,11 @@ + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: ++ case ET_TouchOwnership: + return BadMatch; + default: + /* XXX: */ +@@ -184,6 +190,11 @@ + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: ++ case ET_TouchOwnership: + *count = 0; + *xi = NULL; + return BadMatch; +@@ -225,7 +236,13 @@ + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: ++ case ET_TouchBegin: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: ++ case ET_TouchEnd: + return eventToDeviceEvent(&ev->device_event, xi); ++ case ET_TouchOwnership: ++ return eventToTouchOwnershipEvent(&ev->touch_ownership_event, xi); + case ET_ProximityIn: + case ET_ProximityOut: + *xi = NULL; +@@ -581,6 +598,7 @@ + xde->root_x = FP1616(ev->root_x, ev->root_x_frac); + xde->root_y = FP1616(ev->root_y, ev->root_y_frac); + ++ xde->flags = ev->flags; + if (ev->key_repeat) + xde->flags |= XIKeyRepeat; + +@@ -618,6 +636,27 @@ + } + + static int ++eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi) ++{ ++ int len = sizeof(xXITouchOwnershipEvent); ++ xXITouchOwnershipEvent *xtoe; ++ ++ *xi = calloc(1, len); ++ xtoe = (xXITouchOwnershipEvent*)*xi; ++ xtoe->type = GenericEvent; ++ xtoe->extension = IReqCode; ++ xtoe->length = bytes_to_int32(len - sizeof(xEvent)); ++ xtoe->evtype = GetXI2Type((InternalEvent*)ev); ++ xtoe->deviceid = ev->deviceid; ++ xtoe->time = ev->time; ++ xtoe->sourceid = ev->sourceid; ++ xtoe->touchid = ev->touchid; ++ xtoe->flags = ev->flags; ++ ++ return Success; ++} ++ ++static int + eventToRawEvent(RawDeviceEvent *ev, xEvent **xi) + { + xXIRawEvent* raw; +@@ -732,6 +771,11 @@ + case ET_RawMotion: xi2type = XI_RawMotion; break; + case ET_FocusIn: xi2type = XI_FocusIn; break; + case ET_FocusOut: xi2type = XI_FocusOut; break; ++ case ET_TouchBegin: xi2type = XI_TouchBegin; break; ++ case ET_TouchEnd: xi2type = XI_TouchEnd; break; ++ case ET_TouchMotion: xi2type = XI_TouchUpdate; break; ++ case ET_TouchMotionUnowned: xi2type = XI_TouchUpdateUnowned; break; ++ case ET_TouchOwnership: xi2type = XI_TouchOwnership; break; + default: + break; + } +Index: xorg-server/dix/events.c +=================================================================== +--- xorg-server.orig/dix/events.c 2011-08-24 12:56:49.835650626 +0300 ++++ xorg-server/dix/events.c 2011-08-24 12:57:17.885651026 +0300 +@@ -1096,7 +1096,7 @@ + void + EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) + { +- QdEventPtr tail = *syncEvents.pendtail; ++ QdEventPtr tail = syncEvents.pendtail; + QdEventPtr qe; + SpritePtr pSprite = device->spriteInfo->sprite; + int eventlen; +@@ -1167,8 +1167,10 @@ + qe->event = (InternalEvent *)(qe + 1); + memcpy(qe->event, event, eventlen); + if (tail) +- syncEvents.pendtail = &tail->next; +- *syncEvents.pendtail = qe; ++ tail->next = qe; ++ else ++ syncEvents.pending = qe; ++ syncEvents.pendtail = qe; + } + + /** +@@ -1183,18 +1185,19 @@ + static void + PlayReleasedEvents(void) + { +- QdEventPtr *prev, qe; ++ QdEventPtr prev, qe = syncEvents.pending; + DeviceIntPtr dev; + DeviceIntPtr pDev; + +- prev = &syncEvents.pending; +- while ( (qe = *prev) ) ++ prev = NULL; ++ while (qe) + { + if (!qe->device->deviceGrab.sync.frozen) + { +- *prev = qe->next; ++ if (syncEvents.pending == qe) ++ syncEvents.pending = qe->next; + pDev = qe->device; +- if (*syncEvents.pendtail == *prev) ++ if (syncEvents.pendtail == qe) + syncEvents.pendtail = prev; + if (qe->event->any.type == ET_Motion) + CheckVirtualMotion(pDev, qe, NullWindow); +@@ -1226,6 +1229,7 @@ + + } + #endif ++ + (*qe->device->public.processInputProc)(qe->event, qe->device); + free(qe); + for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next) +@@ -1234,10 +1238,14 @@ + break; + /* Playing the event may have unfrozen another device. */ + /* So to play it safe, restart at the head of the queue */ +- prev = &syncEvents.pending; ++ qe = syncEvents.pending; ++ prev = NULL; + } + else +- prev = &qe->next; ++ { ++ prev = qe; ++ qe = qe->next; ++ } + } + } + +@@ -1259,6 +1267,76 @@ + dev->public.processInputProc = dev->public.realInputProc; + } + ++void ++RemoveTouchEventsFromQueue(DeviceIntPtr dev, Bool touch, Bool ignoreOwned) ++{ ++ QdEventPtr qe = syncEvents.pending; ++ QdEventPtr prev_qe = NULL; ++ QdEventPtr first = NULL; ++ Bool end = FALSE; ++ ++ while (qe && !end) ++ { ++ QdEventPtr tmp; ++ ++ if (qe->device != dev) ++ continue; ++ ++ if (ignoreOwned && (qe->event->any.type == ET_TouchOwnership || ++ qe->event->any.type == ET_TouchEnd)) ++ break; ++ ++ if (qe->event->any.type == ET_TouchEnd) ++ end = TRUE; ++ ++ if ((touch && !IsTouchEvent(qe->event)) || ++ (!touch && !IsPointerEvent(qe->event)) || ++ (ignoreOwned && qe->event->any.type == ET_TouchBegin)) ++ { ++ if (!first) ++ first = qe; ++ prev_qe = qe; ++ qe = qe->next; ++ continue; ++ } ++ ++ tmp = qe; ++ qe = qe->next; ++ if (prev_qe) ++ prev_qe->next = qe; ++ if (syncEvents.pending == tmp) ++ syncEvents.pending = qe; ++ ++ free(tmp); ++ ++ if (!qe) ++ syncEvents.pendtail = prev_qe; ++ } ++ ++ if (qe && !qe->next) ++ syncEvents.pendtail = qe; ++ ++ if (dev->deviceGrab.sync.event && ++ ((touch && IsTouchEvent((InternalEvent *)dev->deviceGrab.sync.event)) || ++ (!touch && ++ IsPointerEvent((InternalEvent *)dev->deviceGrab.sync.event)))) ++ { ++ free(dev->deviceGrab.sync.event); ++ if (first) ++ { ++ dev->deviceGrab.sync.event = malloc(sizeof(DeviceEvent)); ++ memcpy(dev->deviceGrab.sync.event, first->event, ++ sizeof(DeviceEvent)); ++ } ++ else ++ dev->deviceGrab.sync.event = NULL; ++ syncEvents.pending = first->next; ++ free(first); ++ if (!syncEvents.pending) ++ syncEvents.pendtail = NULL; ++ } ++} ++ + /** + * Unfreeze devices and replay all events to the respective clients. + * +@@ -1285,6 +1363,14 @@ + { + DeviceEvent* event = replayDev->deviceGrab.sync.event; + ++ if (event->type == ET_TouchBegin) ++ { ++ ProcessTouchOwnership(replayDev, event->touchpoint, ++ XITouchOwnerAccept, FALSE); ++ if (!replayDev->deviceGrab.sync.event) ++ goto no_sync; ++ } ++ + syncEvents.replayDev = (DeviceIntPtr)NULL; + + w = XYToWindow(replayDev->spriteInfo->sprite, +@@ -1298,6 +1384,7 @@ + NullWindow, replayDev); + } + } ++no_sync: + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->deviceGrab.sync.frozen) +@@ -1517,6 +1604,20 @@ + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(mouse); + ++ if (mouse->deviceGrab.sync.event && ++ (mouse->deviceGrab.sync.event->flags & XIPointerEmulated) && ++ (grab->grabtype != GRABTYPE_XI2 || grab->type != XI_TouchBegin)) ++ { ++ InternalEvent event; ++ ++ event.any.type = ET_TouchBegin; ++ ++ if (CheckPassiveGrabsOnWindow(grab->window, mouse, &event, FALSE, TRUE)) ++ syncEvents.playingEvents = TRUE; ++ } ++ else ++ syncEvents.playingEvents = FALSE; ++ + ComputeFreezes(); + } + +@@ -1764,6 +1865,25 @@ + client->errorValue = stuff->mode; + return BadValue; + } ++ ++ /* If this is a master pointer with an active touch emulation and the touch ++ * has physically ceased, end the touchpoint state. */ ++ if (mouse->emulate_dev) ++ { ++ DeviceIntPtr sourcedev = mouse->emulate_dev; ++ TouchPointInfoPtr ti = sourcedev->touch->emulate; ++ ++ if (ti->pending_finish && ti->owner < 0) ++ EndTouchPoint(sourcedev, ti); ++ else if (ti->pending_finish) ++ { ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ if (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED) ++ EndTouchPoint(sourcedev, ti); ++ } ++ } ++ + return Success; + } + +@@ -2391,7 +2511,7 @@ + + static Window FindChildForEvent(SpritePtr pSprite, WindowPtr event) + { +- WindowPtr w = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; ++ WindowPtr w = DeepestSpriteWin(pSprite); + Window child = None; + + /* If the search ends up past the root should the child field be +@@ -2449,7 +2569,8 @@ + event->evtype == XI_RawMotion || + event->evtype == XI_DeviceChanged || + event->evtype == XI_HierarchyChanged || +- event->evtype == XI_PropertyEvent) ++ event->evtype == XI_PropertyEvent || ++ event->evtype == XI_TouchOwnership) + return; + + event->root = RootWindow(pSprite)->drawable.id; +@@ -2586,12 +2707,119 @@ + xEvent core; + xEvent *xE = NULL; + int rc, mask, count = 0; ++ InternalEvent touch_dummy; ++ Bool check_touch = FALSE; + + CHECKEVENT(event); + ++ /* If we are replaying a pointer emulated button press event, find the first ++ * pointer or touch selecting client. */ ++ if (syncEvents.playingEvents && event->any.type == ET_ButtonPress && ++ (event->device_event.flags & XIPointerEmulated) && ++ event->device_event.touchpoint && ++ event->device_event.touchpoint->active_clients > 0) ++ { ++ QdEventPtr qe; ++ DeviceEvent *te; ++ TouchPointInfoPtr ti; ++ TouchClientPtr tc = NULL; ++ ++ for (qe = syncEvents.pending; qe; qe = qe->next) ++ if (qe->device == dev && qe->event->any.type == ET_TouchBegin) ++ break; ++ if (!qe) ++ { ++ LogMessage(X_ERROR, "no touch for emulated button press\n"); ++ goto no_touch_event; ++ } ++ ++ te = &qe->event->device_event; ++ ti = te->touchpoint; ++ ++ if (ti->active_clients > 0) ++ { ++ tc = &ti->clients[ti->active_clients - 1]; ++ te->deviceid = tc->device->id; ++ } ++ ++ while (pWin) ++ { ++ Bool touch = FALSE; ++ Bool pointer = FALSE; ++ ++ if (tc && ++ EventIsDeliverable(tc->device, (InternalEvent *)te, pWin) && ++ (tc->type == TOUCH_SELECT || tc->type == TOUCH_SELECT_UNOWNED)) ++ { ++ ti->owner = ti->active_clients - 1; ++ if (tc->type == TOUCH_SELECT_UNOWNED) ++ DeliverTouchOwnershipEvent(tc, ti); ++ touch = TRUE; ++ } ++ ++ if (EventIsDeliverable(dev, event, pWin)) ++ pointer = TRUE; ++ ++ if (touch && pointer) ++ break; ++ else if (touch || pointer) ++ { ++ /* Remove unselected events from queue. */ ++ RemoveTouchEventsFromQueue(dev, pointer, FALSE); ++ ++ if (touch) ++ { ++ /* If only touch events are selected, release mouse ++ * button. */ ++ ReleaseButton(dev, 1); ++ ti->emulate_pointer = FALSE; ++ if (IsPointerEvent(event)) ++ return 0; ++ } else { ++ ti->owner = -1; ++ ti->active_clients = 0; ++ if (IsTouchEvent(event)) ++ return 0; ++ } ++ ++ break; ++ } ++ ++ pWin = pWin->parent; ++ } ++ } ++ else if (IsPointerEvent(event) && !syncEvents.playingEvents && ++ (event->device_event.flags & XIPointerEmulated) && ++ event->device_event.touchpoint && ++ event->device_event.touchpoint->active_clients > 0) ++ { ++ /* Non-grabbed emulated pointer event, so check for touch selections. */ ++ check_touch = TRUE; ++ touch_dummy.any.type = ET_TouchBegin; ++ } ++ else if (IsTouchEvent(event)) ++ { ++ TouchPointInfoPtr ti = event->device_event.touchpoint; ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ pWin = tc->window; ++ } ++ ++no_touch_event: + while (pWin) + { +- if ((mask = EventIsDeliverable(dev, event, pWin))) ++ DeviceIntPtr check_dev = dev; ++ ++ if (IsTouchEvent(event)) ++ { ++ TouchPointInfoPtr ti = event->device_event.touchpoint; ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ event->device_event.deviceid = tc->device->id; ++ check_dev = tc->device; ++ } ++ ++ if ((mask = EventIsDeliverable(check_dev, event, pWin))) + { + /* XI2 events first */ + if (mask & XI2_MASK) +@@ -2600,10 +2828,25 @@ + rc = EventToXI2(event, &xi2); + if (rc == Success) + { ++ if (event->any.type == ET_TouchBegin || ++ event->any.type == ET_TouchMotionUnowned) ++ { ++ OtherInputMasks *masks = wOtherInputMasks(pWin); ++ ++ if (BitIsOn(masks->xi2mask[XIAllDevices], ++ XI_TouchOwnership) || ++ BitIsOn(masks->xi2mask[check_dev->id], ++ XI_TouchOwnership) || ++ (IsMaster(check_dev) && ++ BitIsOn(masks->xi2mask[XIAllMasterDevices], ++ XI_TouchOwnership))) ++ goto unwind; ++ } ++ + /* XXX: XACE */ +- filter = GetEventFilter(dev, xi2); ++ filter = GetEventFilter(check_dev, xi2); + FixUpEventFromWindow(pSprite, xi2, pWin, child, FALSE); +- deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, ++ deliveries = DeliverEventsToWindow(check_dev, pWin, xi2, 1, + filter, grab); + free(xi2); + if (deliveries > 0) +@@ -2656,6 +2899,14 @@ + goto unwind; + } + } ++ else if (check_touch && EventIsDeliverable(dev, &touch_dummy, pWin)) ++ { ++ /* Only touch events wanted on this window. Skip this event and ++ * stop pointer emulation. Future touch events will be sent ++ * instead. */ ++ event->device_event.touchpoint->emulate_pointer = FALSE; ++ goto unwind; ++ } + + child = pWin->drawable.id; + pWin = pWin->parent; +@@ -2808,7 +3059,7 @@ + else + pWin = pWin->nextSib; + } +- return pSprite->spriteTrace[pSprite->spriteTraceGood-1]; ++ return DeepestSpriteWin(pSprite); + } + + /** +@@ -2846,7 +3097,8 @@ + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; +- rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL); ++ rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, ++ TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + return rc; +@@ -2883,7 +3135,8 @@ + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; +- rc = (CheckPassiveGrabsOnWindow(win, dev, &event, FALSE, TRUE) != NULL); ++ rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, ++ TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); + return rc; +@@ -3570,7 +3823,7 @@ + CheckPassiveGrabsOnWindow( + WindowPtr pWin, + DeviceIntPtr device, +- DeviceEvent *event, ++ InternalEvent *event, + BOOL checkCore, + BOOL activate) + { +@@ -3587,9 +3840,22 @@ + return NULL; + /* Fill out the grab details, but leave the type for later before + * comparing */ ++ switch (event->any.type) ++ { ++ case ET_KeyPress: ++ case ET_KeyRelease: ++ tempGrab.detail.exact = event->device_event.detail.key; ++ break; ++ case ET_ButtonPress: ++ case ET_ButtonRelease: ++ tempGrab.detail.exact = event->device_event.detail.button; ++ break; ++ default: ++ tempGrab.detail.exact = 0; ++ break; ++ } + tempGrab.window = pWin; + tempGrab.device = device; +- tempGrab.detail.exact = event->detail.key; + tempGrab.detail.pMask = NULL; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.next = NULL; +@@ -3597,6 +3863,9 @@ + { + DeviceIntPtr gdev; + XkbSrvInfoPtr xkbi = NULL; ++ int rc, count = 0; ++ xEvent *xE = NULL; ++ xEvent core; + + gdev= grab->modifierDevice; + if (grab->grabtype == GRABTYPE_CORE) +@@ -3622,16 +3891,15 @@ + tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; + + /* Check for XI2 and XI grabs first */ +- tempGrab.type = GetXI2Type((InternalEvent*)event); ++ tempGrab.type = GetXI2Type(event); + tempGrab.grabtype = GRABTYPE_XI2; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI2_MATCH; + +- tempGrab.detail.exact = event->detail.key; + if (!match) + { + tempGrab.grabtype = GRABTYPE_XI; +- if ((tempGrab.type = GetXIType((InternalEvent*)event)) && ++ if ((tempGrab.type = GetXIType(event)) && + (GrabMatchesSecond(&tempGrab, grab, FALSE))) + match = XI_MATCH; + } +@@ -3640,125 +3908,152 @@ + if (!match && checkCore) + { + tempGrab.grabtype = GRABTYPE_CORE; +- if ((tempGrab.type = GetCoreType((InternalEvent*)event)) && ++ if ((tempGrab.type = GetCoreType(event)) && + (GrabMatchesSecond(&tempGrab, grab, TRUE))) + match = CORE_MATCH; + } + +- if (match && (!grab->confineTo || +- (grab->confineTo->realized && +- BorderSizeNotEmpty(device, grab->confineTo)))) +- { +- int rc, count = 0; +- xEvent *xE = NULL; +- xEvent core; ++ if (!match || (grab->confineTo && ++ (!grab->confineTo->realized || ++ !BorderSizeNotEmpty(device, grab->confineTo)))) ++ continue; + +- event->corestate &= 0x1f00; +- event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); +- grabinfo = &device->deviceGrab; +- /* In some cases a passive core grab may exist, but the client +- * already has a core grab on some other device. In this case we +- * must not get the grab, otherwise we may never ungrab the +- * device. +- */ +- +- if (grab->grabtype == GRABTYPE_CORE) +- { +- DeviceIntPtr other; +- BOOL interfering = FALSE; +- +- /* A passive grab may have been created for a different device +- than it is assigned to at this point in time. +- Update the grab's device and modifier device to reflect the +- current state. +- Since XGrabDeviceButton requires to specify the +- modifierDevice explicitly, we don't override this choice. +- */ +- if (tempGrab.type < GenericEvent) +- { +- grab->device = device; +- grab->modifierDevice = GetPairedDevice(device); +- } ++ grabinfo = &device->deviceGrab; ++ /* In some cases a passive core grab may exist, but the client ++ * already has a core grab on some other device. In this case we ++ * must not get the grab, otherwise we may never ungrab the ++ * device. ++ */ ++ ++ if (grab->grabtype == GRABTYPE_CORE) ++ { ++ DeviceIntPtr other; ++ BOOL interfering = FALSE; ++ ++ /* A passive grab may have been created for a different device ++ than it is assigned to at this point in time. ++ Update the grab's device and modifier device to reflect the ++ current state. ++ Since XGrabDeviceButton requires to specify the ++ modifierDevice explicitly, we don't override this choice. ++ */ ++ if (tempGrab.type < GenericEvent) ++ { ++ grab->device = device; ++ grab->modifierDevice = GetPairedDevice(device); ++ } + +- for (other = inputInfo.devices; other; other = other->next) ++ for (other = inputInfo.devices; other; other = other->next) ++ { ++ GrabPtr othergrab = other->deviceGrab.grab; ++ if (othergrab && othergrab->grabtype == GRABTYPE_CORE && ++ SameClient(grab, rClient(othergrab)) && ++ ((IsPointerDevice(grab->device) && ++ IsPointerDevice(othergrab->device)) || ++ (IsKeyboardDevice(grab->device) && ++ IsKeyboardDevice(othergrab->device)))) + { +- GrabPtr othergrab = other->deviceGrab.grab; +- if (othergrab && othergrab->grabtype == GRABTYPE_CORE && +- SameClient(grab, rClient(othergrab)) && +- ((IsPointerDevice(grab->device) && +- IsPointerDevice(othergrab->device)) || +- (IsKeyboardDevice(grab->device) && +- IsKeyboardDevice(othergrab->device)))) +- { +- interfering = TRUE; +- break; +- } ++ interfering = TRUE; ++ break; + } +- if (interfering) +- continue; + } ++ if (interfering) ++ continue; ++ } + +- if (!activate) +- return grab; ++ if (!activate) ++ { ++ return grab; ++ } ++ else if (!GetXIType(event) && !GetCoreType(event)) ++ { ++ ErrorF("Event type %d in CheckPassiveGrabsOnWindow is neither" ++ " XI 1.x nor core\n", event->any.type); ++ return NULL; ++ } + +- if (match & CORE_MATCH) ++ /* The only consumers of corestate are Xi 1.x and core events, which ++ * are guaranteed to come from DeviceEvents. */ ++ if (match & (XI_MATCH | CORE_MATCH)) ++ { ++ event->device_event.corestate &= 0x1f00; ++ event->device_event.corestate |= tempGrab.modifiersDetail.exact & ++ (~0x1f00); ++ } ++ ++ if (match & CORE_MATCH) ++ { ++ rc = EventToCore(event, &core); ++ if (rc != Success) + { +- rc = EventToCore((InternalEvent*)event, &core); +- if (rc != Success) +- { +- if (rc != BadMatch) +- ErrorF("[dix] %s: core conversion failed in CPGFW " +- "(%d, %d).\n", device->name, event->type, rc); +- continue; +- } +- xE = &core; +- count = 1; +- } else if (match & XI2_MATCH) ++ if (rc != BadMatch) ++ ErrorF("[dix] %s: core conversion failed in CPGFW " ++ "(%d, %d).\n", device->name, event->any.type, rc); ++ continue; ++ } ++ xE = &core; ++ count = 1; ++ } else if (match & XI2_MATCH) ++ { ++ rc = EventToXI2(event, &xE); ++ if (rc != Success) + { +- rc = EventToXI2((InternalEvent*)event, &xE); +- if (rc != Success) +- { +- if (rc != BadMatch) +- ErrorF("[dix] %s: XI2 conversion failed in CPGFW " +- "(%d, %d).\n", device->name, event->type, rc); +- continue; +- } +- count = 1; +- } else ++ if (rc != BadMatch) ++ ErrorF("[dix] %s: XI2 conversion failed in CPGFW " ++ "(%d, %d).\n", device->name, event->any.type, rc); ++ continue; ++ } ++ count = 1; ++ } else ++ { ++ rc = EventToXI(event, &xE, &count); ++ if (rc != Success) + { +- rc = EventToXI((InternalEvent*)event, &xE, &count); +- if (rc != Success) +- { +- if (rc != BadMatch) +- ErrorF("[dix] %s: XI conversion failed in CPGFW " +- "(%d, %d).\n", device->name, event->type, rc); +- continue; +- } ++ if (rc != BadMatch) ++ ErrorF("[dix] %s: XI conversion failed in CPGFW " ++ "(%d, %d).\n", device->name, event->any.type, rc); ++ continue; + } ++ } + +- (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); ++ (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); + +- if (xE) ++ /* Don't send touch events if you activate a touch grab. Touch grabs ++ * are handled separately. */ ++ if (xE && grab->type != ET_TouchBegin) ++ { ++ FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); ++ ++ TryClientEvents(rClient(grab), device, xE, count, ++ GetEventFilter(device, xE), ++ GetEventFilter(device, xE), grab); ++ ++ if (grab->pointerMode == GrabModeAsync && ++ event->device_event.touchpoint) + { +- FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); ++ TouchPointInfoPtr ti = event->device_event.touchpoint; + +- TryClientEvents(rClient(grab), device, xE, count, +- GetEventFilter(device, xE), +- GetEventFilter(device, xE), grab); ++ ProcessTouchOwnership(ti->source, ti, XITouchOwnerAccept, ++ FALSE); + } ++ } + +- if (grabinfo->sync.state == FROZEN_NO_EVENT) +- { ++ if (grabinfo->sync.state == FROZEN_NO_EVENT) ++ { ++ /* Touch events are enqueued differently due to pointer ++ * emulation. */ ++ if (grab->type != ET_TouchBegin) ++ { + if (!grabinfo->sync.event) +- grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); +- *grabinfo->sync.event = *event; +- grabinfo->sync.state = FROZEN_WITH_EVENT; ++ grabinfo->sync.event = calloc(1, sizeof(DeviceEvent)); ++ *grabinfo->sync.event = event->device_event; + } ++ grabinfo->sync.state = FROZEN_WITH_EVENT; ++ } + +- if (match & (XI_MATCH | XI2_MATCH)) +- free(xE); /* on core match xE == &core */ +- return grab; +- } ++ if (match & (XI_MATCH | XI2_MATCH)) ++ free(xE); /* on core match xE == &core */ ++ return grab; + } + return NULL; + #undef CORE_MATCH +@@ -3797,8 +4092,13 @@ + { + int i; + WindowPtr pWin = NULL; +- FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; ++ FocusClassPtr focus = device->focus; + BOOL sendCore = (IsMaster(device) && device->coreEvents); ++ DeviceEvent *touch_event = NULL; ++ ++ if (IsPointerEvent((InternalEvent *)event) || ++ IsTouchEvent((InternalEvent *)event)) ++ focus = NULL; + + if (event->type != ET_ButtonPress && + event->type != ET_KeyPress) +@@ -3826,7 +4126,8 @@ + for (; i < focus->traceGood; i++) + { + pWin = focus->trace[i]; +- if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) ++ if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event, ++ sendCore, TRUE)) + return TRUE; + } + +@@ -3836,11 +4137,54 @@ + return FALSE; + } + ++ if (syncEvents.pending && event->type == ET_ButtonPress && ++ (event->flags & XIPointerEmulated)) ++ { ++ QdEventPtr qe; ++ ++ for (qe = syncEvents.pending; qe; qe = qe->next) ++ if (qe->device == device && qe->event->any.type == ET_TouchBegin) ++ break; ++ if (qe) ++ touch_event = &qe->event->device_event; ++ } ++ + for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) + { +- pWin = device->spriteInfo->sprite->spriteTrace[i]; +- if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) +- return TRUE; ++ pWin = device->spriteInfo->sprite->spriteTrace[i]; ++ ++ if (!pWin->optional) ++ continue; ++ ++ /* Touch grabs are checked before pointer grabs. When a touch grab ++ * should be checked first, check_grab is TRUE. */ ++ if (touch_event && touch_event->check_grab) ++ { ++ GrabPtr grab; ++ ++ grab = CheckPassiveGrabsOnWindow(pWin, device, ++ (InternalEvent *)touch_event, ++ FALSE, FALSE); ++ if (grab) ++ { ++ TouchPointInfoPtr ti = touch_event->touchpoint; ++ TouchClientPtr tc = &ti->clients[ti->owner]; ++ ++ device->deviceGrab.ActivateGrab(device, grab, currentTime, ++ TRUE); ++ touch_event->check_grab = FALSE; ++ DeliverTouchOwnershipEvent(tc, ti); ++ return TRUE; ++ } ++ } ++ ++ if (touch_event) ++ touch_event->check_grab = TRUE; ++ ++ if (pWin->optional && ++ CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *)event, ++ sendCore, TRUE)) ++ return TRUE; + } + + return FALSE; +@@ -3962,6 +4306,17 @@ + grabinfo = &thisDev->deviceGrab; + grab = grabinfo->grab; + ++ /* Touch grab deliver is handled in ProcessTouchEvent. */ ++ if (event->any.type == ET_TouchBegin || ++ event->any.type == ET_TouchMotionUnowned) ++ { ++ if (BitIsOn(grab->xi2mask[XIAllDevices], XI_TouchOwnership) || ++ BitIsOn(grab->xi2mask[thisDev->id], XI_TouchOwnership) || ++ (IsMaster(thisDev) && ++ BitIsOn(grab->xi2mask[XIAllMasterDevices], XI_TouchOwnership))) ++ return; ++ } ++ + if (grab->ownerEvents) + { + WindowPtr focus; +@@ -4038,6 +4393,9 @@ + mask = grab->xi2mask[XIAllDevices][evtype/8] | + grab->xi2mask[XIAllMasterDevices][evtype/8] | + grab->xi2mask[thisDev->id][evtype/8]; ++ if (IsTouchEvent(event)) ++ mask |= ++ grab->xi2mask[event->device_event.sourceid][evtype/8]; + /* try XI2 event */ + FixUpEventFromWindow(pSprite, xi2, grab->window, None, TRUE); + /* XXX: XACE */ +@@ -5171,7 +5529,7 @@ + free(syncEvents.pending); + syncEvents.pending = next; + } +- syncEvents.pendtail = &syncEvents.pending; ++ syncEvents.pendtail = NULL; + syncEvents.playingEvents = FALSE; + syncEvents.time.months = 0; + syncEvents.time.milliseconds = 0; /* hardly matters */ +Index: xorg-server/dix/getevents.c +=================================================================== +--- xorg-server.orig/dix/getevents.c 2011-08-24 12:56:49.825650624 +0300 ++++ xorg-server/dix/getevents.c 2011-08-24 12:57:12.195650944 +0300 +@@ -47,6 +47,7 @@ + #include "eventstr.h" + #include "eventconvert.h" + #include "inpututils.h" ++#include "windowstr.h" + + #include <X11/extensions/XKBproto.h> + #include "xkbsrv.h" +@@ -160,7 +161,7 @@ + (1 << (key_code & 7))); + } + +-static void ++void + init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms) + { + memset(event, 0, sizeof(DeviceEvent)); +@@ -172,6 +173,18 @@ + } + + static void ++init_touch_ownership(DeviceIntPtr dev, TouchOwnershipEvent *event, Time ms) ++{ ++ memset(event, 0, sizeof(TouchOwnershipEvent)); ++ event->header = ET_Internal; ++ event->type = ET_TouchOwnership; ++ event->length = sizeof(TouchOwnershipEvent); ++ event->time = ms; ++ event->deviceid = dev->id; ++ event->sourceid = dev->id; ++} ++ ++static void + init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail) + { + memset(event, 0, sizeof(RawDeviceEvent)); +@@ -212,7 +225,8 @@ + if (valuator_mask_isset(mask, i)) + { + SetBit(event->valuators.mask, i); +- if (valuator_get_mode(dev, i) == Absolute) ++ if (!IsTouchEvent((InternalEvent *)event) && ++ valuator_get_mode(dev, i) == Absolute) + SetBit(event->valuators.mode, i); + event->valuators.data[i] = valuator_mask_get(mask, i); + event->valuators.data_frac[i] = +@@ -1067,24 +1081,14 @@ + } + + static void +-transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask) ++transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask, int *x, int *y) + { +- struct pixman_f_vector p; +- +- /* p' = M * p in homogeneous coordinates */ +- p.v[0] = (valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) : +- dev->last.valuators[0]); +- p.v[1] = (valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) : +- dev->last.valuators[1]); +- p.v[2] = 1.0; ++ struct pixman_f_vector p = {.v = {*x, *y, 1}}; + + pixman_f_transform_point(&dev->transform, &p); + +- if (valuator_mask_isset(mask, 0)) +- valuator_mask_set(mask, 0, lround(p.v[0])); +- +- if (valuator_mask_isset(mask, 1)) +- valuator_mask_set(mask, 1, lround(p.v[1])); ++ *x = lround(p.v[0]); ++ *y = lround(p.v[1]); + } + + /** +@@ -1126,7 +1130,10 @@ + switch (type) + { + case MotionNotify: +- if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) ++ if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0 || ++ (pDev->touch && pDev->touch->active_touches > 1 && ++ (pDev->touch->mode == XIDependentTouch || ++ pDev->touch->mode == XISemiMultitouch))) + return 0; + break; + case ButtonPress: +@@ -1178,7 +1185,16 @@ + } + } + +- transformAbsolute(pDev, &mask); ++ x = (valuator_mask_isset(&mask, 0) ? valuator_mask_get(&mask, 0) : ++ pDev->last.valuators[0]); ++ y = (valuator_mask_isset(&mask, 1) ? valuator_mask_get(&mask, 1) : ++ pDev->last.valuators[1]); ++ transformAbsolute(pDev, &mask, &x, &y); ++ if (valuator_mask_isset(&mask, 0)) ++ valuator_mask_set(&mask, 0, x); ++ if (valuator_mask_isset(&mask, 1)) ++ valuator_mask_set(&mask, 1, y); ++ + moveAbsolute(pDev, &x, &y, &mask); + } else { + if (flags & POINTER_ACCELERATE) { +@@ -1301,6 +1317,130 @@ + return num_events; + } + ++int ++GetTouchOwnershipEvents(EventList *events, DeviceIntPtr pDev, ++ TouchPointInfoPtr ti, uint8_t reason, XID resource, ++ uint32_t flags) ++{ ++ TouchClassPtr t = pDev->touch; ++ TouchOwnershipEvent *event; ++ CARD32 ms = GetTimeInMillis(); ++ ++ if (!pDev->enabled || !t || !ti) ++ return 0; ++ ++ if (reason != XITouchOwnerAccept && reason != XITouchOwnerRejectEnd) ++ return 0; ++ ++ event = (TouchOwnershipEvent *) events->event; ++ init_touch_ownership(pDev, event, ms); ++ ++ event->touchid = ti->client_id; ++ event->resource = resource; ++ event->flags = flags; ++ ++ return 1; ++} ++ ++/** ++ * Get events for a touch. Generates a TouchBegin event if end is not set and ++ * the touch id is not active. Generates a TouchMotion event if end is not set ++ * and the touch id is active. Generates a TouchEnd event if end is set and the ++ * touch id is active. ++ * ++ * events is not NULL-terminated; the return value is the number of events. ++ * The DDX is responsible for allocating the event structure in the first ++ * place via GetMaximumEventsNum(), and for freeing it. ++ */ ++int ++GetTouchEvents(EventList *events, DeviceIntPtr pDev, TouchPointInfoPtr ti, ++ uint16_t type, uint32_t flags, const ValuatorMask *mask_in) ++{ ++ ScreenPtr scr = pDev->spriteInfo->sprite->hotPhys.pScreen; ++ TouchClassPtr t = pDev->touch; ++ DeviceEvent *event; ++ CARD32 ms = GetTimeInMillis(); ++ ValuatorMask mask; ++ int x, y; /* in screen co-ord space */ ++ float x_frac = 0.0, y_frac = 0.0; /* as above */ ++ int i; ++ ++ if (!pDev->enabled || !t || t->x_axis == -1 || t->y_axis == -1) ++ return 0; ++ ++ event = (DeviceEvent *) events->event; ++ init_event(pDev, event, ms); ++ ++ switch (type) { ++ case XI_TouchBegin: ++ event->type = ET_TouchBegin; ++ /* If we're starting a touch, we must have x & y co-ordinates. */ ++ if (!valuator_mask_isset(mask_in, t->x_axis) || ++ !valuator_mask_isset(mask_in, t->y_axis)) ++ { ++ DebugF("%s: Attempted to start touch without x/y (driver bug)\n", ++ pDev->name); ++ return 0; ++ } ++ break; ++ case XI_TouchUpdate: ++ event->type = ET_TouchMotion; ++ break; ++ case XI_TouchEnd: ++ event->type = ET_TouchEnd; ++ break; ++ default: ++ return 0; ++ } ++ ++ event->touchpoint = ti; ++ ++ valuator_mask_copy(&mask, mask_in); ++ ++ /* Get our screen event co-ordinates (root_x/root_y/event_x/event_y): ++ * these come from the touchpoint in Absolute mode, or the sprite in ++ * Relative. */ ++ if (t->mode == XIDirectTouch) { ++ if (valuator_mask_isset(&mask, t->x_axis)) ++ x = valuator_mask_get(&mask, t->x_axis); ++ else ++ x = ti->valuators[t->x_axis]; ++ x = rescaleValuatorAxis(x, 0.0, &x_frac, ++ (AxisInfoPtr)(t->axes + t->x_axis), ++ NULL, scr->width); ++ ++ if (valuator_mask_isset(&mask, t->y_axis)) ++ y = valuator_mask_get(&mask, t->y_axis); ++ else ++ y = ti->valuators[t->y_axis]; ++ y = rescaleValuatorAxis(y, 0.0, &y_frac, ++ (AxisInfoPtr)(t->axes + t->y_axis), ++ NULL, scr->height); ++ ++ transformAbsolute(pDev, &mask, &x, &y); ++ } ++ else { ++ x = pDev->spriteInfo->sprite->hotPhys.x; ++ y = pDev->spriteInfo->sprite->hotPhys.y; ++ } ++ ++ event->root_x = x; ++ event->root_y = y; ++ event->root_x_frac = x_frac; ++ event->root_y_frac = y_frac; ++ event->detail.touch = ti->client_id; ++ event->flags = flags; ++ ++ set_valuators(pDev, event, &mask); ++ for (i = 0; i < t->num_axes; i++) ++ { ++ if (valuator_mask_isset(&mask, i)) ++ ti->valuators[i] = valuator_mask_get(&mask, i); ++ } ++ ++ return 1; ++} ++ + /** + * Synthesize a single motion event for the core pointer. + * +Index: xorg-server/dix/grabs.c +=================================================================== +--- xorg-server.orig/dix/grabs.c 2011-08-24 12:52:43.795647119 +0300 ++++ xorg-server/dix/grabs.c 2011-08-24 12:56:49.855650623 +0300 +@@ -60,6 +60,7 @@ + #include "dixgrabs.h" + #include "xace.h" + #include "exevents.h" ++#include "mi.h" + + #define BITMASK(i) (((Mask)1) << ((i) & 31)) + #define MASKIDX(i) ((i) >> 5) +@@ -243,6 +244,25 @@ + } + + /** ++ * Returns the event type to match when comparing grabs. ++ */ ++static uint32_t ++GetGrabEventMatch(GrabPtr pGrab) ++{ ++ if (pGrab->grabtype != GRABTYPE_XI2) ++ return pGrab->type; ++ ++ if (pGrab->type == XI_TouchBegin || ++ pGrab->type == XI_TouchUpdate || ++ pGrab->type == XI_TouchUpdateUnowned || ++ pGrab->type == XI_TouchOwnership || ++ pGrab->type == XI_TouchEnd) ++ return XI_TouchBegin; ++ ++ return pGrab->type; ++} ++ ++/** + * Compares two grabs and returns TRUE if the first grab matches the second + * grab. + * +@@ -261,6 +281,8 @@ + unsigned int any_modifier = (pFirstGrab->grabtype == GRABTYPE_XI2) ? + (unsigned int)XIAnyModifier : + (unsigned int)AnyModifier; ++ uint32_t first_type = GetGrabEventMatch(pFirstGrab); ++ uint32_t second_type = GetGrabEventMatch(pSecondGrab); + + if (pFirstGrab->grabtype != pSecondGrab->grabtype) + return FALSE; +@@ -288,8 +310,8 @@ + (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) + return FALSE; + +- if (pFirstGrab->type != pSecondGrab->type) +- return FALSE; ++ if (first_type != second_type) ++ return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || + GrabSupersedesSecond(pSecondGrab, pFirstGrab)) +Index: xorg-server/dix/inpututils.c +=================================================================== +--- xorg-server.orig/dix/inpututils.c 2011-08-24 12:52:43.835647119 +0300 ++++ xorg-server/dix/inpututils.c 2011-08-24 12:56:49.855650623 +0300 +@@ -36,6 +36,7 @@ + #include "xkbsrv.h" + #include "xkbstr.h" + #include "inpututils.h" ++#include "eventstr.h" + + /* Check if a button map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy. */ +@@ -556,3 +557,158 @@ + + return ret; + } ++ ++/** ++ * Given the DDX-facing ID (which is _not_ DeviceEvent::detail.touch), find the ++ * associated TouchPointInfoRec. ++ */ ++TouchPointInfoPtr ++FindTouchPointByDDXID(DeviceIntPtr dev, uint32_t ddx_id) ++{ ++ TouchClassPtr t = dev->touch; ++ TouchPointInfoPtr ti; ++ int i; ++ ++ if (!t) ++ return NULL; ++ ++ for (i = 0; i < t->num_touches; i++) ++ { ++ ti = &t->touches[i]; ++ if (ti->active && ti->ddx_id == ddx_id && !ti->ddx_pending_finish) ++ return ti; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * Given a client-facing ID (e.g. DeviceEvent::detail.touch), find the ++ * associated TouchPointInfoRec. ++ */ ++TouchPointInfoPtr ++FindTouchPointByClientID(DeviceIntPtr dev, uint32_t client_id) ++{ ++ TouchClassPtr t = dev->touch; ++ TouchPointInfoPtr ti; ++ int i; ++ ++ if (!t) ++ return NULL; ++ ++ for (i = 0; i < t->num_touches; i++) ++ { ++ ti = &t->touches[i]; ++ if (ti->active && ti->client_id == client_id) ++ return ti; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * Given a unique DDX ID for a touchpoint, create a touchpoint record in the ++ * server and return the client-facing ID. ++ * ++ * Returns 0 on failure (i.e. if another touch with that ID is already active, ++ * allocation failure). ++ */ ++_X_EXPORT TouchPointInfoPtr ++BeginTouchPoint(DeviceIntPtr dev, uint32_t ddx_id) ++{ ++ int i; ++ TouchClassPtr t = dev->touch; ++ TouchPointInfoPtr ti; ++ ++ if (!t) ++ return NULL; ++ ++ /* Look for another active touchpoint with the same DDX ID. It's entirely ++ * legitimate for a touchpoint to still exist with the same DDX ID but ++ * be in the pending_finish state as it waits for a client to release its ++ * grab, so allow for that. */ ++ if (FindTouchPointByDDXID(dev, ddx_id)) ++ return NULL; ++ ++ for (i = 0; i < t->num_touches; i++) ++ { ++ ti = &t->touches[i]; ++ if (!ti->active) { ++ ti->source = dev; ++ ti->active = TRUE; ++ ti->ddx_id = ddx_id; ++ ti->client_id = t->next_client_id; ++ ti->owner = -1; ++ ti->active_clients = 0; ++ ti->accepted = FALSE; ++ ti->pending_finish = FALSE; ++ t->active_touches++; ++next_touch_id: ++ t->next_client_id++; ++ if (t->next_client_id == 0) ++ t->next_client_id = 1; ++ if (FindTouchPointByClientID(dev, t->next_client_id)) ++ goto next_touch_id; /* n'th time's a charm */ ++ return ti; ++ } ++ } ++ ++ /* If we get here, then we've run out of touches. */ ++ LogMessage(X_WARNING, "%s: no more touches available\n", dev->name); ++ ++ return NULL; ++} ++ ++/** ++ * Releases a touchpoint for use: this must only be called after all events ++ * related to that touchpoint have been sent and finalised. Called from ++ * ProcessTouchEvent and friends. Not by you. ++ */ ++void ++EndTouchPoint(DeviceIntPtr dev, TouchPointInfoPtr ti) ++{ ++ int i; ++ TouchClassPtr t = dev->touch; ++ DeviceIntPtr masterdev = dev->u.master; ++ QdEventPtr qe; ++ ++ if (dev->deviceGrab.sync.event && ++ dev->deviceGrab.sync.event->touchpoint == ti) ++ dev->deviceGrab.sync.event->touchpoint = NULL; ++ ++ if (masterdev && masterdev->deviceGrab.sync.event && ++ masterdev->deviceGrab.sync.event->touchpoint == ti) ++ masterdev->deviceGrab.sync.event->touchpoint = NULL; ++ ++ ti->source = NULL; ++ ti->pending_finish = FALSE; ++ ti->sprite.spriteTraceGood = 0; ++ ti->ddx_id = 0; ++ ti->first_history = ti->history; ++ ti->next_history = ti->history; ++ ti->emulate_pointer = FALSE; ++ ti->owner = -1; ++ ti->accepted = FALSE; ++ ti->active_clients = 0; ++ ti->ddx_pending_finish = FALSE; ++ t->active_touches--; ++ ++ if (dev->touch->emulate == ti) ++ { ++ dev->touch->emulate = NULL; ++ if (dev->u.master) ++ dev->u.master->emulate_dev = NULL; ++ ++ for (qe = syncEvents.pending; qe; qe = qe->next) ++ if ((qe->event->any.type == ET_TouchEnd || ++ qe->event->any.type == ET_ButtonRelease) && ++ qe->event->device_event.touchpoint == ti) ++ qe->event->device_event.touchpoint = NULL; ++ } ++ ++ for (i = 0; i < ti->num_valuators; i++) ++ ti->valuators[i] = 0; ++ ++ ti->client_id = 0; ++ ti->active = FALSE; ++} +Index: xorg-server/dix/window.c +=================================================================== +--- xorg-server.orig/dix/window.c 2011-08-24 12:52:43.845647121 +0300 ++++ xorg-server/dix/window.c 2011-08-24 12:57:14.735650978 +0300 +@@ -110,6 +110,7 @@ + #include "windowstr.h" + #include "input.h" + #include "inputstr.h" ++#include "exevents.h" + #include "resource.h" + #include "colormapst.h" + #include "cursorstr.h" +@@ -2875,8 +2876,10 @@ + if (!fromConfigure && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); + } +- if (wasRealized && !fromConfigure) ++ if (wasRealized && !fromConfigure) { + WindowsRestructured (); ++ WindowGone(pWin); ++ } + return Success; + } + +@@ -2959,8 +2962,10 @@ + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); + } +- if (wasRealized) ++ if (wasRealized) { + WindowsRestructured (); ++ WindowGone(pWin); ++ } + } + + +Index: xorg-server/hw/xfree86/common/xf86Module.h +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Module.h 2011-08-24 12:52:43.775647117 +0300 ++++ xorg-server/hw/xfree86/common/xf86Module.h 2011-08-24 12:56:49.855650623 +0300 +@@ -83,7 +83,7 @@ + */ + #define ABI_ANSIC_VERSION SET_ABI_VERSION(0, 4) + #define ABI_VIDEODRV_VERSION SET_ABI_VERSION(10, 0) +-#define ABI_XINPUT_VERSION SET_ABI_VERSION(12, 2) ++#define ABI_XINPUT_VERSION SET_ABI_VERSION(12, 3) + #define ABI_EXTENSION_VERSION SET_ABI_VERSION(5, 0) + #define ABI_FONT_VERSION SET_ABI_VERSION(0, 6) + +Index: xorg-server/hw/xfree86/common/xf86Xinput.c +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:52:43.755647120 +0300 ++++ xorg-server/hw/xfree86/common/xf86Xinput.c 2011-08-24 12:57:17.855651025 +0300 +@@ -1358,6 +1358,16 @@ + max_res, mode); + } + ++void ++xf86InitTouchValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, ++ int minval, int maxval, int resolution) ++{ ++ if (!dev || !dev->touch) ++ return; ++ ++ InitTouchValuatorAxisStruct(dev, axnum, label, minval, maxval, resolution); ++} ++ + /* + * Set the valuator values to be in synch with dix/event.c + * DefineInitialRootWindow(). +@@ -1409,4 +1419,50 @@ + EnableDevice(dev, TRUE); + } + ++/** ++ * Post a touch event with optional valuators. If this is the first touch in ++ * the sequence, at least x & y valuators must be provided. If end is TRUE, ++ * then this is taken to be the last touch in the touch sequence. ++ */ ++void ++xf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid, uint16_t type, ++ uint32_t flags, const ValuatorMask *mask) ++{ ++ int i, nevents; ++ TouchPointInfoPtr ti = FindTouchPointByDDXID(dev, touchid); ++ ++ if (ti && type == XI_TouchBegin) ++ { ++ xf86Msg(X_ERROR, ++ "%s: Tried to post touch begin for existing touch %u\n", ++ dev->name, touchid); ++ return; ++ } ++ ++ if (!ti) ++ { ++ if (type != XI_TouchBegin) ++ { ++ xf86Msg(X_ERROR, ++ "%s: Tried to post event for non-existent touch %u\n", ++ dev->name, touchid); ++ return; ++ } ++ ++ ti = BeginTouchPoint(dev, touchid); ++ if (!ti) ++ { ++ xf86Msg(X_ERROR, "%s: Couldn't create touchpoint\n", dev->name); ++ return; ++ } ++ } ++ ++ if (type == XI_TouchEnd) ++ ti->ddx_pending_finish = TRUE; ++ ++ nevents = GetTouchEvents(xf86Events, dev, ti, type, flags, mask); ++ for (i = 0; i < nevents; i++) ++ mieqEnqueue(dev, (InternalEvent *)((xf86Events + i)->event)); ++} ++ + /* end of xf86Xinput.c */ +Index: xorg-server/hw/xfree86/common/xf86Xinput.h +=================================================================== +--- xorg-server.orig/hw/xfree86/common/xf86Xinput.h 2011-08-24 12:52:43.785647118 +0300 ++++ xorg-server/hw/xfree86/common/xf86Xinput.h 2011-08-24 12:57:17.875651024 +0300 +@@ -141,6 +141,9 @@ + const int *valuators); + extern _X_EXPORT void xf86PostKeyboardEvent(DeviceIntPtr device, unsigned int key_code, + int is_down); ++extern _X_EXPORT void xf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid, ++ uint16_t type, uint32_t flags, ++ const ValuatorMask *mask); + extern _X_EXPORT InputInfoPtr xf86FirstLocalDevice(void); + extern _X_EXPORT int xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min); + extern _X_EXPORT void xf86XInputSetScreen(InputInfoPtr pInfo, int screen_number, int x, int y); +@@ -148,6 +151,8 @@ + extern _X_EXPORT void xf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, + int maxval, int resolution, int min_res, + int max_res, int mode); ++extern _X_EXPORT void xf86InitTouchValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, ++ int minval, int maxval, int resolution); + extern _X_EXPORT void xf86InitValuatorDefaults(DeviceIntPtr dev, int axnum); + extern _X_EXPORT void xf86AddEnabledDevice(InputInfoPtr pInfo); + extern _X_EXPORT void xf86RemoveEnabledDevice(InputInfoPtr pInfo); +Index: xorg-server/include/dix.h +=================================================================== +--- xorg-server.orig/include/dix.h 2011-08-24 12:56:49.835650626 +0300 ++++ xorg-server/include/dix.h 2011-08-24 12:56:49.865650624 +0300 +@@ -375,7 +375,7 @@ + extern GrabPtr CheckPassiveGrabsOnWindow( + WindowPtr /* pWin */, + DeviceIntPtr /* device */, +- DeviceEvent * /* event */, ++ InternalEvent * /* event */, + BOOL /* checkCore */, + BOOL /* activate */); + +@@ -520,6 +520,11 @@ + DeviceIntPtr /* dev */, + xEvent* /* events */); + ++extern void RemoveTouchEventsFromQueue( ++ DeviceIntPtr /* dev */, ++ Bool /*touch*/, ++ Bool /*ignoreOwned*/); ++ + #ifdef PANORAMIX + extern _X_EXPORT void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff); + #endif +@@ -531,6 +536,8 @@ + + extern _X_EXPORT int ffs(int i); + ++extern void init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms); ++ + + /* + * ServerGrabCallback stuff +@@ -574,6 +581,7 @@ + extern Bool _X_EXPORT IsPointerDevice( DeviceIntPtr dev); + extern Bool _X_EXPORT IsKeyboardDevice(DeviceIntPtr dev); + extern Bool IsPointerEvent(InternalEvent *event); ++extern Bool IsTouchEvent(InternalEvent *event); + extern _X_EXPORT Bool IsMaster(DeviceIntPtr dev); + extern _X_EXPORT Bool IsFloating(DeviceIntPtr dev); + +Index: xorg-server/include/events.h +=================================================================== +--- xorg-server.orig/include/events.h 2011-08-24 12:52:43.905647121 +0300 ++++ xorg-server/include/events.h 2011-08-24 12:57:17.895651025 +0300 +@@ -26,6 +26,7 @@ + #define EVENTS_H + typedef struct _DeviceEvent DeviceEvent; + typedef struct _DeviceChangedEvent DeviceChangedEvent; ++typedef struct _TouchOwnershipEvent TouchOwnershipEvent; + #if XFreeXDGA + typedef struct _DGAEvent DGAEvent; + #endif +Index: xorg-server/include/eventstr.h +=================================================================== +--- xorg-server.orig/include/eventstr.h 2011-08-24 12:52:43.915647119 +0300 ++++ xorg-server/include/eventstr.h 2011-08-24 12:57:14.785650979 +0300 +@@ -65,6 +65,11 @@ + ET_RawButtonRelease, + ET_RawMotion, + ET_XQuartz, ++ ET_TouchBegin, ++ ET_TouchEnd, ++ ET_TouchMotion, ++ ET_TouchMotionUnowned, ++ ET_TouchOwnership, + ET_Internal = 0xFF /* First byte */ + }; + +@@ -90,6 +95,7 @@ + union { + uint32_t button; /**< Button number */ + uint32_t key; /**< Key code */ ++ uint32_t touch; /**< Touch ID (client_id) */ + } detail; + int16_t root_x; /**< Pos relative to root window in integral data */ + float root_x_frac; /**< Pos relative to root window in frac part */ +@@ -117,8 +123,28 @@ + Window root; /**< Root window of the event */ + 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 */ ++ TouchPointInfoPtr touchpoint; ++ Bool check_grab; + }; + ++/** ++ * Generated internally whenever a touch ownership chain changes - an owner ++ * has accepted or rejected a touch, or a grab/event selection in the delivery ++ * chain has been removed. ++ */ ++struct _TouchOwnershipEvent ++{ ++ unsigned char header; /**< Always ET_Internal */ ++ enum EventType type; /**< One of EventType */ ++ int length; /**< Length in bytes */ ++ Time time; /**< Time in ms */ ++ int deviceid; /**< Device to post this event for */ ++ int sourceid; /**< The physical source device */ ++ uint32_t touchid; /**< Touch ID (client_id) */ ++ uint32_t resource; /**< Provoking grab or event selection */ ++ uint32_t flags; /**< Flags to be copied into the generated event */ ++}; + + /* Flags used in DeviceChangedEvent to signal if the slave has changed */ + #define DEVCHANGE_SLAVE_SWITCH 0x2 +@@ -234,6 +260,7 @@ + } any; + DeviceEvent device_event; + DeviceChangedEvent changed_event; ++ TouchOwnershipEvent touch_ownership_event; + #if XFreeXDGA + DGAEvent dga_event; + #endif +Index: xorg-server/include/exevents.h +=================================================================== +--- xorg-server.orig/include/exevents.h 2011-08-24 12:52:43.935647121 +0300 ++++ xorg-server/include/exevents.h 2011-08-24 12:56:49.865650624 +0300 +@@ -51,6 +51,14 @@ + int /* max_res */, + int /* mode */); + ++extern _X_EXPORT void InitTouchValuatorAxisStruct( ++ DeviceIntPtr /* dev */, ++ int /* axnum */, ++ Atom /* label */, ++ int /* minval */, ++ int /* maxval */, ++ int /* resolution */); ++ + /* Input device properties */ + extern _X_EXPORT void XIDeleteAllDeviceProperties( + DeviceIntPtr /* device */ +@@ -199,6 +207,14 @@ + GrabMask* /* eventMask */); + + extern int ++GrabTouch( ++ ClientPtr /* client */, ++ DeviceIntPtr /* dev */, ++ DeviceIntPtr /* mod_dev */, ++ GrabParameters* /* param */, ++ GrabMask* /* eventMask */); ++ ++extern int + SelectForWindow( + DeviceIntPtr /* dev */, + WindowPtr /* pWin */, +@@ -222,6 +238,10 @@ + WindowPtr /* pWin */, + XID /* id */); + ++extern void ++WindowGone( ++ WindowPtr /* win */); ++ + extern int + SendEvent ( + ClientPtr /* client */, +@@ -309,4 +329,14 @@ + extern int + XICheckInvalidMaskBits(ClientPtr client, unsigned char *mask, int len); + ++extern void ++ProcessTouchOwnership(DeviceIntPtr dev, TouchPointInfoPtr ti, uint8_t reason, ++ Bool touch_grab); ++ ++extern int ++DeliverTouchOwnershipEvent(TouchClientPtr client, TouchPointInfoPtr ti); ++ ++extern int ++ReleaseButton(DeviceIntPtr device, int button); ++ + #endif /* EXEVENTS_H */ +Index: xorg-server/include/input.h +=================================================================== +--- xorg-server.orig/include/input.h 2011-08-24 12:52:43.895647122 +0300 ++++ xorg-server/include/input.h 2011-08-24 12:56:49.865650624 +0300 +@@ -106,6 +106,8 @@ + typedef struct _ValuatorClassRec *ValuatorClassPtr; + typedef struct _ClassesRec *ClassesPtr; + typedef struct _SpriteRec *SpritePtr; ++typedef struct _TouchClassRec *TouchClassPtr; ++typedef struct _TouchPointInfo *TouchPointInfoPtr; + typedef union _GrabMask GrabMask; + + typedef struct _EventList { +@@ -320,6 +322,12 @@ + extern _X_EXPORT Bool InitFocusClassDeviceStruct( + DeviceIntPtr /*device*/); + ++extern _X_EXPORT Bool InitTouchClassDeviceStruct( ++ DeviceIntPtr /*device*/, ++ unsigned int /*max_touches*/, ++ unsigned int /*mode*/, ++ unsigned int /*numAxes*/); ++ + typedef void (*BellProcPtr)( + int /*percent*/, + DeviceIntPtr /*device*/, +@@ -469,6 +477,22 @@ + int key_code, + const ValuatorMask *mask); + ++extern int GetTouchEvents( ++ EventListPtr events, ++ DeviceIntPtr pDev, ++ TouchPointInfoPtr ti, ++ uint16_t type, ++ uint32_t flags, ++ const ValuatorMask *mask); ++ ++extern int GetTouchOwnershipEvents( ++ EventListPtr events, ++ DeviceIntPtr pDev, ++ TouchPointInfoPtr ti, ++ uint8_t mode, ++ XID resource, ++ uint32_t flags); ++ + extern int GetProximityEvents( + EventListPtr events, + DeviceIntPtr pDev, +@@ -533,6 +557,18 @@ + extern _X_EXPORT InputAttributes *DuplicateInputAttributes(InputAttributes *attrs); + extern _X_EXPORT void FreeInputAttributes(InputAttributes *attrs); + ++/* DDX touch API: create with CreateTouchPoint, use its returned ID to lookup ++ * with FindTouchPoint, and eventually end with FinishTouchPoint. */ ++extern TouchPointInfoPtr BeginTouchPoint(DeviceIntPtr dev, uint32_t ddx_id); ++extern TouchPointInfoPtr FindTouchPointByDDXID(DeviceIntPtr dev, ++ uint32_t ddx_id); ++extern TouchPointInfoPtr FindTouchPointByClientID(DeviceIntPtr dev, ++ uint32_t client_id); ++extern void EndTouchPoint(DeviceIntPtr dev, TouchPointInfoPtr ti); ++/* Internal use only, DDX this is not for you */ ++extern Bool InitTouchPoint(TouchClassPtr touch, int index); ++extern void FreeTouchPoint(DeviceIntPtr dev, int index); ++ + /* misc event helpers */ + extern Mask GetEventMask(DeviceIntPtr dev, xEvent* ev, InputClientsPtr clients); + extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event); +Index: xorg-server/include/inputstr.h +=================================================================== +--- xorg-server.orig/include/inputstr.h 2011-08-24 12:52:43.885647120 +0300 ++++ xorg-server/include/inputstr.h 2011-08-24 12:57:12.215650943 +0300 +@@ -49,6 +49,8 @@ + #ifndef INPUTSTRUCT_H + #define INPUTSTRUCT_H + ++#include <X11/extensions/XI2proto.h> ++ + #include <pixman.h> + #include "input.h" + #include "window.h" +@@ -71,7 +73,7 @@ + * events to the protocol, the server will not support these events until + * this number here is bumped. + */ +-#define XI2LASTEVENT 17 /* XI_RawMotion */ ++#define XI2LASTEVENT XI_TouchUpdateUnowned + #define XI2MASKSIZE ((XI2LASTEVENT + 7)/8) /* no of bits for masks */ + + /** +@@ -244,6 +246,9 @@ + + } SpriteRec; + ++#define DeepestSpriteWin(sprite) \ ++ ((sprite)->spriteTrace[(sprite)->spriteTraceGood - 1]) ++ + typedef struct _KeyClassRec { + int sourceid; + CARD8 down[DOWN_LENGTH]; +@@ -254,11 +259,11 @@ + + typedef struct _AxisInfo { + int resolution; +- int min_resolution; +- int max_resolution; + int min_value; + int max_value; + Atom label; ++ int min_resolution; ++ int max_resolution; + CARD8 mode; + } AxisInfo, *AxisInfoPtr; + +@@ -284,6 +289,75 @@ + ValuatorAccelerationRec accelScheme; + } ValuatorClassRec; + ++typedef enum { ++ TOUCH_GRAB, ++ TOUCH_SELECT, ++ TOUCH_SELECT_UNOWNED ++} TouchClientType; ++ ++typedef struct _TouchClientRec { ++ ClientPtr client; ++ WindowPtr window; ++ TouchClientType type; ++ DeviceIntPtr device; ++ DeviceIntPtr source; ++ GrabPtr grab; ++} TouchClientRec, *TouchClientPtr; ++ ++typedef struct _TouchPointInfo { ++ DeviceIntPtr source; ++ 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 */ ++ Bool ddx_pending_finish; ++ 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 owner; ++ Bool accepted; ++ int *valuators; /* last recorded axis values */ ++ int num_valuators; /* == TouchClassInfo::num_axes */ ++#if 0 ++ XID *listeners; /* grabs/event selection IDs receiving ++ * events for this touch */ ++ int num_listeners; ++ int num_grabs; /* number of open grabs on this touch ++ * which have not accepted or rejected */ ++ WindowPtr select_win; ++ Bool select_unowned; ++#endif ++ Bool emulate_pointer; ++ InternalEvent *begin_event; /* Touch begin event for history */ ++ InternalEvent *history; /* Touch motion and end history events */ ++ unsigned int history_size; /* Size of history ring buffer */ ++ InternalEvent *first_history; /* Pointer to first event in history */ ++ InternalEvent *next_history; /* Pointer to next available event */ ++} TouchPointInfoRec; ++ ++typedef struct _TouchAxisInfo { ++ int resolution; ++ int min_value; ++ int max_value; ++ Atom label; ++} TouchAxisInfoRec, *TouchAxisInfoPtr; ++ ++typedef struct _TouchClassRec { ++ TouchAxisInfoPtr axes; ++ unsigned short num_axes; ++ TouchPointInfoPtr touches; ++ unsigned short num_touches; /* number of allocated touches */ ++ unsigned short max_touches; /* maximum number of touches, may be 0 */ ++ unsigned short active_touches; /* number of active touches */ ++ CARD8 mode; /* ::XIDirectTouch, XIDependentTouch */ ++ uint32_t next_client_id; /* next client_id to give out */ ++ int x_axis; /* axis number of x axis */ ++ int y_axis; /* axis number of y axis */ ++ TouchPointInfoPtr emulate; ++} TouchClassRec; ++ + typedef struct _ButtonClassRec { + int sourceid; + CARD8 numButtons; +@@ -388,6 +462,7 @@ + typedef struct _ClassesRec { + KeyClassPtr key; + ValuatorClassPtr valuator; ++ TouchClassPtr touch; + ButtonClassPtr button; + FocusClassPtr focus; + ProximityClassPtr proximity; +@@ -512,6 +587,7 @@ + int id; + KeyClassPtr key; + ValuatorClassPtr valuator; ++ TouchClassPtr touch; + ButtonClassPtr button; + FocusClassPtr focus; + ProximityClassPtr proximity; +@@ -533,6 +609,8 @@ + DeviceIntPtr master; /* master device */ + DeviceIntPtr lastSlave; /* last slave device used */ + } u; ++ DeviceIntPtr emulate_dev; ++ Bool process_touch; + + /* last valuator values recorded, not posted to client; + * for slave devices, valuators is in device coordinates +@@ -592,7 +670,7 @@ + */ + typedef struct _EventSyncInfo { + QdEventPtr pending, /**< list of queued events */ +- *pendtail; /**< last event in list */ ++ pendtail; /**< last event in list */ + /** The device to replay events for. Only set in AllowEvents(), in which + * case it is set to the device specified in the request. */ + DeviceIntPtr replayDev; /* kludgy rock to put flag for */ +Index: xorg-server/include/protocol-versions.h +=================================================================== +--- xorg-server.orig/include/protocol-versions.h 2011-08-24 12:56:49.825650624 +0300 ++++ xorg-server/include/protocol-versions.h 2011-08-24 12:57:14.795650980 +0300 +@@ -131,7 +131,7 @@ + + /* X Input */ + #define SERVER_XI_MAJOR_VERSION 2 +-#define SERVER_XI_MINOR_VERSION 0 ++#define SERVER_XI_MINOR_VERSION 1 + + /* XKB */ + #define SERVER_XKB_MAJOR_VERSION 1 +Index: xorg-server/mi/mieq.c +=================================================================== +--- xorg-server.orig/mi/mieq.c 2011-08-24 12:52:43.945647123 +0300 ++++ xorg-server/mi/mieq.c 2011-08-24 12:57:14.815650981 +0300 +@@ -269,8 +269,15 @@ + case ET_ProximityOut: + case ET_Hierarchy: + case ET_DeviceChanged: ++ case ET_TouchBegin: ++ case ET_TouchEnd: ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: + event->device_event.deviceid = dev->id; + break; ++ case ET_TouchOwnership: ++ event->touch_ownership_event.deviceid = dev->id; ++ break; + #if XFreeXDGA + case ET_DGAEvent: + break; +@@ -419,7 +426,7 @@ + + /* Check for the SD's master in case the device got detached + * during event processing */ +- if (master && dev->u.master) ++ if (master && dev->u.master && !IsTouchEvent(&mevent)) + master->public.processInputProc(&mevent, master); + } + } +Index: xorg-server/test/input.c +=================================================================== +--- xorg-server.orig/test/input.c 2011-08-24 12:52:43.725647116 +0300 ++++ xorg-server/test/input.c 2011-08-24 12:56:49.865650624 +0300 +@@ -278,6 +278,11 @@ + dix_event_to_core_fail(ET_ProximityOut + 1, BadImplementation); + dix_event_to_core_fail(ET_ProximityIn, BadMatch); + dix_event_to_core_fail(ET_ProximityOut, BadMatch); ++ dix_event_to_core_fail(ET_TouchBegin, BadMatch); ++ dix_event_to_core_fail(ET_TouchMotion, BadMatch); ++ dix_event_to_core_fail(ET_TouchMotionUnowned, BadMatch); ++ dix_event_to_core_fail(ET_TouchOwnership, BadMatch); ++ dix_event_to_core_fail(ET_TouchEnd, BadMatch); + + dix_event_to_core(ET_KeyPress); + dix_event_to_core(ET_KeyRelease); +@@ -423,6 +428,32 @@ + } + + ++static void dix_event_to_xi2_conversion(void) ++{ ++ DeviceEvent ev; ++ xXIDeviceEvent *xi2, *xi2_flags; ++ int rc; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ ev.header = 0xFF; ++ ev.length = sizeof(DeviceEvent); ++ ev.type = ET_TouchBegin; ++ ++ rc = EventToXI2((InternalEvent*)&ev, (xEvent**)&xi2); ++ g_assert(rc == Success); ++ g_assert(xi2->type == GenericEvent); ++ g_assert(xi2->evtype == XI_TouchBegin); ++ g_assert(xi2->flags == 0); ++ ++ rc = EventToXI2((InternalEvent*)&ev, (xEvent**)&xi2_flags); ++ g_assert(rc == Success); ++ g_assert(xi2_flags->type == GenericEvent); ++ g_assert(xi2_flags->evtype == XI_TouchBegin); ++ xi2_flags->flags = 0; ++ g_assert(memcmp(xi2, xi2_flags, sizeof(*xi2)) == 0); ++} ++ + static void xi2_struct_sizes(void) + { + #define compare(req) \ +@@ -812,6 +843,38 @@ + g_assert(rc == TRUE); + rc = GrabMatchesSecond(&b, &a, FALSE); + g_assert(rc == TRUE); ++ ++ /* All touch grabs must match a TouchBegin grab. */ ++ a.grabtype = GRABTYPE_XI2; ++ b.grabtype = GRABTYPE_XI2; ++ a.type = XI_TouchBegin; ++ b.type = XI_TouchUpdate; ++ a.detail.exact = 0; ++ b.detail.exact = 0; ++ a.modifiersDetail.exact = 0; ++ b.modifiersDetail.exact = 0; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); ++ ++ b.type = XI_TouchUpdateUnowned; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); ++ ++ b.type = XI_TouchOwnership; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); ++ ++ b.type = XI_TouchEnd; ++ rc = GrabMatchesSecond(&a, &b, FALSE); ++ g_assert(rc == TRUE); ++ rc = GrabMatchesSecond(&b, &a, FALSE); ++ g_assert(rc == TRUE); + } + + static void test_bits_to_byte(int i) +@@ -1224,6 +1287,101 @@ + free(v); + } + ++static void touch_create(void) ++{ ++ DeviceIntRec dev; ++ TouchClassRec touch; ++ TouchPointInfoRec touches[2]; ++ TouchPointInfoPtr ti; ++ ++ memset(&dev, 0, sizeof(dev)); ++ memset(&touch, 0, sizeof(touch)); ++ memset(touches, 0, sizeof(*touches) * 2); ++ touch.touches = touches; ++ touch.num_touches = 2; ++ touch.num_axes = 2; ++ touch.next_client_id = 1; ++ dev.touch = &touch; ++ ++ /* Make sure we get a valid touchpoint back. */ ++ ti = BeginTouchPoint(&dev, 0xdeadbeef); ++ g_assert(ti); ++ g_assert(ti->active == TRUE); ++ g_assert(ti->ddx_id == 0xdeadbeef); ++ g_assert(ti->client_id != 0); ++ g_assert(ti->pending_finish == 0); ++ g_assert(ti->sprite.spriteTraceGood == 0); ++} ++ ++static void touch_find_point(void) ++{ ++ DeviceIntRec dev; ++ TouchClassRec touch; ++ TouchPointInfoRec touches[2]; ++ TouchPointInfoPtr create_ret, find_ret; ++ ++ memset(&dev, 0, sizeof(dev)); ++ memset(&touch, 0, sizeof(touch)); ++ memset(touches, 0, sizeof(*touches) * 2); ++ touch.touches = touches; ++ touch.num_touches = 2; ++ touch.num_axes = 2; ++ touch.next_client_id = 1; ++ dev.touch = &touch; ++ ++ create_ret = BeginTouchPoint(&dev, 0xdeadbeef); ++ g_assert(create_ret); ++ ++ /* Make sure we can find the touch by both DDX and client ID. */ ++ find_ret = FindTouchPointByDDXID(&dev, 0xdeadbeef); ++ g_assert(create_ret == find_ret); ++ find_ret = FindTouchPointByClientID(&dev, create_ret->client_id); ++ g_assert(find_ret->active == TRUE); ++ g_assert(find_ret->ddx_id == 0xdeadbeef); ++ ++ /* Touches which are pending finish must be findable by their client ID, ++ * but not by their DDX ID, as only the DIX can inject ownership change ++ * events. */ ++ find_ret->ddx_pending_finish = 1; ++ find_ret = FindTouchPointByClientID(&dev, create_ret->client_id); ++ g_assert(find_ret == create_ret); ++ find_ret = FindTouchPointByDDXID(&dev, 0xdeadbeef); ++ g_assert(!find_ret); ++} ++ ++static void touch_finish(void) ++{ ++ DeviceIntRec dev; ++ TouchClassRec touch; ++ TouchPointInfoRec touches[2]; ++ TouchPointInfoPtr ti; ++ uint32_t client_id; ++ ++ memset(&dev, 0, sizeof(dev)); ++ memset(&touch, 0, sizeof(touch)); ++ memset(touches, 0, sizeof(*touches) * 2); ++ touch.touches = touches; ++ touch.num_touches = 2; ++ touch.num_axes = 2; ++ touch.next_client_id = 1; ++ dev.touch = &touch; ++ ++ /* Make sure the touch is in a sane state once we kill it, and that we ++ * can't find it once it's gone. */ ++ ti = BeginTouchPoint(&dev, 0xdeadbeef); ++ g_assert(ti); ++ client_id = ti->client_id; ++ EndTouchPoint(&dev, ti); ++ g_assert(ti->active == FALSE); ++ g_assert(ti->pending_finish == 0); ++ g_assert(ti->sprite.spriteTraceGood == 0); ++ g_assert(ti->client_id == 0); ++ g_assert(ti->ddx_id == 0); ++ ++ g_assert(FindTouchPointByDDXID(&dev, 0xdeadbeef) == NULL); ++ g_assert(FindTouchPointByClientID(&dev, client_id) == NULL); ++} ++ + int main(int argc, char** argv) + { + g_test_init(&argc, &argv,NULL); +@@ -1234,6 +1392,7 @@ + g_test_add_func("/dix/input/init-valuators", dix_init_valuators); + g_test_add_func("/dix/input/event-core-conversion", dix_event_to_core_conversion); + g_test_add_func("/dix/input/event-xi1-conversion", dix_event_to_xi1_conversion); ++ g_test_add_func("/dix/input/event-xi2-conversion", dix_event_to_xi2_conversion); + g_test_add_func("/dix/input/check-grab-values", dix_check_grab_values); + g_test_add_func("/dix/input/xi2-struct-sizes", xi2_struct_sizes); + g_test_add_func("/dix/input/grab_matching", dix_grab_matching); +@@ -1242,6 +1401,9 @@ + g_test_add_func("/include/bit_test_macros", include_bit_test_macros); + g_test_add_func("/Xi/xiproperty/register-unregister", xi_unregister_handlers); + g_test_add_func("/dix/input/valuator-alloc", dix_valuator_alloc); ++ g_test_add_func("/dix/input/touch-create", touch_create); ++ g_test_add_func("/dix/input/touch-find-point", touch_find_point); ++ g_test_add_func("/dix/input/touch-finish", touch_finish); + + return g_test_run(); + } +Index: xorg-server/test/xi2/protocol-eventconvert.c +=================================================================== +--- xorg-server.orig/test/xi2/protocol-eventconvert.c 2011-08-24 12:52:43.735647117 +0300 ++++ xorg-server/test/xi2/protocol-eventconvert.c 2011-08-24 12:56:49.865650624 +0300 +@@ -149,6 +149,59 @@ + free(swapped); + } + ++static void test_values_XITouchOwnershipEvent(TouchOwnershipEvent *in, ++ xXITouchOwnershipEvent *out, ++ BOOL swap) ++{ ++ char n; ++ ++ if (swap) ++ { ++ swaps(&out->sequenceNumber, n); ++ swapl(&out->length, n); ++ swaps(&out->evtype, n); ++ swaps(&out->deviceid, n); ++ swapl(&out->time, n); ++ swaps(&out->sourceid, n); ++ swapl(&out->touchid, n); ++ swapl(&out->flags, n); ++ } ++ ++ g_assert(out->type == GenericEvent); ++ g_assert(out->extension == 0); ++ g_assert(out->length == bytes_to_int32(sizeof(*out) - sizeof(xEvent))); ++ g_assert(out->evtype == XI_TouchOwnership); ++ g_assert(out->deviceid == in->deviceid); ++ g_assert(out->time == in->time); ++ g_assert(out->sourceid == in->sourceid); ++ g_assert(out->touchid == in->touchid); ++ g_assert(out->flags == in->flags); ++} ++ ++static void test_convert_XITouchOwnershipEvent(void) ++{ ++ TouchOwnershipEvent in; ++ xXITouchOwnershipEvent *out, swapped; ++ int rc; ++ ++ in.header = ET_Internal; ++ in.type = ET_TouchOwnership; ++ in.touchid = 0xdeadbeef; ++ in.time = 234; ++ in.deviceid = 12; ++ in.sourceid = 14; ++ in.resource = 0xcafebabe; ++ in.flags = 0; ++ rc = EventToXI2((InternalEvent *) &in, (xEvent **) &out); ++ g_assert(rc == Success); ++ ++ test_values_XITouchOwnershipEvent(&in, out, FALSE); ++ XI2EventSwap((xGenericEvent*)out, (xGenericEvent*)&swapped); ++ test_values_XITouchOwnershipEvent(&in, &swapped, TRUE); ++ ++ free(out); ++} ++ + static void test_convert_XIFocusEvent(void) + { + xEvent *out; +@@ -272,7 +325,7 @@ + int buttons, valuators; + int i; + unsigned char *ptr; +- uint32_t flagmask = 0; ++ uint32_t flagmask; + FP3232 *values; + + if (swap) { +@@ -311,9 +364,16 @@ + g_assert(out->sourceid == in->sourceid); + + switch (in->type) { ++ case ET_ButtonPress: ++ case ET_ButtonRelease: ++ case ET_Motion: ++ flagmask = XIPointerEmulated; ++ break; + case ET_KeyPress: + flagmask = XIKeyRepeat; + break; ++ case ET_TouchMotion: ++ case ET_TouchMotionUnowned: + default: + flagmask = 0; + break; +@@ -636,6 +696,49 @@ + } + } + ++static void test_convert_XITouch(void) ++{ ++ DeviceEvent in; ++ ++ memset(&in, 0, sizeof(in)); ++ ++ g_test_message("Testing TouchBegin"); ++ in.header = ET_Internal; ++ in.type = ET_TouchBegin; ++ in.length = sizeof(DeviceEvent); ++ in.time = 0; ++ in.deviceid = 1; ++ in.sourceid = 2; ++ in.root = 3; ++ in.root_x = 4; ++ in.root_x_frac = 5; ++ in.root_y = 6; ++ in.root_y_frac = 7; ++ in.detail.button = 8; ++ in.mods.base = 9; ++ in.mods.latched = 10; ++ in.mods.locked = 11; ++ in.mods.effective = 11; ++ in.group.base = 12; ++ in.group.latched = 13; ++ in.group.locked = 14; ++ in.group.effective = 15; ++ test_XIDeviceEvent(&in); ++ ++ in.flags = 0; ++ g_test_message("Testing TouchMotion"); ++ in.type = ET_TouchMotion; ++ test_XIDeviceEvent(&in); ++ ++ g_test_message("Testing TouchMotionUnowned"); ++ in.type = ET_TouchMotionUnowned; ++ test_XIDeviceEvent(&in); ++ ++ g_test_message("Testing TouchEnd"); ++ in.type = ET_TouchEnd; ++ test_XIDeviceEvent(&in); ++} ++ + static void test_values_XIDeviceChangedEvent(DeviceChangedEvent *in, + xXIDeviceChangedEvent *out, + BOOL swap) +@@ -912,6 +1015,8 @@ + g_test_add_func("/xi2/eventconvert/XIFocusEvent", test_convert_XIFocusEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceEvent", test_convert_XIDeviceEvent); + g_test_add_func("/xi2/eventconvert/XIDeviceChangedEvent", test_convert_XIDeviceChangedEvent); ++ g_test_add_func("/xi2/eventconvert/XITouch", test_convert_XITouch); ++ g_test_add_func("/xi2/eventconvert/XITouchOwnership", test_convert_XITouchOwnershipEvent); + + return g_test_run(); + } +Index: xorg-server/test/xi2/protocol-xiselectevents.c +=================================================================== +--- xorg-server.orig/test/xi2/protocol-xiselectevents.c 2011-08-24 12:52:43.745647118 +0300 ++++ xorg-server/test/xi2/protocol-xiselectevents.c 2011-08-24 12:56:49.865650624 +0300 +@@ -159,9 +159,33 @@ + memset(bits, 0, mask->mask_len * 4); + for (j = 0; j <= XI2LASTEVENT; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, Success); + ClearBit(bits, j); ++ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ ClearBit(bits, XI_TouchBegin); ++ ClearBit(bits, XI_TouchUpdate); ++ ClearBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ ClearBit(bits, XI_TouchOwnership); ++ } + } + + /* Test 2: +@@ -175,7 +199,23 @@ + + for (j = 0; j <= XI2LASTEVENT; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, Success); + } + +@@ -189,7 +229,23 @@ + + for (j = XI2LASTEVENT + 1; j < mask->mask_len * 4; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, BadValue); + ClearBit(bits, j); + } +@@ -202,7 +258,23 @@ + memset(bits, 0, mask->mask_len * 4); + for (j = 0; j <= XI2LASTEVENT; j++) + { ++ /* Can't select for these events alone */ ++ if (j == XI_TouchBegin || j == XI_TouchOwnership || ++ j == XI_TouchEnd) ++ continue; ++ + SetBit(bits, j); ++ ++ /* Must select for TouchBegin + TouchMotion + TouchEnd together, ++ * and optionally also TouchMotionUnowned and TouchOwnerhip. */ ++ if (j == XI_TouchUpdate || j == XI_TouchUpdateUnowned) { ++ SetBit(bits, XI_TouchBegin); ++ SetBit(bits, XI_TouchUpdate); ++ SetBit(bits, XI_TouchEnd); ++ if (j == XI_TouchUpdateUnowned) ++ SetBit(bits, XI_TouchOwnership); ++ } ++ + request_XISelectEvent(req, Success); + } + |