diff options
-rw-r--r-- | Xi/Makefile.am | 2 | ||||
-rw-r--r-- | Xi/exevents.c | 47 | ||||
-rw-r--r-- | Xi/extinit.c | 41 | ||||
-rw-r--r-- | Xi/xibarriers.c | 916 | ||||
-rw-r--r-- | Xi/xibarriers.h | 48 | ||||
-rw-r--r-- | Xi/xichangehierarchy.c | 5 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | dix/eventconvert.c | 43 | ||||
-rw-r--r-- | dix/events.c | 24 | ||||
-rw-r--r-- | dix/getevents.c | 15 | ||||
-rw-r--r-- | include/events.h | 1 | ||||
-rw-r--r-- | include/eventstr.h | 24 | ||||
-rw-r--r-- | include/input.h | 6 | ||||
-rw-r--r-- | include/inputstr.h | 2 | ||||
-rw-r--r-- | mi/mieq.c | 4 | ||||
-rw-r--r-- | mi/mipointer.c | 54 | ||||
-rw-r--r-- | mi/mipointer.h | 3 | ||||
-rw-r--r-- | test/fixes.c | 26 | ||||
-rw-r--r-- | test/xi2/protocol-eventconvert.c | 216 | ||||
-rw-r--r-- | xfixes/cursor.c | 432 | ||||
-rw-r--r-- | xfixes/xfixes.h | 17 |
21 files changed, 1464 insertions, 464 deletions
diff --git a/Xi/Makefile.am b/Xi/Makefile.am index 69c7886b9..af85bd049 100644 --- a/Xi/Makefile.am +++ b/Xi/Makefile.am @@ -78,6 +78,8 @@ libXi_la_SOURCES = \ ungrdevk.h \ xiallowev.c \ xiallowev.h \ + xibarriers.c \ + xibarriers.h \ xichangecursor.c \ xichangecursor.h \ xichangehierarchy.c \ diff --git a/Xi/exevents.c b/Xi/exevents.c index 4c1aeb4da..58fe49363 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -1648,6 +1648,49 @@ ProcessTouchEvent(InternalEvent *ev, DeviceIntPtr dev) UpdateDeviceState(dev, &ev->device_event); } +static void +ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev) +{ + Mask filter; + WindowPtr pWin; + BarrierEvent *be = &e->barrier_event; + xEvent *ev; + int rc; + GrabPtr grab = dev->deviceGrab.grab; + + if (!IsMaster(dev)) + return; + + if (dixLookupWindow(&pWin, be->window, serverClient, DixReadAccess) != Success) + return; + + if (grab) + be->flags |= XIBarrierDeviceIsGrabbed; + + rc = EventToXI2(e, &ev); + if (rc != Success) { + ErrorF("[Xi] event conversion from %s failed with code %d\n", __func__, rc); + return; + } + + /* A client has a grab, deliver to this client if the grab_window is the + barrier window. + + Otherwise, deliver normally to the client. + */ + if (grab && + CLIENT_ID(be->barrierid) == CLIENT_ID(grab->resource) && + grab->window->drawable.id == be->window) { + DeliverGrabbedEvent(e, dev, FALSE); + } else { + filter = GetEventFilter(dev, ev); + + DeliverEventsToWindow(dev, pWin, ev, 1, + filter, NullGrab); + } + free(ev); +} + /** * Process DeviceEvents and DeviceChangedEvents. */ @@ -1797,6 +1840,10 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device) case ET_TouchEnd: ProcessTouchEvent(ev, device); break; + case ET_BarrierHit: + case ET_BarrierLeave: + ProcessBarrierEvent(ev, device); + break; default: ProcessDeviceEvent(ev, device); break; diff --git a/Xi/extinit.c b/Xi/extinit.c index 7e3075551..73b084cd9 100644 --- a/Xi/extinit.c +++ b/Xi/extinit.c @@ -122,6 +122,7 @@ SOFTWARE. #include "xiqueryversion.h" #include "xisetclientpointer.h" #include "xiwarppointer.h" +#include "xibarriers.h" /* Masks for XI events have to be aligned with core event (partially anyway). * If DeviceButtonMotionMask is != ButtonMotionMask, event delivery @@ -251,7 +252,8 @@ static int (*ProcIVector[]) (ClientPtr) = { ProcXIChangeProperty, /* 57 */ ProcXIDeleteProperty, /* 58 */ ProcXIGetProperty, /* 59 */ - ProcXIGetSelectedEvents /* 60 */ + ProcXIGetSelectedEvents, /* 60 */ + ProcXIBarrierReleasePointer /* 61 */ }; /* For swapped clients */ @@ -316,7 +318,8 @@ static int (*SProcIVector[]) (ClientPtr) = { SProcXIChangeProperty, /* 57 */ SProcXIDeleteProperty, /* 58 */ SProcXIGetProperty, /* 59 */ - SProcXIGetSelectedEvents /* 60 */ + SProcXIGetSelectedEvents, /* 60 */ + SProcXIBarrierReleasePointer /* 61 */ }; /***************************************************************** @@ -839,6 +842,32 @@ STouchOwnershipEvent(xXITouchOwnershipEvent * from, xXITouchOwnershipEvent * to) swapl(&to->child); } +static void +SBarrierEvent(xXIBarrierEvent * from, + xXIBarrierEvent * to) { + + *to = *from; + + swaps(&from->sequenceNumber); + swapl(&from->length); + swaps(&from->evtype); + swapl(&from->time); + swaps(&from->deviceid); + swaps(&from->sourceid); + swapl(&from->event); + swapl(&from->root); + swapl(&from->root_x); + swapl(&from->root_y); + + swapl(&from->dx.integral); + swapl(&from->dx.frac); + swapl(&from->dy.integral); + swapl(&from->dy.frac); + swapl(&from->dtime); + swapl(&from->barrier); + swapl(&from->eventid); +} + /** Event swapping function for XI2 events. */ void XI2EventSwap(xGenericEvent *from, xGenericEvent *to) @@ -885,6 +914,11 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to) case XI_RawTouchEnd: SRawEvent((xXIRawEvent *) from, (xXIRawEvent *) to); break; + case XI_BarrierHit: + case XI_BarrierLeave: + SBarrierEvent((xXIBarrierEvent *) from, + (xXIBarrierEvent *) to); + break; default: ErrorF("[Xi] Unknown event type to swap. This is a bug.\n"); break; @@ -1263,6 +1297,9 @@ XInputExtensionInit(void) if (!AddCallback(&ClientStateCallback, XIClientCallback, 0)) FatalError("Failed to add callback to XI.\n"); + if (!XIBarrierInit()) + FatalError("Could not initialize barriers.\n"); + extEntry = AddExtension(INAME, IEVENTS, IERRORS, ProcIDispatch, SProcIDispatch, IResetProc, StandardMinorOpcode); if (extEntry) { diff --git a/Xi/xibarriers.c b/Xi/xibarriers.c new file mode 100644 index 000000000..7b7b83f1c --- /dev/null +++ b/Xi/xibarriers.c @@ -0,0 +1,916 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * 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. + * + * Copyright © 2002 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "xibarriers.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixevents.h" +#include "servermd.h" +#include "mipointer.h" +#include "inputstr.h" +#include "windowstr.h" +#include "xace.h" +#include "list.h" +#include "exglobals.h" +#include "eventstr.h" +#include "mi.h" + +RESTYPE PointerBarrierType; + +static DevPrivateKeyRec BarrierScreenPrivateKeyRec; + +#define BarrierScreenPrivateKey (&BarrierScreenPrivateKeyRec) + +typedef struct PointerBarrierClient *PointerBarrierClientPtr; + +struct PointerBarrierDevice { + struct xorg_list entry; + int deviceid; + Time last_timestamp; + int barrier_event_id; + int release_event_id; + Bool hit; + Bool seen; +}; + +struct PointerBarrierClient { + XID id; + ScreenPtr screen; + Window window; + struct PointerBarrier barrier; + struct xorg_list entry; + /* num_devices/device_ids are devices the barrier applies to */ + int num_devices; + int *device_ids; /* num_devices */ + + /* per_device keeps track of devices actually blocked by barriers */ + struct xorg_list per_device; +}; + +typedef struct _BarrierScreen { + struct xorg_list barriers; +} BarrierScreenRec, *BarrierScreenPtr; + +#define GetBarrierScreen(s) ((BarrierScreenPtr)dixLookupPrivate(&(s)->devPrivates, BarrierScreenPrivateKey)) +#define GetBarrierScreenIfSet(s) GetBarrierScreen(s) +#define SetBarrierScreen(s,p) dixSetPrivate(&(s)->devPrivates, BarrierScreenPrivateKey, p) + +static struct PointerBarrierDevice *AllocBarrierDevice(void) +{ + struct PointerBarrierDevice *pbd = NULL; + + pbd = malloc(sizeof(struct PointerBarrierDevice)); + if (!pbd) + return NULL; + + pbd->deviceid = -1; /* must be set by caller */ + pbd->barrier_event_id = 1; + pbd->release_event_id = 0; + pbd->hit = FALSE; + pbd->seen = FALSE; + xorg_list_init(&pbd->entry); + + return pbd; +} + +static void FreePointerBarrierClient(struct PointerBarrierClient *c) +{ + struct PointerBarrierDevice *pbd = NULL, *tmp = NULL; + + xorg_list_for_each_entry_safe(pbd, tmp, &c->per_device, entry) { + free(pbd); + } + free(c); +} + +static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid) +{ + struct PointerBarrierDevice *pbd = NULL; + + xorg_list_for_each_entry(pbd, &c->per_device, entry) { + if (pbd->deviceid == deviceid) + break; + } + + BUG_WARN(!pbd); + return pbd; +} + +static BOOL +barrier_is_horizontal(const struct PointerBarrier *barrier) +{ + return barrier->y1 == barrier->y2; +} + +static BOOL +barrier_is_vertical(const struct PointerBarrier *barrier) +{ + return barrier->x1 == barrier->x2; +} + +/** + * @return The set of barrier movement directions the movement vector + * x1/y1 → x2/y2 represents. + */ +int +barrier_get_direction(int x1, int y1, int x2, int y2) +{ + int direction = 0; + + /* which way are we trying to go */ + if (x2 > x1) + direction |= BarrierPositiveX; + if (x2 < x1) + direction |= BarrierNegativeX; + if (y2 > y1) + direction |= BarrierPositiveY; + if (y2 < y1) + direction |= BarrierNegativeY; + + return direction; +} + +/** + * Test if the barrier may block movement in the direction defined by + * x1/y1 → x2/y2. This function only tests whether the directions could be + * blocked, it does not test if the barrier actually blocks the movement. + * + * @return TRUE if the barrier blocks the direction of movement or FALSE + * otherwise. + */ +BOOL +barrier_is_blocking_direction(const struct PointerBarrier * barrier, + int direction) +{ + /* Barriers define which way is ok, not which way is blocking */ + return (barrier->directions & direction) != direction; +} + +static BOOL +inside_segment(int v, int v1, int v2) +{ + if (v1 < 0 && v2 < 0) /* line */ + return TRUE; + else if (v1 < 0) /* ray */ + return v <= v2; + else if (v2 < 0) /* ray */ + return v >= v1; + else /* line segment */ + return v >= v1 && v <= v2; +} + +#define T(v, a, b) (((float)v) - (a)) / ((b) - (a)) +#define F(t, a, b) ((t) * ((a) - (b)) + (a)) + +/** + * Test if the movement vector x1/y1 → x2/y2 is intersecting with the + * barrier. A movement vector with the startpoint or endpoint adjacent to + * the barrier itself counts as intersecting. + * + * @param x1 X start coordinate of movement vector + * @param y1 Y start coordinate of movement vector + * @param x2 X end coordinate of movement vector + * @param y2 Y end coordinate of movement vector + * @param[out] distance The distance between the start point and the + * intersection with the barrier (if applicable). + * @return TRUE if the barrier intersects with the given vector + */ +BOOL +barrier_is_blocking(const struct PointerBarrier * barrier, + int x1, int y1, int x2, int y2, double *distance) +{ + if (barrier_is_vertical(barrier)) { + float t, y; + t = T(barrier->x1, x1, x2); + if (t < 0 || t > 1) + return FALSE; + + /* Edge case: moving away from barrier. */ + if (x2 > x1 && t == 0) + return FALSE; + + y = F(t, y1, y2); + if (!inside_segment(y, barrier->y1, barrier->y2)) + return FALSE; + + *distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2))); + return TRUE; + } + else { + float t, x; + t = T(barrier->y1, y1, y2); + if (t < 0 || t > 1) + return FALSE; + + /* Edge case: moving away from barrier. */ + if (y2 > y1 && t == 0) + return FALSE; + + x = F(t, x1, x2); + if (!inside_segment(x, barrier->x1, barrier->x2)) + return FALSE; + + *distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2))); + return TRUE; + } +} + +#define HIT_EDGE_EXTENTS 2 +static BOOL +barrier_inside_hit_box(struct PointerBarrier *barrier, int x, int y) +{ + int x1, x2, y1, y2; + int dir; + + x1 = barrier->x1; + x2 = barrier->x2; + y1 = barrier->y1; + y2 = barrier->y2; + dir = ~(barrier->directions); + + if (barrier_is_vertical(barrier)) { + if (dir & BarrierPositiveX) + x1 -= HIT_EDGE_EXTENTS; + if (dir & BarrierNegativeX) + x2 += HIT_EDGE_EXTENTS; + } + if (barrier_is_horizontal(barrier)) { + if (dir & BarrierPositiveY) + y1 -= HIT_EDGE_EXTENTS; + if (dir & BarrierNegativeY) + y2 += HIT_EDGE_EXTENTS; + } + + return x >= x1 && x <= x2 && y >= y1 && y <= y2; +} + +static BOOL +barrier_blocks_device(struct PointerBarrierClient *client, + DeviceIntPtr dev) +{ + int i; + int master_id; + + /* Clients with no devices are treated as + * if they specified XIAllDevices. */ + if (client->num_devices == 0) + return TRUE; + + master_id = GetMaster(dev, POINTER_OR_FLOAT)->id; + + for (i = 0; i < client->num_devices; i++) { + int device_id = client->device_ids[i]; + if (device_id == XIAllDevices || + device_id == XIAllMasterDevices || + device_id == master_id) + return TRUE; + } + + return FALSE; +} + +/** + * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2. + * + * @param dir Only barriers blocking movement in direction dir are checked + * @param x1 X start coordinate of movement vector + * @param y1 Y start coordinate of movement vector + * @param x2 X end coordinate of movement vector + * @param y2 Y end coordinate of movement vector + * @return The barrier nearest to the movement origin that blocks this movement. + */ +static struct PointerBarrierClient * +barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev, + int dir, + int x1, int y1, int x2, int y2) +{ + struct PointerBarrierClient *c, *nearest = NULL; + double min_distance = INT_MAX; /* can't get higher than that in X anyway */ + + xorg_list_for_each_entry(c, &cs->barriers, entry) { + struct PointerBarrier *b = &c->barrier; + struct PointerBarrierDevice *pbd; + double distance; + + pbd = GetBarrierDevice(c, dev->id); + if (pbd->seen) + continue; + + if (!barrier_is_blocking_direction(b, dir)) + continue; + + if (!barrier_blocks_device(c, dev)) + continue; + + if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) { + if (min_distance > distance) { + min_distance = distance; + nearest = c; + } + } + } + + return nearest; +} + +/** + * Clamp to the given barrier given the movement direction specified in dir. + * + * @param barrier The barrier to clamp to + * @param dir The movement direction + * @param[out] x The clamped x coordinate. + * @param[out] y The clamped x coordinate. + */ +void +barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, + int *y) +{ + if (barrier_is_vertical(barrier)) { + if ((dir & BarrierNegativeX) & ~barrier->directions) + *x = barrier->x1; + if ((dir & BarrierPositiveX) & ~barrier->directions) + *x = barrier->x1 - 1; + } + if (barrier_is_horizontal(barrier)) { + if ((dir & BarrierNegativeY) & ~barrier->directions) + *y = barrier->y1; + if ((dir & BarrierPositiveY) & ~barrier->directions) + *y = barrier->y1 - 1; + } +} + +void +input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, + int current_x, int current_y, + int dest_x, int dest_y, + int *out_x, int *out_y, + int *nevents, InternalEvent* events) +{ + /* Clamped coordinates here refer to screen edge clamping. */ + BarrierScreenPtr cs = GetBarrierScreen(screen); + int x = dest_x, + y = dest_y; + int dir; + struct PointerBarrier *nearest = NULL; + PointerBarrierClientPtr c; + Time ms = GetTimeInMillis(); + BarrierEvent ev = { + .header = ET_Internal, + .type = 0, + .length = sizeof (BarrierEvent), + .time = ms, + .deviceid = dev->id, + .sourceid = dev->id, + .dx = dest_x - current_x, + .dy = dest_y - current_y, + .root = screen->root->drawable.id, + }; + InternalEvent *barrier_events = events; + DeviceIntPtr master; + + if (nevents) + *nevents = 0; + + if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev)) + goto out; + + /** + * This function is only called for slave devices, but pointer-barriers + * are for master-devices only. Flip the device to the master here, + * continue with that. + */ + master = GetMaster(dev, MASTER_POINTER); + + /* How this works: + * Given the origin and the movement vector, get the nearest barrier + * to the origin that is blocking the movement. + * Clamp to that barrier. + * Then, check from the clamped intersection to the original + * destination, again finding the nearest barrier and clamping. + */ + dir = barrier_get_direction(current_x, current_y, x, y); + + while (dir != 0) { + struct PointerBarrierDevice *pbd; + + c = barrier_find_nearest(cs, master, dir, current_x, current_y, x, y); + if (!c) + break; + + nearest = &c->barrier; + + pbd = GetBarrierDevice(c, master->id); + pbd->seen = TRUE; + pbd->hit = TRUE; + + if (pbd->barrier_event_id == pbd->release_event_id) + continue; + + ev.type = ET_BarrierHit; + barrier_clamp_to_barrier(nearest, dir, &x, &y); + + if (barrier_is_vertical(nearest)) { + dir &= ~(BarrierNegativeX | BarrierPositiveX); + current_x = x; + } + else if (barrier_is_horizontal(nearest)) { + dir &= ~(BarrierNegativeY | BarrierPositiveY); + current_y = y; + } + + ev.flags = 0; + ev.event_id = pbd->barrier_event_id; + ev.barrierid = c->id; + + ev.dt = ms - pbd->last_timestamp; + ev.window = c->window; + pbd->last_timestamp = ms; + + /* root x/y is filled in later */ + + barrier_events->barrier_event = ev; + barrier_events++; + *nevents += 1; + } + + xorg_list_for_each_entry(c, &cs->barriers, entry) { + struct PointerBarrierDevice *pbd; + int flags = 0; + + pbd = GetBarrierDevice(c, master->id); + pbd->seen = FALSE; + if (!pbd->hit) + continue; + + if (barrier_inside_hit_box(&c->barrier, x, y)) + continue; + + pbd->hit = FALSE; + + ev.type = ET_BarrierLeave; + + if (pbd->barrier_event_id == pbd->release_event_id) + flags |= XIBarrierPointerReleased; + + ev.flags = flags; + ev.event_id = pbd->barrier_event_id; + ev.barrierid = c->id; + + ev.dt = ms - pbd->last_timestamp; + ev.window = c->window; + pbd->last_timestamp = ms; + + /* root x/y is filled in later */ + + barrier_events->barrier_event = ev; + barrier_events++; + *nevents += 1; + + /* If we've left the hit box, this is the + * start of a new event ID. */ + pbd->barrier_event_id++; + } + + out: + *out_x = x; + *out_y = y; +} + +static void +sort_min_max(INT16 *a, INT16 *b) +{ + INT16 A, B; + if (*a < 0 || *b < 0) + return; + A = *a; + B = *b; + *a = min(A, B); + *b = max(A, B); +} + +static int +CreatePointerBarrierClient(ClientPtr client, + xXFixesCreatePointerBarrierReq * stuff, + PointerBarrierClientPtr *client_out) +{ + WindowPtr pWin; + ScreenPtr screen; + BarrierScreenPtr cs; + int err; + int size; + int i; + struct PointerBarrierClient *ret; + CARD16 *in_devices; + DeviceIntPtr dev; + + size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices; + ret = malloc(size); + + if (!ret) { + return BadAlloc; + } + + xorg_list_init(&ret->per_device); + + err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); + if (err != Success) { + client->errorValue = stuff->window; + goto error; + } + + screen = pWin->drawable.pScreen; + cs = GetBarrierScreen(screen); + + ret->screen = screen; + ret->window = stuff->window; + ret->num_devices = stuff->num_devices; + if (ret->num_devices > 0) + ret->device_ids = (int*)&ret[1]; + else + ret->device_ids = NULL; + + in_devices = (CARD16 *) &stuff[1]; + for (i = 0; i < stuff->num_devices; i++) { + int device_id = in_devices[i]; + DeviceIntPtr device; + + if ((err = dixLookupDevice (&device, device_id, + client, DixReadAccess))) { + client->errorValue = device_id; + goto error; + } + + if (!IsMaster (device)) { + client->errorValue = device_id; + err = BadDevice; + goto error; + } + + ret->device_ids[i] = device_id; + } + + /* Alloc one per master pointer, they're the ones that can be blocked */ + xorg_list_init(&ret->per_device); + nt_list_for_each_entry(dev, inputInfo.devices, next) { + struct PointerBarrierDevice *pbd; + + if (dev->type != MASTER_POINTER) + continue; + + pbd = AllocBarrierDevice(); + if (!pbd) { + err = BadAlloc; + goto error; + } + pbd->deviceid = dev->id; + + xorg_list_add(&pbd->entry, &ret->per_device); + } + + ret->id = stuff->barrier; + ret->barrier.x1 = stuff->x1; + ret->barrier.x2 = stuff->x2; + ret->barrier.y1 = stuff->y1; + ret->barrier.y2 = stuff->y2; + sort_min_max(&ret->barrier.x1, &ret->barrier.x2); + sort_min_max(&ret->barrier.y1, &ret->barrier.y2); + ret->barrier.directions = stuff->directions & 0x0f; + if (barrier_is_horizontal(&ret->barrier)) + ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX); + if (barrier_is_vertical(&ret->barrier)) + ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY); + xorg_list_add(&ret->entry, &cs->barriers); + + *client_out = ret; + return Success; + + error: + *client_out = NULL; + FreePointerBarrierClient(ret); + return err; +} + +static int +BarrierFreeBarrier(void *data, XID id) +{ + struct PointerBarrierClient *c; + Time ms = GetTimeInMillis(); + DeviceIntPtr dev = NULL; + ScreenPtr screen; + + c = container_of(data, struct PointerBarrierClient, barrier); + screen = c->screen; + + for (dev = inputInfo.devices; dev; dev = dev->next) { + struct PointerBarrierDevice *pbd; + int root_x, root_y; + BarrierEvent ev = { + .header = ET_Internal, + .type = ET_BarrierLeave, + .length = sizeof (BarrierEvent), + .time = ms, + /* .deviceid */ + .sourceid = 0, + .barrierid = c->id, + .window = c->window, + .root = screen->root->drawable.id, + .dx = 0, + .dy = 0, + /* .root_x */ + /* .root_y */ + /* .dt */ + /* .event_id */ + .flags = XIBarrierPointerReleased, + }; + + + if (dev->type != MASTER_POINTER) + continue; + + pbd = GetBarrierDevice(c, dev->id); + if (!pbd->hit) + continue; + + ev.deviceid = dev->id; + ev.event_id = pbd->barrier_event_id, + ev.dt = ms - pbd->last_timestamp, + + GetSpritePosition(dev, &root_x, &root_y); + ev.root_x = root_x; + ev.root_y = root_y; + + mieqEnqueue(dev, (InternalEvent *) &ev); + } + + xorg_list_del(&c->entry); + + FreePointerBarrierClient(c); + return Success; +} + +static void add_master_func(pointer res, XID id, pointer devid) +{ + struct PointerBarrier *b; + struct PointerBarrierClient *barrier; + struct PointerBarrierDevice *pbd; + int *deviceid = devid; + + b = res; + barrier = container_of(b, struct PointerBarrierClient, barrier); + + + pbd = AllocBarrierDevice(); + pbd->deviceid = *deviceid; + + xorg_list_add(&pbd->entry, &barrier->per_device); +} + +static void remove_master_func(pointer res, XID id, pointer devid) +{ + struct PointerBarrierDevice *pbd; + struct PointerBarrierClient *barrier; + struct PointerBarrier *b; + DeviceIntPtr dev; + int *deviceid = devid; + int rc; + Time ms = GetTimeInMillis(); + + rc = dixLookupDevice(&dev, *deviceid, serverClient, DixSendAccess); + if (rc != Success) + return; + + b = res; + barrier = container_of(b, struct PointerBarrierClient, barrier); + + pbd = GetBarrierDevice(barrier, *deviceid); + + if (pbd->hit) { + BarrierEvent ev = { + .header = ET_Internal, + .type =ET_BarrierLeave, + .length = sizeof (BarrierEvent), + .time = ms, + .deviceid = *deviceid, + .sourceid = 0, + .dx = 0, + .dy = 0, + .root = barrier->screen->root->drawable.id, + .window = barrier->window, + .dt = ms - pbd->last_timestamp, + .flags = XIBarrierPointerReleased, + .event_id = pbd->barrier_event_id, + .barrierid = barrier->id, + }; + + mieqEnqueue(dev, (InternalEvent *) &ev); + } + + xorg_list_del(&pbd->entry); + free(pbd); +} + +void XIBarrierNewMasterDevice(ClientPtr client, int deviceid) +{ + FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid); +} + +void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid) +{ + FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid); +} + +int +XICreatePointerBarrier(ClientPtr client, + xXFixesCreatePointerBarrierReq * stuff) +{ + int err; + struct PointerBarrierClient *barrier; + struct PointerBarrier b; + + b.x1 = stuff->x1; + b.x2 = stuff->x2; + b.y1 = stuff->y1; + b.y2 = stuff->y2; + + if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b)) + return BadValue; + + /* no 0-sized barriers */ + if (barrier_is_horizontal(&b) && barrier_is_vertical(&b)) + return BadValue; + + /* no infinite barriers on the wrong axis */ + if (barrier_is_horizontal(&b) && (b.y1 < 0 || b.y2 < 0)) + return BadValue; + + if (barrier_is_vertical(&b) && (b.x1 < 0 || b.x2 < 0)) + return BadValue; + + if ((err = CreatePointerBarrierClient(client, stuff, &barrier))) + return err; + + if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier)) + return BadAlloc; + + return Success; +} + +int +XIDestroyPointerBarrier(ClientPtr client, + xXFixesDestroyPointerBarrierReq * stuff) +{ + int err; + void *barrier; + + err = dixLookupResourceByType((void **) &barrier, stuff->barrier, + PointerBarrierType, client, DixDestroyAccess); + if (err != Success) { + client->errorValue = stuff->barrier; + return err; + } + + if (CLIENT_ID(stuff->barrier) != client->index) + return BadAccess; + + FreeResource(stuff->barrier, RT_NONE); + return Success; +} + +int +SProcXIBarrierReleasePointer(ClientPtr client) +{ + xXIBarrierReleasePointerInfo *info; + REQUEST(xXIBarrierReleasePointerReq); + int i; + + info = (xXIBarrierReleasePointerInfo*) &stuff[1]; + + swaps(&stuff->length); + swapl(&stuff->num_barriers); + for (i = 0; i < stuff->num_barriers; i++, info++) { + swaps(&info->deviceid); + swapl(&info->barrier); + swapl(&info->eventid); + } + + return (ProcXIBarrierReleasePointer(client)); +} + +int +ProcXIBarrierReleasePointer(ClientPtr client) +{ + int i; + int err; + struct PointerBarrierClient *barrier; + struct PointerBarrier *b; + xXIBarrierReleasePointerInfo *info; + + REQUEST(xXIBarrierReleasePointerReq); + REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq); + + info = (xXIBarrierReleasePointerInfo*) &stuff[1]; + for (i = 0; i < stuff->num_barriers; i++, info++) { + struct PointerBarrierDevice *pbd; + DeviceIntPtr dev; + CARD32 barrier_id, event_id; + _X_UNUSED CARD32 device_id; + + barrier_id = info->barrier; + event_id = info->eventid; + + err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess); + if (err != Success) { + client->errorValue = BadDevice; + return err; + } + + err = dixLookupResourceByType((void **) &b, barrier_id, + PointerBarrierType, client, DixReadAccess); + if (err != Success) { + client->errorValue = barrier_id; + return err; + } + + if (CLIENT_ID(barrier_id) != client->index) + return BadAccess; + + + barrier = container_of(b, struct PointerBarrierClient, barrier); + + pbd = GetBarrierDevice(barrier, dev->id); + + if (pbd->barrier_event_id == event_id) + pbd->release_event_id = event_id; + } + + return Success; +} + +Bool +XIBarrierInit(void) +{ + int i; + + if (!dixRegisterPrivateKey(&BarrierScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + BarrierScreenPtr cs; + + cs = (BarrierScreenPtr) calloc(1, sizeof(BarrierScreenRec)); + if (!cs) + return FALSE; + xorg_list_init(&cs->barriers); + SetBarrierScreen(pScreen, cs); + } + + PointerBarrierType = CreateNewResourceType(BarrierFreeBarrier, + "XIPointerBarrier"); + + return PointerBarrierType; +} diff --git a/Xi/xibarriers.h b/Xi/xibarriers.h new file mode 100644 index 000000000..11e84ec9f --- /dev/null +++ b/Xi/xibarriers.h @@ -0,0 +1,48 @@ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#ifndef _XIBARRIERS_H_ +#define _XIBARRIERS_H_ + +#include "resource.h" + +extern _X_EXPORT RESTYPE PointerBarrierType; + +struct PointerBarrier { + INT16 x1, x2, y1, y2; + CARD32 directions; +}; + +int +barrier_get_direction(int, int, int, int); +BOOL +barrier_is_blocking(const struct PointerBarrier *, int, int, int, int, + double *); +BOOL +barrier_is_blocking_direction(const struct PointerBarrier *, int); +void +barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, + int *y); + +#include <xfixesint.h> + +int +XICreatePointerBarrier(ClientPtr client, + xXFixesCreatePointerBarrierReq * stuff); + +int +XIDestroyPointerBarrier(ClientPtr client, + xXFixesDestroyPointerBarrierReq * stuff); + +Bool +XIBarrierInit(void); + +int SProcXIBarrierReleasePointer(ClientPtr client); +int ProcXIBarrierReleasePointer(ClientPtr client); + +void XIBarrierNewMasterDevice(ClientPtr client, int deviceid); +void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid); + +#endif /* _XIBARRIERS_H_ */ diff --git a/Xi/xichangehierarchy.c b/Xi/xichangehierarchy.c index 4dc3d76e9..0184eb29a 100644 --- a/Xi/xichangehierarchy.c +++ b/Xi/xichangehierarchy.c @@ -52,6 +52,7 @@ #include "xkbsrv.h" #include "xichangehierarchy.h" +#include "xibarriers.h" /** * Send the current state of the device hierarchy to all clients. @@ -189,6 +190,8 @@ add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES]) flags[XTestptr->id] |= XISlaveAttached; flags[XTestkeybd->id] |= XISlaveAttached; + XIBarrierNewMasterDevice(client, ptr->id); + unwind: free(name); return rc; @@ -293,6 +296,8 @@ remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES]) } } + XIBarrierRemoveMasterDevice(client, ptr->id); + /* disable the remove the devices, XTest devices must be done first else the sprites they rely on will be destroyed */ DisableDevice(XTestptr, FALSE); diff --git a/configure.ac b/configure.ac index 38ac240df..ee0fa7818 100644 --- a/configure.ac +++ b/configure.ac @@ -788,7 +788,7 @@ XPROTO="xproto >= 7.0.22" RANDRPROTO="randrproto >= 1.4.0" RENDERPROTO="renderproto >= 0.11" XEXTPROTO="xextproto >= 7.1.99" -INPUTPROTO="inputproto >= 2.1.99.6" +INPUTPROTO="inputproto >= 2.2.99.1" KBPROTO="kbproto >= 1.0.3" FONTSPROTO="fontsproto" FIXESPROTO="fixesproto >= 5.0" diff --git a/dix/eventconvert.c b/dix/eventconvert.c index 2e422d7a1..47dcf8b41 100644 --- a/dix/eventconvert.c +++ b/dix/eventconvert.c @@ -57,6 +57,7 @@ static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count); static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce); static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi); static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi); +static int eventToBarrierEvent(BarrierEvent *ev, xEvent **xi); static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi); /* Do not use, read comments below */ @@ -160,6 +161,8 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out) case ET_TouchUpdate: case ET_TouchEnd: case ET_TouchOwnership: + case ET_BarrierHit: + case ET_BarrierLeave: ret = BadMatch; break; default: @@ -216,6 +219,8 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count) case ET_TouchUpdate: case ET_TouchEnd: case ET_TouchOwnership: + case ET_BarrierHit: + case ET_BarrierLeave: *count = 0; *xi = NULL; return BadMatch; @@ -277,6 +282,9 @@ EventToXI2(InternalEvent *ev, xEvent **xi) case ET_RawTouchUpdate: case ET_RawTouchEnd: return eventToRawEvent(&ev->raw_event, xi); + case ET_BarrierHit: + case ET_BarrierLeave: + return eventToBarrierEvent(&ev->barrier_event, xi); default: break; } @@ -782,6 +790,35 @@ eventToRawEvent(RawDeviceEvent *ev, xEvent **xi) return Success; } +static int +eventToBarrierEvent(BarrierEvent *ev, xEvent **xi) +{ + xXIBarrierEvent *barrier; + int len = sizeof(xXIBarrierEvent); + + *xi = calloc(1, len); + barrier = (xXIBarrierEvent*) *xi; + barrier->type = GenericEvent; + barrier->extension = IReqCode; + barrier->evtype = GetXI2Type(ev->type); + barrier->length = bytes_to_int32(len - sizeof(xEvent)); + barrier->deviceid = ev->deviceid; + barrier->sourceid = ev->sourceid; + barrier->time = ev->time; + barrier->event = ev->window; + barrier->root = ev->root; + barrier->dx = double_to_fp3232(ev->dx); + barrier->dy = double_to_fp3232(ev->dy); + barrier->dtime = ev->dt; + barrier->flags = ev->flags; + barrier->eventid = ev->event_id; + barrier->barrier = ev->barrierid; + barrier->root_x = double_to_fp1616(ev->root_x); + barrier->root_y = double_to_fp1616(ev->root_y); + + return Success; +} + /** * Return the corresponding core type for the given event or 0 if no core * equivalent exists. @@ -929,6 +966,12 @@ GetXI2Type(enum EventType type) case ET_TouchOwnership: xi2type = XI_TouchOwnership; break; + case ET_BarrierHit: + xi2type = XI_BarrierHit; + break; + case ET_BarrierLeave: + xi2type = XI_BarrierLeave; + break; default: break; } diff --git a/dix/events.c b/dix/events.c index 3836d2f17..73593626e 100644 --- a/dix/events.c +++ b/dix/events.c @@ -219,6 +219,9 @@ static void CheckVirtualMotion(DeviceIntPtr pDev, QdEventPtr qe, static void CheckPhysLimits(DeviceIntPtr pDev, CursorPtr cursor, Bool generateEvents, Bool confineToScreen, ScreenPtr pScreen); +static Bool IsWrongPointerBarrierClient(ClientPtr client, + DeviceIntPtr dev, + xEvent *event); /** Key repeat hack. Do not use but in TryClientEvents */ extern BOOL EventIsKeyRepeat(xEvent *event); @@ -2092,6 +2095,9 @@ DeliverEventToInputClients(DeviceIntPtr dev, InputClients * inputclients, if (IsInterferingGrab(client, dev, events)) continue; + if (IsWrongPointerBarrierClient(client, dev, events)) + continue; + mask = GetEventMask(dev, events, inputclients); if (XaceHook(XACE_RECEIVE_ACCESS, client, win, events, count)) @@ -2446,6 +2452,8 @@ FixUpEventFromWindow(SpritePtr pSprite, case XI_DeviceChanged: case XI_HierarchyChanged: case XI_PropertyEvent: + case XI_BarrierHit: + case XI_BarrierLeave: return; default: break; @@ -6080,3 +6088,19 @@ IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent *event) return FALSE; } + +/* PointerBarrier events are only delivered to the client that created that + * barrier */ +static Bool +IsWrongPointerBarrierClient(ClientPtr client, DeviceIntPtr dev, xEvent *event) +{ + xXIBarrierEvent *ev = (xXIBarrierEvent*)event; + + if (ev->type != GenericEvent || ev->extension != IReqCode) + return FALSE; + + if (ev->evtype != XI_BarrierHit && ev->evtype != XI_BarrierLeave) + return FALSE; + + return client->index != CLIENT_ID(ev->barrier); +} diff --git a/dix/getevents.c b/dix/getevents.c index fa538d9f4..3d41e1e5a 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -916,10 +916,13 @@ scale_to_desktop(DeviceIntPtr dev, ValuatorMask *mask, * @param[in,out] devy y desktop-wide coordinate in device coordinate system * @param[in,out] screenx x coordinate in desktop coordinate system * @param[in,out] screeny y coordinate in desktop coordinate system + * @param[out] nevents Number of barrier events added to events + * @param[in,out] events List of events barrier events are added to */ static ScreenPtr positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask, - double *devx, double *devy, double *screenx, double *screeny) + double *devx, double *devy, double *screenx, double *screeny, + int *nevents, InternalEvent* events) { ScreenPtr scr = miPointerGetScreen(dev); double tmpx, tmpy; @@ -933,7 +936,7 @@ positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask, /* miPointerSetPosition takes care of crossing screens for us, as well as * clipping to the current screen. Coordinates returned are in desktop * coord system */ - scr = miPointerSetPosition(dev, mode, screenx, screeny); + scr = miPointerSetPosition(dev, mode, screenx, screeny, nevents, events); /* If we were constrained, rescale x/y from the screen coordinates so * the device valuators reflect the correct position. For screen @@ -1319,6 +1322,7 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type, int sx, sy; /* for POINTER_SCREEN */ ValuatorMask mask; ScreenPtr scr; + int num_barrier_events = 0; switch (type) { case MotionNotify: @@ -1395,7 +1399,10 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type, } scr = positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative, - &mask, &devx, &devy, &screenx, &screeny); + &mask, &devx, &devy, &screenx, &screeny, + &num_barrier_events, events); + num_events += num_barrier_events; + events += num_barrier_events; /* screenx, screeny are in desktop coordinates, mask is in device coordinates per-screen (the event data) @@ -1945,7 +1952,7 @@ GetTouchEvents(InternalEvent *events, DeviceIntPtr dev, uint32_t ddx_touchid, scr = scale_to_desktop(dev, &mask, &devx, &devy, &screenx, &screeny); if (emulate_pointer) scr = positionSprite(dev, Absolute, &mask, - &devx, &devy, &screenx, &screeny); + &devx, &devy, &screenx, &screeny, NULL, NULL); /* see fill_pointer_events for coordinate systems */ if (emulate_pointer) diff --git a/include/events.h b/include/events.h index 222bf328b..c0ef45d5f 100644 --- a/include/events.h +++ b/include/events.h @@ -27,6 +27,7 @@ typedef struct _DeviceEvent DeviceEvent; typedef struct _DeviceChangedEvent DeviceChangedEvent; typedef struct _TouchOwnershipEvent TouchOwnershipEvent; +typedef struct _BarrierEvent BarrierEvent; #if XFreeXDGA typedef struct _DGAEvent DGAEvent; diff --git a/include/eventstr.h b/include/eventstr.h index dd6fbeffb..38fab4f3c 100644 --- a/include/eventstr.h +++ b/include/eventstr.h @@ -72,6 +72,8 @@ enum EventType { ET_RawTouchUpdate, ET_RawTouchEnd, ET_XQuartz, + ET_BarrierHit, + ET_BarrierLeave, ET_Internal = 0xFF /* First byte */ }; @@ -130,7 +132,7 @@ struct _DeviceEvent { */ struct _TouchOwnershipEvent { unsigned char header; /**< Always ET_Internal */ - enum EventType type; /**< One of EventType */ + enum EventType type; /**< ET_TouchOwnership */ int length; /**< Length in bytes */ Time time; /**< Time in ms */ int deviceid; /**< Device to post this event for */ @@ -227,6 +229,25 @@ struct _RawDeviceEvent { uint32_t flags; /**< Flags to be copied into the generated event */ }; +struct _BarrierEvent { + unsigned char header; /**< Always ET_Internal */ + enum EventType type; /**< ET_BarrierHit, ET_BarrierLeave */ + int length; /**< Length in bytes */ + Time time; /**< Time in ms */ + int deviceid; /**< Device to post this event for */ + int sourceid; /**< The physical source device */ + int barrierid; + Window window; + Window root; + double dx; + double dy; + double root_x; + double root_y; + int16_t dt; + int32_t event_id; + uint32_t flags; +}; + #ifdef XQUARTZ #define XQUARTZ_EVENT_MAXARGS 5 struct _XQuartzEvent { @@ -253,6 +274,7 @@ union _InternalEvent { DeviceEvent device_event; DeviceChangedEvent changed_event; TouchOwnershipEvent touch_ownership_event; + BarrierEvent barrier_event; #if XFreeXDGA DGAEvent dga_event; #endif diff --git a/include/input.h b/include/input.h index 2387dbf4a..23a20b59d 100644 --- a/include/input.h +++ b/include/input.h @@ -678,4 +678,10 @@ extern _X_EXPORT void input_option_set_value(InputOption *opt, extern _X_HIDDEN Bool point_on_screen(ScreenPtr pScreen, int x, int y); extern _X_HIDDEN void update_desktop_dimensions(void); +extern _X_HIDDEN void input_constrain_cursor(DeviceIntPtr pDev, ScreenPtr screen, + int current_x, int current_y, + int dest_x, int dest_y, + int *out_x, int *out_y, + int *nevents, InternalEvent* events); + #endif /* INPUT_H */ diff --git a/include/inputstr.h b/include/inputstr.h index bb0a77963..17cee9854 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -71,7 +71,7 @@ extern _X_EXPORT int CountBits(const uint8_t * mask, int len); * events to the protocol, the server will not support these events until * this number here is bumped. */ -#define XI2LASTEVENT XI_RawTouchEnd +#define XI2LASTEVENT XI_BarrierLeave #define XI2MASKSIZE ((XI2LASTEVENT >> 3) + 1) /* no of bytes for masks */ /** @@ -407,6 +407,10 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event) case ET_RawTouchUpdate: event->raw_event.deviceid = dev->id; break; + case ET_BarrierHit: + case ET_BarrierLeave: + event->barrier_event.deviceid = dev->id; + break; default: ErrorF("[mi] Unknown event type (%d), cannot change id.\n", event->any.type); diff --git a/mi/mipointer.c b/mi/mipointer.c index f34506326..b8503f450 100644 --- a/mi/mipointer.c +++ b/mi/mipointer.c @@ -98,7 +98,7 @@ static void miPointerDeviceCleanup(DeviceIntPtr pDev, ScreenPtr pScreen); static void miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y); -static InternalEvent *events; /* for WarpPointer MotionNotifies */ +static InternalEvent *mipointermove_events; /* for WarpPointer MotionNotifies */ Bool miPointerInitialize(ScreenPtr pScreen, @@ -143,7 +143,7 @@ miPointerInitialize(ScreenPtr pScreen, pScreen->DeviceCursorInitialize = miPointerDeviceInitialize; pScreen->DeviceCursorCleanup = miPointerDeviceCleanup; - events = NULL; + mipointermove_events = NULL; return TRUE; } @@ -160,8 +160,8 @@ miPointerCloseScreen(ScreenPtr pScreen) pScreen->CloseScreen = pScreenPriv->CloseScreen; free((pointer) pScreenPriv); - FreeEventList(events, GetMaximumEventsNum()); - events = NULL; + FreeEventList(mipointermove_events, GetMaximumEventsNum()); + mipointermove_events = NULL; return (*pScreen->CloseScreen) (pScreen); } @@ -565,13 +565,16 @@ miPointerMoveNoEvent(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) */ ScreenPtr miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx, - double *screeny) + double *screeny, + int *nevents, InternalEvent* events) { miPointerScreenPtr pScreenPriv; ScreenPtr pScreen; ScreenPtr newScreen; int x, y; Bool switch_screen = FALSE; + Bool should_constrain_barriers = FALSE; + int i; miPointerPtr pPointer; @@ -588,6 +591,25 @@ miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx, x -= pScreen->x; y -= pScreen->y; + should_constrain_barriers = (mode == Relative); + + if (should_constrain_barriers) { + /* coordinates after clamped to a barrier */ + int constrained_x, constrained_y; + int current_x, current_y; /* current position in per-screen coord */ + + current_x = MIPOINTER(pDev)->x - pScreen->y; + current_y = MIPOINTER(pDev)->y - pScreen->x; + + input_constrain_cursor(pDev, pScreen, + current_x, current_y, x, y, + &constrained_x, &constrained_y, + nevents, events); + + x = constrained_x; + y = constrained_y; + } + if (switch_screen) { pScreenPriv = GetScreenPrivate(pScreen); if (!pPointer->confined) { @@ -619,6 +641,18 @@ miPointerSetPosition(DeviceIntPtr pDev, int mode, double *screenx, if (pPointer->x != x || pPointer->y != y || pPointer->pScreen != pScreen) miPointerMoveNoEvent(pDev, pScreen, x, y); + /* check if we generated any barrier events and if so, update root x/y + * to the fully constrained coords */ + if (should_constrain_barriers) { + for (i = 0; i < *nevents; i++) { + if (events[i].any.type == ET_BarrierHit || + events[i].any.type == ET_BarrierLeave) { + events[i].barrier_event.root_x = x; + events[i].barrier_event.root_y = y; + } + } + } + /* Convert to desktop coordinates again */ x += pScreen->x; y += pScreen->y; @@ -676,17 +710,17 @@ miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) valuators[0] = x; valuators[1] = y; - if (!events) { - events = InitEventList(GetMaximumEventsNum()); + if (!mipointermove_events) { + mipointermove_events = InitEventList(GetMaximumEventsNum()); - if (!events) { + if (!mipointermove_events) { FatalError("Could not allocate event store.\n"); return; } } valuator_mask_set_range(&mask, 0, 2, valuators); - nevents = GetPointerEvents(events, pDev, MotionNotify, 0, + nevents = GetPointerEvents(mipointermove_events, pDev, MotionNotify, 0, POINTER_SCREEN | POINTER_ABSOLUTE | POINTER_NORAW, &mask); @@ -695,7 +729,7 @@ miPointerMove(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) darwinEvents_lock(); #endif for (i = 0; i < nevents; i++) - mieqEnqueue(pDev, &events[i]); + mieqEnqueue(pDev, &mipointermove_events[i]); #ifdef XQUARTZ darwinEvents_unlock(); #endif diff --git a/mi/mipointer.h b/mi/mipointer.h index 1500e216a..f89dff31e 100644 --- a/mi/mipointer.h +++ b/mi/mipointer.h @@ -115,7 +115,8 @@ miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y); /* Moves the cursor to the specified position. May clip the co-ordinates: * x and y are modified in-place. */ extern _X_EXPORT ScreenPtr -miPointerSetPosition(DeviceIntPtr pDev, int mode, double *x, double *y); +miPointerSetPosition(DeviceIntPtr pDev, int mode, double *x, double *y, + int *nevents, InternalEvent *events); extern _X_EXPORT void miPointerUpdateSprite(DeviceIntPtr pDev); diff --git a/test/fixes.c b/test/fixes.c index 7807c73ce..4ac6750e4 100644 --- a/test/fixes.c +++ b/test/fixes.c @@ -265,6 +265,32 @@ fixes_pointer_barriers_test(void) x2 = x + 100; assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); + /* ray vert barrier */ + barrier.x1 = x; + barrier.x2 = x; + barrier.y1 = -1; + barrier.y2 = y + 100; + + /* ray barrier simple case */ + y1 = y; + y2 = y; + x1 = x + 50; + x2 = x - 50; + assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); + + /* endpoint outside y range; should be blocked */ + y1 = y - 1000; + y2 = y - 1000; + x1 = x + 50; + x2 = x - 50; + assert(barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); + + /* endpoint outside y range */ + y1 = y + 150; + y2 = y + 150; + x1 = x + 50; + x2 = x - 50; + assert(!barrier_is_blocking(&barrier, x1, y1, x2, y2, &distance)); } static void diff --git a/test/xi2/protocol-eventconvert.c b/test/xi2/protocol-eventconvert.c index bb3177cc1..395774774 100644 --- a/test/xi2/protocol-eventconvert.c +++ b/test/xi2/protocol-eventconvert.c @@ -984,6 +984,221 @@ test_convert_XITouchOwnershipEvent(void) } } +static void +test_XIBarrierEvent(BarrierEvent *in) +{ + xXIBarrierEvent *out, *swapped; + int count; + int rc; + int eventlen; + FP3232 value; + + rc = EventToXI((InternalEvent*)in, (xEvent**)&out, &count); + assert(rc == BadMatch); + + rc = EventToCore((InternalEvent*)in, (xEvent**)&out, &count); + assert(rc == BadMatch); + + rc = EventToXI2((InternalEvent*)in, (xEvent**)&out); + + assert(out->type == GenericEvent); + assert(out->extension == 0); /* IReqCode defaults to 0 */ + assert(out->evtype == GetXI2Type(in->type)); + assert(out->time == in->time); + assert(out->deviceid == in->deviceid); + assert(out->sourceid == in->sourceid); + assert(out->barrier == in->barrierid); + assert(out->flags == in->flags); + assert(out->event == in->window); + assert(out->root == in->root); + assert(out->dtime == in->dt); + assert(out->eventid == in->event_id); + assert(out->root_x == double_to_fp1616(in->root_x)); + assert(out->root_y == double_to_fp1616(in->root_y)); + + value = double_to_fp3232(in->dx); + assert(out->dx.integral == value.integral); + assert(out->dx.frac == value.frac); + value = double_to_fp3232(in->dy); + assert(out->dy.integral == value.integral); + assert(out->dy.frac == value.frac); + + eventlen = sizeof(xEvent) + out->length * 4; + swapped = calloc(1, eventlen); + XI2EventSwap((xGenericEvent *) out, (xGenericEvent *) swapped); + + swaps(&swapped->sequenceNumber); + swapl(&swapped->length); + swaps(&swapped->evtype); + swaps(&swapped->deviceid); + swapl(&swapped->time); + swapl(&swapped->eventid); + swapl(&swapped->root); + swapl(&swapped->event); + swapl(&swapped->barrier); + swapl(&swapped->dtime); + swaps(&swapped->sourceid); + swapl(&swapped->root_x); + swapl(&swapped->root_y); + swapl(&swapped->dx.integral); + swapl(&swapped->dx.frac); + swapl(&swapped->dy.integral); + swapl(&swapped->dy.frac); + + assert(memcmp(swapped, out, eventlen) == 0); + + free(swapped); + free(out); +} + +static void +test_convert_XIBarrierEvent(void) +{ + BarrierEvent in; + + memset(&in, 0, sizeof(in)); + in.header = ET_Internal; + in.type = ET_BarrierHit; + in.length = sizeof(in); + in.time = 0; + in.deviceid = 1; + in.sourceid = 2; + + test_XIBarrierEvent(&in); + + in.deviceid = 1; + while(in.deviceid & 0xFFFF) { + test_XIBarrierEvent(&in); + in.deviceid <<= 1; + } + in.deviceid = 0; + + in.sourceid = 1; + while(in.sourceid & 0xFFFF) { + test_XIBarrierEvent(&in); + in.sourceid <<= 1; + } + in.sourceid = 0; + + in.flags = 1; + while(in.flags) { + test_XIBarrierEvent(&in); + in.flags <<= 1; + } + + in.barrierid = 1; + while(in.barrierid) { + test_XIBarrierEvent(&in); + in.barrierid <<= 1; + } + + in.dt = 1; + while(in.dt) { + test_XIBarrierEvent(&in); + in.dt <<= 1; + } + + in.event_id = 1; + while(in.event_id) { + test_XIBarrierEvent(&in); + in.event_id <<= 1; + } + + in.window = 1; + while(in.window) { + test_XIBarrierEvent(&in); + in.window <<= 1; + } + + in.root = 1; + while(in.root) { + test_XIBarrierEvent(&in); + in.root <<= 1; + } + + /* pseudo-random 16 bit numbers */ + in.root_x = 1; + test_XIBarrierEvent(&in); + in.root_x = 1.3; + test_XIBarrierEvent(&in); + in.root_x = 264.908; + test_XIBarrierEvent(&in); + in.root_x = 35638.292; + test_XIBarrierEvent(&in); + + in.root_x = -1; + test_XIBarrierEvent(&in); + in.root_x = -1.3; + test_XIBarrierEvent(&in); + in.root_x = -264.908; + test_XIBarrierEvent(&in); + in.root_x = -35638.292; + test_XIBarrierEvent(&in); + + in.root_y = 1; + test_XIBarrierEvent(&in); + in.root_y = 1.3; + test_XIBarrierEvent(&in); + in.root_y = 264.908; + test_XIBarrierEvent(&in); + in.root_y = 35638.292; + test_XIBarrierEvent(&in); + + in.root_y = -1; + test_XIBarrierEvent(&in); + in.root_y = -1.3; + test_XIBarrierEvent(&in); + in.root_y = -264.908; + test_XIBarrierEvent(&in); + in.root_y = -35638.292; + test_XIBarrierEvent(&in); + + /* equally pseudo-random 32 bit numbers */ + in.dx = 1; + test_XIBarrierEvent(&in); + in.dx = 1.3; + test_XIBarrierEvent(&in); + in.dx = 264.908; + test_XIBarrierEvent(&in); + in.dx = 35638.292; + test_XIBarrierEvent(&in); + in.dx = 2947813871.2342; + test_XIBarrierEvent(&in); + + in.dx = -1; + test_XIBarrierEvent(&in); + in.dx = -1.3; + test_XIBarrierEvent(&in); + in.dx = -264.908; + test_XIBarrierEvent(&in); + in.dx = -35638.292; + test_XIBarrierEvent(&in); + in.dx = -2947813871.2342; + test_XIBarrierEvent(&in); + + in.dy = 1; + test_XIBarrierEvent(&in); + in.dy = 1.3; + test_XIBarrierEvent(&in); + in.dy = 264.908; + test_XIBarrierEvent(&in); + in.dy = 35638.292; + test_XIBarrierEvent(&in); + in.dy = 2947813871.2342; + test_XIBarrierEvent(&in); + + in.dy = -1; + test_XIBarrierEvent(&in); + in.dy = -1.3; + test_XIBarrierEvent(&in); + in.dy = -264.908; + test_XIBarrierEvent(&in); + in.dy = -35638.292; + test_XIBarrierEvent(&in); + in.dy = -2947813871.2342; + test_XIBarrierEvent(&in); +} + int main(int argc, char **argv) { @@ -992,6 +1207,7 @@ main(int argc, char **argv) test_convert_XIDeviceEvent(); test_convert_XIDeviceChangedEvent(); test_convert_XITouchOwnershipEvent(); + test_convert_XIBarrierEvent(); return 0; } diff --git a/xfixes/cursor.c b/xfixes/cursor.c index ffee4d6ab..568e717fa 100644 --- a/xfixes/cursor.c +++ b/xfixes/cursor.c @@ -56,12 +56,11 @@ #include "windowstr.h" #include "xace.h" #include "list.h" -#include "exglobals.h" +#include "xibarriers.h" static RESTYPE CursorClientType; static RESTYPE CursorHideCountType; static RESTYPE CursorWindowType; -RESTYPE PointerBarrierType; static CursorPtr CursorCurrent[MAXDEVICES]; static DevPrivateKeyRec CursorScreenPrivateKeyRec; @@ -113,16 +112,6 @@ typedef struct _CursorHideCountRec { XID resource; } CursorHideCountRec; -typedef struct PointerBarrierClient *PointerBarrierClientPtr; - -struct PointerBarrierClient { - ScreenPtr screen; - struct PointerBarrier barrier; - struct xorg_list entry; - int num_devices; - int *device_ids; /* num_devices */ -}; - /* * Wrap DisplayCursor to catch cursor change events */ @@ -130,9 +119,7 @@ struct PointerBarrierClient { typedef struct _CursorScreen { DisplayCursorProcPtr DisplayCursor; CloseScreenProcPtr CloseScreen; - ConstrainCursorHarderProcPtr ConstrainCursorHarder; CursorHideCountPtr pCursorHideCounts; - struct xorg_list barriers; } CursorScreenRec, *CursorScreenPtr; #define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) @@ -199,11 +186,9 @@ CursorCloseScreen(ScreenPtr pScreen) Bool ret; _X_UNUSED CloseScreenProcPtr close_proc; _X_UNUSED DisplayCursorProcPtr display_proc; - _X_UNUSED ConstrainCursorHarderProcPtr constrain_proc; Unwrap(cs, pScreen, CloseScreen, close_proc); Unwrap(cs, pScreen, DisplayCursor, display_proc); - Unwrap(cs, pScreen, ConstrainCursorHarder, constrain_proc); deleteCursorHideCountsForScreen(pScreen); ret = (*pScreen->CloseScreen) (pScreen); free(cs); @@ -1013,384 +998,15 @@ CursorFreeWindow(pointer data, XID id) return 1; } -static BOOL -barrier_is_horizontal(const struct PointerBarrier *barrier) -{ - return barrier->y1 == barrier->y2; -} - -static BOOL -barrier_is_vertical(const struct PointerBarrier *barrier) -{ - return barrier->x1 == barrier->x2; -} - -/** - * @return The set of barrier movement directions the movement vector - * x1/y1 → x2/y2 represents. - */ -int -barrier_get_direction(int x1, int y1, int x2, int y2) -{ - int direction = 0; - - /* which way are we trying to go */ - if (x2 > x1) - direction |= BarrierPositiveX; - if (x2 < x1) - direction |= BarrierNegativeX; - if (y2 > y1) - direction |= BarrierPositiveY; - if (y2 < y1) - direction |= BarrierNegativeY; - - return direction; -} - -/** - * Test if the barrier may block movement in the direction defined by - * x1/y1 → x2/y2. This function only tests whether the directions could be - * blocked, it does not test if the barrier actually blocks the movement. - * - * @return TRUE if the barrier blocks the direction of movement or FALSE - * otherwise. - */ -BOOL -barrier_is_blocking_direction(const struct PointerBarrier * barrier, - int direction) -{ - /* Barriers define which way is ok, not which way is blocking */ - return (barrier->directions & direction) != direction; -} - -/** - * Test if the movement vector x1/y1 → x2/y2 is intersecting with the - * barrier. A movement vector with the startpoint or endpoint adjacent to - * the barrier itself counts as intersecting. - * - * @param x1 X start coordinate of movement vector - * @param y1 Y start coordinate of movement vector - * @param x2 X end coordinate of movement vector - * @param y2 Y end coordinate of movement vector - * @param[out] distance The distance between the start point and the - * intersection with the barrier (if applicable). - * @return TRUE if the barrier intersects with the given vector - */ -BOOL -barrier_is_blocking(const struct PointerBarrier * barrier, - int x1, int y1, int x2, int y2, double *distance) -{ - BOOL rc = FALSE; - float ua, ub, ud; - int dir = barrier_get_direction(x1, y1, x2, y2); - - /* Algorithm below doesn't handle edge cases well, hence the extra - * checks. */ - if (barrier_is_vertical(barrier)) { - /* handle immediate barrier adjacency, moving away */ - if (dir & BarrierPositiveX && x1 == barrier->x1) - return FALSE; - if (dir & BarrierNegativeX && x1 == (barrier->x1 - 1)) - return FALSE; - /* startpoint adjacent to barrier, moving towards -> block */ - if (dir & BarrierPositiveX && x1 == (barrier->x1 - 1) && y1 >= barrier->y1 && y1 <= barrier->y2) { - *distance = 0; - return TRUE; - } - if (dir & BarrierNegativeX && x1 == barrier->x1 && y1 >= barrier->y1 && y1 <= barrier->y2) { - *distance = 0; - return TRUE; - } - } - else { - /* handle immediate barrier adjacency, moving away */ - if (dir & BarrierPositiveY && y1 == barrier->y1) - return FALSE; - if (dir & BarrierNegativeY && y1 == (barrier->y1 - 1)) - return FALSE; - /* startpoint adjacent to barrier, moving towards -> block */ - if (dir & BarrierPositiveY && y1 == (barrier->y1 - 1) && x1 >= barrier->x1 && x1 <= barrier->x2) { - *distance = 0; - return TRUE; - } - if (dir & BarrierNegativeY && y1 == barrier->y1 && x1 >= barrier->x1 && x1 <= barrier->x2) { - *distance = 0; - return TRUE; - } - } - - /* not an edge case, compute distance */ - ua = 0; - ud = (barrier->y2 - barrier->y1) * (x2 - x1) - (barrier->x2 - - barrier->x1) * (y2 - y1); - if (ud != 0) { - ua = ((barrier->x2 - barrier->x1) * (y1 - barrier->y1) - - (barrier->y2 - barrier->y1) * (x1 - barrier->x1)) / ud; - ub = ((x2 - x1) * (y1 - barrier->y1) - - (y2 - y1) * (x1 - barrier->x1)) / ud; - if (ua < 0 || ua > 1 || ub < 0 || ub > 1) - ua = 0; - } - - if (ua > 0 && ua <= 1) { - double ix = barrier->x1 + ua * (barrier->x2 - barrier->x1); - double iy = barrier->y1 + ua * (barrier->y2 - barrier->y1); - - *distance = sqrt(pow(x1 - ix, 2) + pow(y1 - iy, 2)); - rc = TRUE; - } - - return rc; -} - -static BOOL -barrier_blocks_device(struct PointerBarrierClient *client, - DeviceIntPtr dev) -{ - int i; - int master_id; - - /* Clients with no devices are treated as - * if they specified XIAllDevices. */ - if (client->num_devices == 0) - return TRUE; - - master_id = GetMaster(dev, POINTER_OR_FLOAT)->id; - - for (i = 0; i < client->num_devices; i++) { - int device_id = client->device_ids[i]; - if (device_id == XIAllDevices || - device_id == XIAllMasterDevices || - device_id == master_id) - return TRUE; - } - - return FALSE; -} - -/** - * Find the nearest barrier that is blocking movement from x1/y1 to x2/y2. - * - * @param dir Only barriers blocking movement in direction dir are checked - * @param x1 X start coordinate of movement vector - * @param y1 Y start coordinate of movement vector - * @param x2 X end coordinate of movement vector - * @param y2 Y end coordinate of movement vector - * @return The barrier nearest to the movement origin that blocks this movement. - */ -static struct PointerBarrier * -barrier_find_nearest(CursorScreenPtr cs, DeviceIntPtr dev, - int dir, - int x1, int y1, int x2, int y2) -{ - struct PointerBarrierClient *c; - struct PointerBarrier *nearest = NULL; - double min_distance = INT_MAX; /* can't get higher than that in X anyway */ - - xorg_list_for_each_entry(c, &cs->barriers, entry) { - struct PointerBarrier *b = &c->barrier; - double distance; - - if (!barrier_is_blocking_direction(b, dir)) - continue; - - if (!barrier_blocks_device(c, dev)) - continue; - - if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) { - if (min_distance > distance) { - min_distance = distance; - nearest = b; - } - } - } - - return nearest; -} - -/** - * Clamp to the given barrier given the movement direction specified in dir. - * - * @param barrier The barrier to clamp to - * @param dir The movement direction - * @param[out] x The clamped x coordinate. - * @param[out] y The clamped x coordinate. - */ -void -barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, - int *y) -{ - if (barrier_is_vertical(barrier)) { - if ((dir & BarrierNegativeX) & ~barrier->directions) - *x = barrier->x1; - if ((dir & BarrierPositiveX) & ~barrier->directions) - *x = barrier->x1 - 1; - } - if (barrier_is_horizontal(barrier)) { - if ((dir & BarrierNegativeY) & ~barrier->directions) - *y = barrier->y1; - if ((dir & BarrierPositiveY) & ~barrier->directions) - *y = barrier->y1 - 1; - } -} - -static void -CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, - int *x, int *y) -{ - CursorScreenPtr cs = GetCursorScreen(screen); - - if (!xorg_list_is_empty(&cs->barriers) && !IsFloating(dev) && - mode == Relative) { - int ox, oy; - int dir; - int i; - struct PointerBarrier *nearest = NULL; - - /* where are we coming from */ - miPointerGetPosition(dev, &ox, &oy); - - /* How this works: - * Given the origin and the movement vector, get the nearest barrier - * to the origin that is blocking the movement. - * Clamp to that barrier. - * Then, check from the clamped intersection to the original - * destination, again finding the nearest barrier and clamping. - */ - dir = barrier_get_direction(ox, oy, *x, *y); - -#define MAX_BARRIERS 2 - for (i = 0; i < MAX_BARRIERS; i++) { - nearest = barrier_find_nearest(cs, dev, dir, ox, oy, *x, *y); - if (!nearest) - break; - - barrier_clamp_to_barrier(nearest, dir, x, y); - - if (barrier_is_vertical(nearest)) { - dir &= ~(BarrierNegativeX | BarrierPositiveX); - ox = *x; - } - else if (barrier_is_horizontal(nearest)) { - dir &= ~(BarrierNegativeY | BarrierPositiveY); - oy = *y; - } - } - } - - if (cs->ConstrainCursorHarder) { - screen->ConstrainCursorHarder = cs->ConstrainCursorHarder; - screen->ConstrainCursorHarder(dev, screen, mode, x, y); - screen->ConstrainCursorHarder = CursorConstrainCursorHarder; - } -} - -static int -CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client, - xXFixesCreatePointerBarrierReq * stuff, - PointerBarrierClientPtr *client_out) -{ - CursorScreenPtr cs = GetCursorScreen(screen); - int err; - int size; - int i; - CARD16 *in_devices; - struct PointerBarrierClient *ret; - - size = sizeof(*ret) + sizeof(int) * stuff->num_devices; - ret = malloc(size); - - *client_out = NULL; - - if (!ret) { - return BadAlloc; - } - - ret->screen = screen; - ret->num_devices = stuff->num_devices; - if (ret->num_devices > 0) - ret->device_ids = (int*)&ret[1]; - else - ret->device_ids = NULL; - - in_devices = (CARD16 *) &stuff[1]; - for (i = 0; i < stuff->num_devices; i++) { - int device_id = in_devices[i]; - DeviceIntPtr device; - - if ((err = dixLookupDevice (&device, device_id, - client, DixReadAccess))) { - client->errorValue = device_id; - goto error; - } - - if (!IsMaster (device)) { - client->errorValue = device_id; - err = BadDevice; - goto error; - } - - ret->device_ids[i] = device_id; - } - - ret->barrier.x1 = min(stuff->x1, stuff->x2); - ret->barrier.x2 = max(stuff->x1, stuff->x2); - ret->barrier.y1 = min(stuff->y1, stuff->y2); - ret->barrier.y2 = max(stuff->y1, stuff->y2); - ret->barrier.directions = stuff->directions & 0x0f; - if (barrier_is_horizontal(&ret->barrier)) - ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX); - if (barrier_is_vertical(&ret->barrier)) - ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY); - xorg_list_add(&ret->entry, &cs->barriers); - - *client_out = ret; - return Success; - - error: - free(ret); - return err; -} - int ProcXFixesCreatePointerBarrier(ClientPtr client) { - int err; - WindowPtr pWin; - struct PointerBarrierClient *barrier; - struct PointerBarrier b; - REQUEST(xXFixesCreatePointerBarrierReq); REQUEST_FIXED_SIZE(xXFixesCreatePointerBarrierReq, pad_to_int32(stuff->num_devices)); LEGAL_NEW_RESOURCE(stuff->barrier, client); - err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); - if (err != Success) { - client->errorValue = stuff->window; - return err; - } - - b.x1 = stuff->x1; - b.x2 = stuff->x2; - b.y1 = stuff->y1; - b.y2 = stuff->y2; - - if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b)) - return BadValue; - - /* no 0-sized barriers */ - if (barrier_is_horizontal(&b) && barrier_is_vertical(&b)) - return BadValue; - - if ((err = CreatePointerBarrierClient(pWin->drawable.pScreen, - client, stuff, &barrier))) - return err; - - if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier)) - return BadAlloc; - - return Success; + return XICreatePointerBarrier(client, stuff); } int @@ -1418,49 +1034,14 @@ SProcXFixesCreatePointerBarrier(ClientPtr client) return ProcXFixesVector[stuff->xfixesReqType] (client); } -static int -CursorFreeBarrier(void *data, XID id) -{ - struct PointerBarrierClient *b = NULL, *barrier; - ScreenPtr screen; - CursorScreenPtr cs; - - barrier = container_of(data, struct PointerBarrierClient, barrier); - - screen = barrier->screen; - cs = GetCursorScreen(screen); - - /* find and unlink from the screen private */ - xorg_list_for_each_entry(b, &cs->barriers, entry) { - if (b == barrier) { - xorg_list_del(&b->entry); - break; - } - } - - free(barrier); - return Success; -} - int ProcXFixesDestroyPointerBarrier(ClientPtr client) { - int err; - void *barrier; - REQUEST(xXFixesDestroyPointerBarrierReq); REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); - err = dixLookupResourceByType((void **) &barrier, stuff->barrier, - PointerBarrierType, client, DixDestroyAccess); - if (err != Success) { - client->errorValue = stuff->barrier; - return err; - } - - FreeResource(stuff->barrier, RT_NONE); - return Success; + return XIDestroyPointerBarrier(client, stuff); } int @@ -1492,10 +1073,8 @@ XFixesCursorInit(void) cs = (CursorScreenPtr) calloc(1, sizeof(CursorScreenRec)); if (!cs) return FALSE; - xorg_list_init(&cs->barriers); Wrap(cs, pScreen, CloseScreen, CursorCloseScreen); Wrap(cs, pScreen, DisplayCursor, CursorDisplayCursor); - Wrap(cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder); cs->pCursorHideCounts = NULL; SetCursorScreen(pScreen, cs); } @@ -1505,9 +1084,6 @@ XFixesCursorInit(void) "XFixesCursorHideCount"); CursorWindowType = CreateNewResourceType(CursorFreeWindow, "XFixesCursorWindow"); - PointerBarrierType = CreateNewResourceType(CursorFreeBarrier, - "XFixesPointerBarrier"); - return CursorClientType && CursorHideCountType && CursorWindowType && - PointerBarrierType; + return CursorClientType && CursorHideCountType && CursorWindowType; } diff --git a/xfixes/xfixes.h b/xfixes/xfixes.h index 19af09f7d..98828710f 100644 --- a/xfixes/xfixes.h +++ b/xfixes/xfixes.h @@ -30,7 +30,6 @@ #include "resource.h" extern _X_EXPORT RESTYPE RegionResType; -extern _X_EXPORT RESTYPE PointerBarrierType; extern _X_EXPORT int XFixesErrorBase; #define VERIFY_REGION(pRegion, rid, client, mode) \ @@ -52,20 +51,6 @@ extern _X_EXPORT int XFixesErrorBase; extern _X_EXPORT RegionPtr XFixesRegionCopy(RegionPtr pRegion); -struct PointerBarrier { - CARD16 x1, x2, y1, y2; - CARD32 directions; -}; - -extern int - barrier_get_direction(int, int, int, int); -extern BOOL -barrier_is_blocking(const struct PointerBarrier *, int, int, int, int, - double *); -extern BOOL barrier_is_blocking_direction(const struct PointerBarrier *, int); -extern void - -barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, - int *y); +#include "xibarriers.h" #endif /* _XFIXES_H_ */ |