From 3f553aaceddc9b09363c73d9bea40eaea8164fc4 Mon Sep 17 00:00:00 2001
From: marha <marha@users.sourceforge.net>
Date: Mon, 7 Jan 2013 11:56:06 +0100
Subject: pixman xkbcomp libX11 libXau mesa fontconfig xserver xkeyboard-config
 git update 7 jan 2013

fontconfig: 17eda89ed2e24a3fc5f68538dd7fd9ada8efb087
xserver: bd91b05b631f13afd1f7a9d6cbc4f0c5408b523a
xkeyboard-config: 4779e2745094ebe0c06364b4099d7067ae750d07
libX11: cd25cab4b5b957641183ce72dd1ae0424aff1663
libXau: e04364efccbb3bb4cfc5f4cb491ffa1faaaacbdb
mesa: afec10df373f342f058aab66c622237964a4a147
pixman: 35cc965514ca6e665c18411fcf66db826d559c2a
xkbcomp: e4f767913338052527538d429931e8abd8c3fb88
---
 xorg-server/Xi/Makefile.am         |   2 +
 xorg-server/Xi/exevents.c          |  47 ++
 xorg-server/Xi/extinit.c           |  47 +-
 xorg-server/Xi/gtmotion.c          |   2 +-
 xorg-server/Xi/xibarriers.c        | 916 +++++++++++++++++++++++++++++++++++++
 xorg-server/Xi/xibarriers.h        |  48 ++
 xorg-server/Xi/xichangehierarchy.c |  16 +-
 xorg-server/Xi/xiquerydevice.c     |   4 +-
 8 files changed, 1069 insertions(+), 13 deletions(-)
 create mode 100644 xorg-server/Xi/xibarriers.c
 create mode 100644 xorg-server/Xi/xibarriers.h

(limited to 'xorg-server/Xi')

diff --git a/xorg-server/Xi/Makefile.am b/xorg-server/Xi/Makefile.am
index 69c7886b9..af85bd049 100644
--- a/xorg-server/Xi/Makefile.am
+++ b/xorg-server/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/xorg-server/Xi/exevents.c b/xorg-server/Xi/exevents.c
index 4c1aeb4da..58fe49363 100644
--- a/xorg-server/Xi/exevents.c
+++ b/xorg-server/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/xorg-server/Xi/extinit.c b/xorg-server/Xi/extinit.c
index 7e3075551..619d0e468 100644
--- a/xorg-server/Xi/extinit.c
+++ b/xorg-server/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 */
 };
 
 /*****************************************************************
@@ -646,7 +649,7 @@ SDeviceChangedEvent(xXIDeviceChangedEvent * from, xXIDeviceChangedEvent * to)
     *to = *from;
     memcpy(&to[1], &from[1], from->length * 4);
 
-    any = (xXIAnyInfo *) & to[1];
+    any = (xXIAnyInfo *) &to[1];
     for (i = 0; i < to->num_classes; i++) {
         int length = any->length;
 
@@ -654,7 +657,7 @@ SDeviceChangedEvent(xXIDeviceChangedEvent * from, xXIDeviceChangedEvent * to)
         case KeyClass:
         {
             xXIKeyInfo *ki = (xXIKeyInfo *) any;
-            uint32_t *key = (uint32_t *) & ki[1];
+            uint32_t *key = (uint32_t *) &ki[1];
 
             for (j = 0; j < ki->num_keycodes; j++, key++)
                 swapl(key);
@@ -765,7 +768,7 @@ SDeviceHierarchyEvent(xXIHierarchyEvent * from, xXIHierarchyEvent * to)
     swapl(&to->flags);
     swaps(&to->num_info);
 
-    info = (xXIHierarchyInfo *) & to[1];
+    info = (xXIHierarchyInfo *) &to[1];
     for (i = 0; i < from->num_info; i++) {
         swaps(&info->deviceid);
         swaps(&info->attachment);
@@ -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/xorg-server/Xi/gtmotion.c b/xorg-server/Xi/gtmotion.c
index 4642b194a..cde5351a6 100644
--- a/xorg-server/Xi/gtmotion.c
+++ b/xorg-server/Xi/gtmotion.c
@@ -131,7 +131,7 @@ ProcXGetDeviceMotionEvents(ClientPtr client)
     num_events = v->numMotionEvents;
     if (num_events) {
         size = sizeof(Time) + (axes * sizeof(INT32));
-        rep.nEvents = GetMotionHistory(dev, (xTimecoord **) & coords,   /* XXX */
+        rep.nEvents = GetMotionHistory(dev, (xTimecoord **) &coords,   /* XXX */
                                        start.milliseconds, stop.milliseconds,
                                        (ScreenPtr) NULL, FALSE);
     }
diff --git a/xorg-server/Xi/xibarriers.c b/xorg-server/Xi/xibarriers.c
new file mode 100644
index 000000000..7b7b83f1c
--- /dev/null
+++ b/xorg-server/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/xorg-server/Xi/xibarriers.h b/xorg-server/Xi/xibarriers.h
new file mode 100644
index 000000000..11e84ec9f
--- /dev/null
+++ b/xorg-server/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/xorg-server/Xi/xichangehierarchy.c b/xorg-server/Xi/xichangehierarchy.c
index 89f16d8be..e2f4b8a0a 100644
--- a/xorg-server/Xi/xichangehierarchy.c
+++ b/xorg-server/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.
@@ -79,7 +80,7 @@ XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
     ev->flags = 0;
     ev->num_info = inputInfo.numDevices;
 
-    info = (xXIHierarchyInfo *) & ev[1];
+    info = (xXIHierarchyInfo *) &ev[1];
     for (dev = inputInfo.devices; dev; dev = dev->next) {
         info->deviceid = dev->id;
         info->enabled = dev->enabled;
@@ -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);
@@ -304,15 +309,16 @@ remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
     flags[keybd->id] |= XIDeviceDisabled;
     flags[ptr->id] |= XIDeviceDisabled;
 
-    RemoveDevice(XTestptr, FALSE);
-    RemoveDevice(XTestkeybd, FALSE);
-    RemoveDevice(keybd, FALSE);
-    RemoveDevice(ptr, FALSE);
     flags[XTestptr->id] |= XISlaveRemoved;
     flags[XTestkeybd->id] |= XISlaveRemoved;
     flags[keybd->id] |= XIMasterRemoved;
     flags[ptr->id] |= XIMasterRemoved;
 
+    RemoveDevice(XTestptr, FALSE);
+    RemoveDevice(XTestkeybd, FALSE);
+    RemoveDevice(keybd, FALSE);
+    RemoveDevice(ptr, FALSE);
+
  unwind:
     return rc;
 }
diff --git a/xorg-server/Xi/xiquerydevice.c b/xorg-server/Xi/xiquerydevice.c
index 85c1dd81d..4e544f0f5 100644
--- a/xorg-server/Xi/xiquerydevice.c
+++ b/xorg-server/Xi/xiquerydevice.c
@@ -304,7 +304,7 @@ ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info)
     info->length = sizeof(xXIKeyInfo) / 4 + info->num_keycodes;
     info->sourceid = dev->key->sourceid;
 
-    kc = (uint32_t *) & info[1];
+    kc = (uint32_t *) &info[1];
     for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++)
         *kc = i;
 
@@ -321,7 +321,7 @@ SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info)
     swaps(&info->length);
     swaps(&info->sourceid);
 
-    for (i = 0, key = (uint32_t *) & info[1]; i < info->num_keycodes;
+    for (i = 0, key = (uint32_t *) &info[1]; i < info->num_keycodes;
          i++, key++)
         swapl(key);
 
-- 
cgit v1.2.3