135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright 2012 Red Hat, Inc.
335c4bbdfSmrg *
435c4bbdfSmrg * Permission is hereby granted, free of charge, to any person obtaining a
535c4bbdfSmrg * copy of this software and associated documentation files (the "Software"),
635c4bbdfSmrg * to deal in the Software without restriction, including without limitation
735c4bbdfSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
835c4bbdfSmrg * and/or sell copies of the Software, and to permit persons to whom the
935c4bbdfSmrg * Software is furnished to do so, subject to the following conditions:
1035c4bbdfSmrg *
1135c4bbdfSmrg * The above copyright notice and this permission notice (including the next
1235c4bbdfSmrg * paragraph) shall be included in all copies or substantial portions of the
1335c4bbdfSmrg * Software.
1435c4bbdfSmrg *
1535c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1635c4bbdfSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1735c4bbdfSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1835c4bbdfSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1935c4bbdfSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2035c4bbdfSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2135c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
2235c4bbdfSmrg *
2335c4bbdfSmrg * Copyright © 2002 Keith Packard
2435c4bbdfSmrg *
2535c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
2635c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
2735c4bbdfSmrg * the above copyright notice appear in all copies and that both that
2835c4bbdfSmrg * copyright notice and this permission notice appear in supporting
2935c4bbdfSmrg * documentation, and that the name of Keith Packard not be used in
3035c4bbdfSmrg * advertising or publicity pertaining to distribution of the software without
3135c4bbdfSmrg * specific, written prior permission.  Keith Packard makes no
3235c4bbdfSmrg * representations about the suitability of this software for any purpose.  It
3335c4bbdfSmrg * is provided "as is" without express or implied warranty.
3435c4bbdfSmrg *
3535c4bbdfSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
3635c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
3735c4bbdfSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
3835c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
3935c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
4035c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
4135c4bbdfSmrg * PERFORMANCE OF THIS SOFTWARE.
4235c4bbdfSmrg */
4335c4bbdfSmrg
4435c4bbdfSmrg#ifdef HAVE_DIX_CONFIG_H
4535c4bbdfSmrg#include <dix-config.h>
4635c4bbdfSmrg#endif
4735c4bbdfSmrg
4835c4bbdfSmrg#include "xibarriers.h"
4935c4bbdfSmrg#include "scrnintstr.h"
5035c4bbdfSmrg#include "cursorstr.h"
5135c4bbdfSmrg#include "dixevents.h"
5235c4bbdfSmrg#include "servermd.h"
5335c4bbdfSmrg#include "mipointer.h"
5435c4bbdfSmrg#include "inputstr.h"
5535c4bbdfSmrg#include "windowstr.h"
5635c4bbdfSmrg#include "xace.h"
5735c4bbdfSmrg#include "list.h"
5835c4bbdfSmrg#include "exglobals.h"
5935c4bbdfSmrg#include "eventstr.h"
6035c4bbdfSmrg#include "mi.h"
6135c4bbdfSmrg
6235c4bbdfSmrgRESTYPE PointerBarrierType;
6335c4bbdfSmrg
6435c4bbdfSmrgstatic DevPrivateKeyRec BarrierScreenPrivateKeyRec;
6535c4bbdfSmrg
6635c4bbdfSmrg#define BarrierScreenPrivateKey (&BarrierScreenPrivateKeyRec)
6735c4bbdfSmrg
6835c4bbdfSmrgtypedef struct PointerBarrierClient *PointerBarrierClientPtr;
6935c4bbdfSmrg
7035c4bbdfSmrgstruct PointerBarrierDevice {
7135c4bbdfSmrg    struct xorg_list entry;
7235c4bbdfSmrg    int deviceid;
7335c4bbdfSmrg    Time last_timestamp;
7435c4bbdfSmrg    int barrier_event_id;
7535c4bbdfSmrg    int release_event_id;
7635c4bbdfSmrg    Bool hit;
7735c4bbdfSmrg    Bool seen;
7835c4bbdfSmrg};
7935c4bbdfSmrg
8035c4bbdfSmrgstruct PointerBarrierClient {
8135c4bbdfSmrg    XID id;
8235c4bbdfSmrg    ScreenPtr screen;
8335c4bbdfSmrg    Window window;
8435c4bbdfSmrg    struct PointerBarrier barrier;
8535c4bbdfSmrg    struct xorg_list entry;
8635c4bbdfSmrg    /* num_devices/device_ids are devices the barrier applies to */
8735c4bbdfSmrg    int num_devices;
8835c4bbdfSmrg    int *device_ids; /* num_devices */
8935c4bbdfSmrg
9035c4bbdfSmrg    /* per_device keeps track of devices actually blocked by barriers */
9135c4bbdfSmrg    struct xorg_list per_device;
9235c4bbdfSmrg};
9335c4bbdfSmrg
9435c4bbdfSmrgtypedef struct _BarrierScreen {
9535c4bbdfSmrg    struct xorg_list barriers;
9635c4bbdfSmrg} BarrierScreenRec, *BarrierScreenPtr;
9735c4bbdfSmrg
9835c4bbdfSmrg#define GetBarrierScreen(s) ((BarrierScreenPtr)dixLookupPrivate(&(s)->devPrivates, BarrierScreenPrivateKey))
9935c4bbdfSmrg#define GetBarrierScreenIfSet(s) GetBarrierScreen(s)
10035c4bbdfSmrg#define SetBarrierScreen(s,p) dixSetPrivate(&(s)->devPrivates, BarrierScreenPrivateKey, p)
10135c4bbdfSmrg
10235c4bbdfSmrgstatic struct PointerBarrierDevice *AllocBarrierDevice(void)
10335c4bbdfSmrg{
10435c4bbdfSmrg    struct PointerBarrierDevice *pbd = NULL;
10535c4bbdfSmrg
10635c4bbdfSmrg    pbd = malloc(sizeof(struct PointerBarrierDevice));
10735c4bbdfSmrg    if (!pbd)
10835c4bbdfSmrg        return NULL;
10935c4bbdfSmrg
11035c4bbdfSmrg    pbd->deviceid = -1; /* must be set by caller */
11135c4bbdfSmrg    pbd->barrier_event_id = 1;
11235c4bbdfSmrg    pbd->release_event_id = 0;
11335c4bbdfSmrg    pbd->hit = FALSE;
11435c4bbdfSmrg    pbd->seen = FALSE;
11535c4bbdfSmrg    xorg_list_init(&pbd->entry);
11635c4bbdfSmrg
11735c4bbdfSmrg    return pbd;
11835c4bbdfSmrg}
11935c4bbdfSmrg
12035c4bbdfSmrgstatic void FreePointerBarrierClient(struct PointerBarrierClient *c)
12135c4bbdfSmrg{
12235c4bbdfSmrg    struct PointerBarrierDevice *pbd = NULL, *tmp = NULL;
12335c4bbdfSmrg
12435c4bbdfSmrg    xorg_list_for_each_entry_safe(pbd, tmp, &c->per_device, entry) {
12535c4bbdfSmrg        free(pbd);
12635c4bbdfSmrg    }
12735c4bbdfSmrg    free(c);
12835c4bbdfSmrg}
12935c4bbdfSmrg
13035c4bbdfSmrgstatic struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid)
13135c4bbdfSmrg{
132d566a54bSmrg    struct PointerBarrierDevice *p, *pbd = NULL;
13335c4bbdfSmrg
134d566a54bSmrg    xorg_list_for_each_entry(p, &c->per_device, entry) {
135d566a54bSmrg        if (p->deviceid == deviceid) {
136d566a54bSmrg            pbd = p;
13735c4bbdfSmrg            break;
138d566a54bSmrg        }
13935c4bbdfSmrg    }
14035c4bbdfSmrg
14135c4bbdfSmrg    return pbd;
14235c4bbdfSmrg}
14335c4bbdfSmrg
14435c4bbdfSmrgstatic BOOL
14535c4bbdfSmrgbarrier_is_horizontal(const struct PointerBarrier *barrier)
14635c4bbdfSmrg{
14735c4bbdfSmrg    return barrier->y1 == barrier->y2;
14835c4bbdfSmrg}
14935c4bbdfSmrg
15035c4bbdfSmrgstatic BOOL
15135c4bbdfSmrgbarrier_is_vertical(const struct PointerBarrier *barrier)
15235c4bbdfSmrg{
15335c4bbdfSmrg    return barrier->x1 == barrier->x2;
15435c4bbdfSmrg}
15535c4bbdfSmrg
15635c4bbdfSmrg/**
15735c4bbdfSmrg * @return The set of barrier movement directions the movement vector
15835c4bbdfSmrg * x1/y1x2/y2 represents.
15935c4bbdfSmrg */
16035c4bbdfSmrgint
16135c4bbdfSmrgbarrier_get_direction(int x1, int y1, int x2, int y2)
16235c4bbdfSmrg{
16335c4bbdfSmrg    int direction = 0;
16435c4bbdfSmrg
16535c4bbdfSmrg    /* which way are we trying to go */
16635c4bbdfSmrg    if (x2 > x1)
16735c4bbdfSmrg        direction |= BarrierPositiveX;
16835c4bbdfSmrg    if (x2 < x1)
16935c4bbdfSmrg        direction |= BarrierNegativeX;
17035c4bbdfSmrg    if (y2 > y1)
17135c4bbdfSmrg        direction |= BarrierPositiveY;
17235c4bbdfSmrg    if (y2 < y1)
17335c4bbdfSmrg        direction |= BarrierNegativeY;
17435c4bbdfSmrg
17535c4bbdfSmrg    return direction;
17635c4bbdfSmrg}
17735c4bbdfSmrg
17835c4bbdfSmrg/**
17935c4bbdfSmrg * Test if the barrier may block movement in the direction defined by
18035c4bbdfSmrg * x1/y1x2/y2. This function only tests whether the directions could be
18135c4bbdfSmrg * blocked, it does not test if the barrier actually blocks the movement.
18235c4bbdfSmrg *
18335c4bbdfSmrg * @return TRUE if the barrier blocks the direction of movement or FALSE
18435c4bbdfSmrg * otherwise.
18535c4bbdfSmrg */
18635c4bbdfSmrgBOOL
18735c4bbdfSmrgbarrier_is_blocking_direction(const struct PointerBarrier * barrier,
18835c4bbdfSmrg                              int direction)
18935c4bbdfSmrg{
19035c4bbdfSmrg    /* Barriers define which way is ok, not which way is blocking */
19135c4bbdfSmrg    return (barrier->directions & direction) != direction;
19235c4bbdfSmrg}
19335c4bbdfSmrg
19435c4bbdfSmrgstatic BOOL
19535c4bbdfSmrginside_segment(int v, int v1, int v2)
19635c4bbdfSmrg{
19735c4bbdfSmrg    if (v1 < 0 && v2 < 0) /* line */
19835c4bbdfSmrg        return TRUE;
19935c4bbdfSmrg    else if (v1 < 0)      /* ray */
20035c4bbdfSmrg        return v <= v2;
20135c4bbdfSmrg    else if (v2 < 0)      /* ray */
20235c4bbdfSmrg        return v >= v1;
20335c4bbdfSmrg    else                  /* line segment */
20435c4bbdfSmrg        return v >= v1 && v <= v2;
20535c4bbdfSmrg}
20635c4bbdfSmrg
20735c4bbdfSmrg#define T(v, a, b) (((float)v) - (a)) / ((b) - (a))
20835c4bbdfSmrg#define F(t, a, b) ((t) * ((a) - (b)) + (a))
20935c4bbdfSmrg
21035c4bbdfSmrg/**
21135c4bbdfSmrg * Test if the movement vector x1/y1x2/y2 is intersecting with the
21235c4bbdfSmrg * barrier. A movement vector with the startpoint or endpoint adjacent to
21335c4bbdfSmrg * the barrier itself counts as intersecting.
21435c4bbdfSmrg *
21535c4bbdfSmrg * @param x1 X start coordinate of movement vector
21635c4bbdfSmrg * @param y1 Y start coordinate of movement vector
21735c4bbdfSmrg * @param x2 X end coordinate of movement vector
21835c4bbdfSmrg * @param y2 Y end coordinate of movement vector
21935c4bbdfSmrg * @param[out] distance The distance between the start point and the
22035c4bbdfSmrg * intersection with the barrier (if applicable).
22135c4bbdfSmrg * @return TRUE if the barrier intersects with the given vector
22235c4bbdfSmrg */
22335c4bbdfSmrgBOOL
22435c4bbdfSmrgbarrier_is_blocking(const struct PointerBarrier * barrier,
22535c4bbdfSmrg                    int x1, int y1, int x2, int y2, double *distance)
22635c4bbdfSmrg{
22735c4bbdfSmrg    if (barrier_is_vertical(barrier)) {
22835c4bbdfSmrg        float t, y;
22935c4bbdfSmrg        t = T(barrier->x1, x1, x2);
23035c4bbdfSmrg        if (t < 0 || t > 1)
23135c4bbdfSmrg            return FALSE;
23235c4bbdfSmrg
23335c4bbdfSmrg        /* Edge case: moving away from barrier. */
23435c4bbdfSmrg        if (x2 > x1 && t == 0)
23535c4bbdfSmrg            return FALSE;
23635c4bbdfSmrg
23735c4bbdfSmrg        y = F(t, y1, y2);
23835c4bbdfSmrg        if (!inside_segment(y, barrier->y1, barrier->y2))
23935c4bbdfSmrg            return FALSE;
24035c4bbdfSmrg
24135c4bbdfSmrg        *distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2)));
24235c4bbdfSmrg        return TRUE;
24335c4bbdfSmrg    }
24435c4bbdfSmrg    else {
24535c4bbdfSmrg        float t, x;
24635c4bbdfSmrg        t = T(barrier->y1, y1, y2);
24735c4bbdfSmrg        if (t < 0 || t > 1)
24835c4bbdfSmrg            return FALSE;
24935c4bbdfSmrg
25035c4bbdfSmrg        /* Edge case: moving away from barrier. */
25135c4bbdfSmrg        if (y2 > y1 && t == 0)
25235c4bbdfSmrg            return FALSE;
25335c4bbdfSmrg
25435c4bbdfSmrg        x = F(t, x1, x2);
25535c4bbdfSmrg        if (!inside_segment(x, barrier->x1, barrier->x2))
25635c4bbdfSmrg            return FALSE;
25735c4bbdfSmrg
25835c4bbdfSmrg        *distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2)));
25935c4bbdfSmrg        return TRUE;
26035c4bbdfSmrg    }
26135c4bbdfSmrg}
26235c4bbdfSmrg
26335c4bbdfSmrg#define HIT_EDGE_EXTENTS 2
26435c4bbdfSmrgstatic BOOL
26535c4bbdfSmrgbarrier_inside_hit_box(struct PointerBarrier *barrier, int x, int y)
26635c4bbdfSmrg{
26735c4bbdfSmrg    int x1, x2, y1, y2;
26835c4bbdfSmrg    int dir;
26935c4bbdfSmrg
27035c4bbdfSmrg    x1 = barrier->x1;
27135c4bbdfSmrg    x2 = barrier->x2;
27235c4bbdfSmrg    y1 = barrier->y1;
27335c4bbdfSmrg    y2 = barrier->y2;
27435c4bbdfSmrg    dir = ~(barrier->directions);
27535c4bbdfSmrg
27635c4bbdfSmrg    if (barrier_is_vertical(barrier)) {
27735c4bbdfSmrg        if (dir & BarrierPositiveX)
27835c4bbdfSmrg            x1 -= HIT_EDGE_EXTENTS;
27935c4bbdfSmrg        if (dir & BarrierNegativeX)
28035c4bbdfSmrg            x2 += HIT_EDGE_EXTENTS;
28135c4bbdfSmrg    }
28235c4bbdfSmrg    if (barrier_is_horizontal(barrier)) {
28335c4bbdfSmrg        if (dir & BarrierPositiveY)
28435c4bbdfSmrg            y1 -= HIT_EDGE_EXTENTS;
28535c4bbdfSmrg        if (dir & BarrierNegativeY)
28635c4bbdfSmrg            y2 += HIT_EDGE_EXTENTS;
28735c4bbdfSmrg    }
28835c4bbdfSmrg
28935c4bbdfSmrg    return x >= x1 && x <= x2 && y >= y1 && y <= y2;
29035c4bbdfSmrg}
29135c4bbdfSmrg
29235c4bbdfSmrgstatic BOOL
29335c4bbdfSmrgbarrier_blocks_device(struct PointerBarrierClient *client,
29435c4bbdfSmrg                      DeviceIntPtr dev)
29535c4bbdfSmrg{
29635c4bbdfSmrg    int i;
29735c4bbdfSmrg    int master_id;
29835c4bbdfSmrg
29935c4bbdfSmrg    /* Clients with no devices are treated as
30035c4bbdfSmrg     * if they specified XIAllDevices. */
30135c4bbdfSmrg    if (client->num_devices == 0)
30235c4bbdfSmrg        return TRUE;
30335c4bbdfSmrg
30435c4bbdfSmrg    master_id = GetMaster(dev, POINTER_OR_FLOAT)->id;
30535c4bbdfSmrg
30635c4bbdfSmrg    for (i = 0; i < client->num_devices; i++) {
30735c4bbdfSmrg        int device_id = client->device_ids[i];
30835c4bbdfSmrg        if (device_id == XIAllDevices ||
30935c4bbdfSmrg            device_id == XIAllMasterDevices ||
31035c4bbdfSmrg            device_id == master_id)
31135c4bbdfSmrg            return TRUE;
31235c4bbdfSmrg    }
31335c4bbdfSmrg
31435c4bbdfSmrg    return FALSE;
31535c4bbdfSmrg}
31635c4bbdfSmrg
31735c4bbdfSmrg/**
31835c4bbdfSmrg * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2.
31935c4bbdfSmrg *
32035c4bbdfSmrg * @param dir Only barriers blocking movement in direction dir are checked
32135c4bbdfSmrg * @param x1 X start coordinate of movement vector
32235c4bbdfSmrg * @param y1 Y start coordinate of movement vector
32335c4bbdfSmrg * @param x2 X end coordinate of movement vector
32435c4bbdfSmrg * @param y2 Y end coordinate of movement vector
32535c4bbdfSmrg * @return The barrier nearest to the movement origin that blocks this movement.
32635c4bbdfSmrg */
32735c4bbdfSmrgstatic struct PointerBarrierClient *
32835c4bbdfSmrgbarrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev,
32935c4bbdfSmrg                     int dir,
33035c4bbdfSmrg                     int x1, int y1, int x2, int y2)
33135c4bbdfSmrg{
33235c4bbdfSmrg    struct PointerBarrierClient *c, *nearest = NULL;
33335c4bbdfSmrg    double min_distance = INT_MAX;      /* can't get higher than that in X anyway */
33435c4bbdfSmrg
33535c4bbdfSmrg    xorg_list_for_each_entry(c, &cs->barriers, entry) {
33635c4bbdfSmrg        struct PointerBarrier *b = &c->barrier;
33735c4bbdfSmrg        struct PointerBarrierDevice *pbd;
33835c4bbdfSmrg        double distance;
33935c4bbdfSmrg
34035c4bbdfSmrg        pbd = GetBarrierDevice(c, dev->id);
341d566a54bSmrg        if (!pbd)
342d566a54bSmrg            continue;
343d566a54bSmrg
34435c4bbdfSmrg        if (pbd->seen)
34535c4bbdfSmrg            continue;
34635c4bbdfSmrg
34735c4bbdfSmrg        if (!barrier_is_blocking_direction(b, dir))
34835c4bbdfSmrg            continue;
34935c4bbdfSmrg
35035c4bbdfSmrg        if (!barrier_blocks_device(c, dev))
35135c4bbdfSmrg            continue;
35235c4bbdfSmrg
35335c4bbdfSmrg        if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) {
35435c4bbdfSmrg            if (min_distance > distance) {
35535c4bbdfSmrg                min_distance = distance;
35635c4bbdfSmrg                nearest = c;
35735c4bbdfSmrg            }
35835c4bbdfSmrg        }
35935c4bbdfSmrg    }
36035c4bbdfSmrg
36135c4bbdfSmrg    return nearest;
36235c4bbdfSmrg}
36335c4bbdfSmrg
36435c4bbdfSmrg/**
36535c4bbdfSmrg * Clamp to the given barrier given the movement direction specified in dir.
36635c4bbdfSmrg *
36735c4bbdfSmrg * @param barrier The barrier to clamp to
36835c4bbdfSmrg * @param dir The movement direction
36935c4bbdfSmrg * @param[out] x The clamped x coordinate.
37035c4bbdfSmrg * @param[out] y The clamped x coordinate.
37135c4bbdfSmrg */
37235c4bbdfSmrgvoid
37335c4bbdfSmrgbarrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
37435c4bbdfSmrg                         int *y)
37535c4bbdfSmrg{
37635c4bbdfSmrg    if (barrier_is_vertical(barrier)) {
37735c4bbdfSmrg        if ((dir & BarrierNegativeX) & ~barrier->directions)
37835c4bbdfSmrg            *x = barrier->x1;
37935c4bbdfSmrg        if ((dir & BarrierPositiveX) & ~barrier->directions)
38035c4bbdfSmrg            *x = barrier->x1 - 1;
38135c4bbdfSmrg    }
38235c4bbdfSmrg    if (barrier_is_horizontal(barrier)) {
38335c4bbdfSmrg        if ((dir & BarrierNegativeY) & ~barrier->directions)
38435c4bbdfSmrg            *y = barrier->y1;
38535c4bbdfSmrg        if ((dir & BarrierPositiveY) & ~barrier->directions)
38635c4bbdfSmrg            *y = barrier->y1 - 1;
38735c4bbdfSmrg    }
38835c4bbdfSmrg}
38935c4bbdfSmrg
39035c4bbdfSmrgvoid
39135c4bbdfSmrginput_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
39235c4bbdfSmrg                       int current_x, int current_y,
39335c4bbdfSmrg                       int dest_x, int dest_y,
39435c4bbdfSmrg                       int *out_x, int *out_y,
39535c4bbdfSmrg                       int *nevents, InternalEvent* events)
39635c4bbdfSmrg{
39735c4bbdfSmrg    /* Clamped coordinates here refer to screen edge clamping. */
39835c4bbdfSmrg    BarrierScreenPtr cs = GetBarrierScreen(screen);
39935c4bbdfSmrg    int x = dest_x,
40035c4bbdfSmrg        y = dest_y;
40135c4bbdfSmrg    int dir;
40235c4bbdfSmrg    struct PointerBarrier *nearest = NULL;
40335c4bbdfSmrg    PointerBarrierClientPtr c;
40435c4bbdfSmrg    Time ms = GetTimeInMillis();
40535c4bbdfSmrg    BarrierEvent ev = {
40635c4bbdfSmrg        .header = ET_Internal,
40735c4bbdfSmrg        .type = 0,
40835c4bbdfSmrg        .length = sizeof (BarrierEvent),
40935c4bbdfSmrg        .time = ms,
41035c4bbdfSmrg        .deviceid = dev->id,
41135c4bbdfSmrg        .sourceid = dev->id,
41235c4bbdfSmrg        .dx = dest_x - current_x,
41335c4bbdfSmrg        .dy = dest_y - current_y,
41435c4bbdfSmrg        .root = screen->root->drawable.id,
41535c4bbdfSmrg    };
41635c4bbdfSmrg    InternalEvent *barrier_events = events;
41735c4bbdfSmrg    DeviceIntPtr master;
41835c4bbdfSmrg
41935c4bbdfSmrg    if (nevents)
42035c4bbdfSmrg        *nevents = 0;
42135c4bbdfSmrg
42235c4bbdfSmrg    if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev))
42335c4bbdfSmrg        goto out;
42435c4bbdfSmrg
42535c4bbdfSmrg    /**
42635c4bbdfSmrg     * This function is only called for slave devices, but pointer-barriers
42735c4bbdfSmrg     * are for master-devices only. Flip the device to the master here,
42835c4bbdfSmrg     * continue with that.
42935c4bbdfSmrg     */
43035c4bbdfSmrg    master = GetMaster(dev, MASTER_POINTER);
43135c4bbdfSmrg
43235c4bbdfSmrg    /* How this works:
43335c4bbdfSmrg     * Given the origin and the movement vector, get the nearest barrier
43435c4bbdfSmrg     * to the origin that is blocking the movement.
43535c4bbdfSmrg     * Clamp to that barrier.
43635c4bbdfSmrg     * Then, check from the clamped intersection to the original
43735c4bbdfSmrg     * destination, again finding the nearest barrier and clamping.
43835c4bbdfSmrg     */
43935c4bbdfSmrg    dir = barrier_get_direction(current_x, current_y, x, y);
44035c4bbdfSmrg
44135c4bbdfSmrg    while (dir != 0) {
44235c4bbdfSmrg        int new_sequence;
44335c4bbdfSmrg        struct PointerBarrierDevice *pbd;
44435c4bbdfSmrg
44535c4bbdfSmrg        c = barrier_find_nearest(cs, master, dir, current_x, current_y, x, y);
44635c4bbdfSmrg        if (!c)
44735c4bbdfSmrg            break;
44835c4bbdfSmrg
44935c4bbdfSmrg        nearest = &c->barrier;
45035c4bbdfSmrg
45135c4bbdfSmrg        pbd = GetBarrierDevice(c, master->id);
452d566a54bSmrg        if (!pbd)
453d566a54bSmrg            continue;
454d566a54bSmrg
45535c4bbdfSmrg        new_sequence = !pbd->hit;
45635c4bbdfSmrg
45735c4bbdfSmrg        pbd->seen = TRUE;
45835c4bbdfSmrg        pbd->hit = TRUE;
45935c4bbdfSmrg
46035c4bbdfSmrg        if (pbd->barrier_event_id == pbd->release_event_id)
46135c4bbdfSmrg            continue;
46235c4bbdfSmrg
46335c4bbdfSmrg        ev.type = ET_BarrierHit;
46435c4bbdfSmrg        barrier_clamp_to_barrier(nearest, dir, &x, &y);
46535c4bbdfSmrg
46635c4bbdfSmrg        if (barrier_is_vertical(nearest)) {
46735c4bbdfSmrg            dir &= ~(BarrierNegativeX | BarrierPositiveX);
46835c4bbdfSmrg            current_x = x;
46935c4bbdfSmrg        }
47035c4bbdfSmrg        else if (barrier_is_horizontal(nearest)) {
47135c4bbdfSmrg            dir &= ~(BarrierNegativeY | BarrierPositiveY);
47235c4bbdfSmrg            current_y = y;
47335c4bbdfSmrg        }
47435c4bbdfSmrg
47535c4bbdfSmrg        ev.flags = 0;
47635c4bbdfSmrg        ev.event_id = pbd->barrier_event_id;
47735c4bbdfSmrg        ev.barrierid = c->id;
47835c4bbdfSmrg
47935c4bbdfSmrg        ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp;
48035c4bbdfSmrg        ev.window = c->window;
48135c4bbdfSmrg        pbd->last_timestamp = ms;
48235c4bbdfSmrg
48335c4bbdfSmrg        /* root x/y is filled in later */
48435c4bbdfSmrg
48535c4bbdfSmrg        barrier_events->barrier_event = ev;
48635c4bbdfSmrg        barrier_events++;
48735c4bbdfSmrg        *nevents += 1;
48835c4bbdfSmrg    }
48935c4bbdfSmrg
49035c4bbdfSmrg    xorg_list_for_each_entry(c, &cs->barriers, entry) {
49135c4bbdfSmrg        struct PointerBarrierDevice *pbd;
49235c4bbdfSmrg        int flags = 0;
49335c4bbdfSmrg
49435c4bbdfSmrg        pbd = GetBarrierDevice(c, master->id);
495d566a54bSmrg        if (!pbd)
496d566a54bSmrg            continue;
497d566a54bSmrg
49835c4bbdfSmrg        pbd->seen = FALSE;
49935c4bbdfSmrg        if (!pbd->hit)
50035c4bbdfSmrg            continue;
50135c4bbdfSmrg
50235c4bbdfSmrg        if (barrier_inside_hit_box(&c->barrier, x, y))
50335c4bbdfSmrg            continue;
50435c4bbdfSmrg
50535c4bbdfSmrg        pbd->hit = FALSE;
50635c4bbdfSmrg
50735c4bbdfSmrg        ev.type = ET_BarrierLeave;
50835c4bbdfSmrg
50935c4bbdfSmrg        if (pbd->barrier_event_id == pbd->release_event_id)
51035c4bbdfSmrg            flags |= XIBarrierPointerReleased;
51135c4bbdfSmrg
51235c4bbdfSmrg        ev.flags = flags;
51335c4bbdfSmrg        ev.event_id = pbd->barrier_event_id;
51435c4bbdfSmrg        ev.barrierid = c->id;
51535c4bbdfSmrg
51635c4bbdfSmrg        ev.dt = ms - pbd->last_timestamp;
51735c4bbdfSmrg        ev.window = c->window;
51835c4bbdfSmrg        pbd->last_timestamp = ms;
51935c4bbdfSmrg
52035c4bbdfSmrg        /* root x/y is filled in later */
52135c4bbdfSmrg
52235c4bbdfSmrg        barrier_events->barrier_event = ev;
52335c4bbdfSmrg        barrier_events++;
52435c4bbdfSmrg        *nevents += 1;
52535c4bbdfSmrg
52635c4bbdfSmrg        /* If we've left the hit box, this is the
52735c4bbdfSmrg         * start of a new event ID. */
52835c4bbdfSmrg        pbd->barrier_event_id++;
52935c4bbdfSmrg    }
53035c4bbdfSmrg
53135c4bbdfSmrg out:
53235c4bbdfSmrg    *out_x = x;
53335c4bbdfSmrg    *out_y = y;
53435c4bbdfSmrg}
53535c4bbdfSmrg
53635c4bbdfSmrgstatic void
53735c4bbdfSmrgsort_min_max(INT16 *a, INT16 *b)
53835c4bbdfSmrg{
53935c4bbdfSmrg    INT16 A, B;
54035c4bbdfSmrg    if (*a < 0 || *b < 0)
54135c4bbdfSmrg        return;
54235c4bbdfSmrg    A = *a;
54335c4bbdfSmrg    B = *b;
54435c4bbdfSmrg    *a = min(A, B);
54535c4bbdfSmrg    *b = max(A, B);
54635c4bbdfSmrg}
54735c4bbdfSmrg
54835c4bbdfSmrgstatic int
54935c4bbdfSmrgCreatePointerBarrierClient(ClientPtr client,
55035c4bbdfSmrg                           xXFixesCreatePointerBarrierReq * stuff,
55135c4bbdfSmrg                           PointerBarrierClientPtr *client_out)
55235c4bbdfSmrg{
55335c4bbdfSmrg    WindowPtr pWin;
55435c4bbdfSmrg    ScreenPtr screen;
55535c4bbdfSmrg    BarrierScreenPtr cs;
55635c4bbdfSmrg    int err;
55735c4bbdfSmrg    int size;
55835c4bbdfSmrg    int i;
55935c4bbdfSmrg    struct PointerBarrierClient *ret;
56035c4bbdfSmrg    CARD16 *in_devices;
56135c4bbdfSmrg    DeviceIntPtr dev;
56235c4bbdfSmrg
56335c4bbdfSmrg    size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices;
56435c4bbdfSmrg    ret = malloc(size);
56535c4bbdfSmrg
56635c4bbdfSmrg    if (!ret) {
56735c4bbdfSmrg        return BadAlloc;
56835c4bbdfSmrg    }
56935c4bbdfSmrg
57035c4bbdfSmrg    xorg_list_init(&ret->per_device);
57135c4bbdfSmrg
57235c4bbdfSmrg    err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
57335c4bbdfSmrg    if (err != Success) {
57435c4bbdfSmrg        client->errorValue = stuff->window;
57535c4bbdfSmrg        goto error;
57635c4bbdfSmrg    }
57735c4bbdfSmrg
57835c4bbdfSmrg    screen = pWin->drawable.pScreen;
57935c4bbdfSmrg    cs = GetBarrierScreen(screen);
58035c4bbdfSmrg
58135c4bbdfSmrg    ret->screen = screen;
58235c4bbdfSmrg    ret->window = stuff->window;
58335c4bbdfSmrg    ret->num_devices = stuff->num_devices;
58435c4bbdfSmrg    if (ret->num_devices > 0)
58535c4bbdfSmrg        ret->device_ids = (int*)&ret[1];
58635c4bbdfSmrg    else
58735c4bbdfSmrg        ret->device_ids = NULL;
58835c4bbdfSmrg
58935c4bbdfSmrg    in_devices = (CARD16 *) &stuff[1];
59035c4bbdfSmrg    for (i = 0; i < stuff->num_devices; i++) {
59135c4bbdfSmrg        int device_id = in_devices[i];
59235c4bbdfSmrg        DeviceIntPtr device;
59335c4bbdfSmrg
59435c4bbdfSmrg        if ((err = dixLookupDevice (&device, device_id,
59535c4bbdfSmrg                                    client, DixReadAccess))) {
59635c4bbdfSmrg            client->errorValue = device_id;
59735c4bbdfSmrg            goto error;
59835c4bbdfSmrg        }
59935c4bbdfSmrg
60035c4bbdfSmrg        if (!IsMaster (device)) {
60135c4bbdfSmrg            client->errorValue = device_id;
60235c4bbdfSmrg            err = BadDevice;
60335c4bbdfSmrg            goto error;
60435c4bbdfSmrg        }
60535c4bbdfSmrg
60635c4bbdfSmrg        ret->device_ids[i] = device_id;
60735c4bbdfSmrg    }
60835c4bbdfSmrg
60935c4bbdfSmrg    /* Alloc one per master pointer, they're the ones that can be blocked */
61035c4bbdfSmrg    xorg_list_init(&ret->per_device);
61135c4bbdfSmrg    nt_list_for_each_entry(dev, inputInfo.devices, next) {
61235c4bbdfSmrg        struct PointerBarrierDevice *pbd;
61335c4bbdfSmrg
61435c4bbdfSmrg        if (dev->type != MASTER_POINTER)
61535c4bbdfSmrg            continue;
61635c4bbdfSmrg
61735c4bbdfSmrg        pbd = AllocBarrierDevice();
61835c4bbdfSmrg        if (!pbd) {
61935c4bbdfSmrg            err = BadAlloc;
62035c4bbdfSmrg            goto error;
62135c4bbdfSmrg        }
62235c4bbdfSmrg        pbd->deviceid = dev->id;
62335c4bbdfSmrg
624bf8e669cSmrg        input_lock();
62535c4bbdfSmrg        xorg_list_add(&pbd->entry, &ret->per_device);
626bf8e669cSmrg        input_unlock();
62735c4bbdfSmrg    }
62835c4bbdfSmrg
62935c4bbdfSmrg    ret->id = stuff->barrier;
63035c4bbdfSmrg    ret->barrier.x1 = stuff->x1;
63135c4bbdfSmrg    ret->barrier.x2 = stuff->x2;
63235c4bbdfSmrg    ret->barrier.y1 = stuff->y1;
63335c4bbdfSmrg    ret->barrier.y2 = stuff->y2;
63435c4bbdfSmrg    sort_min_max(&ret->barrier.x1, &ret->barrier.x2);
63535c4bbdfSmrg    sort_min_max(&ret->barrier.y1, &ret->barrier.y2);
63635c4bbdfSmrg    ret->barrier.directions = stuff->directions & 0x0f;
63735c4bbdfSmrg    if (barrier_is_horizontal(&ret->barrier))
63835c4bbdfSmrg        ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
63935c4bbdfSmrg    if (barrier_is_vertical(&ret->barrier))
64035c4bbdfSmrg        ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
641bf8e669cSmrg    input_lock();
64235c4bbdfSmrg    xorg_list_add(&ret->entry, &cs->barriers);
643bf8e669cSmrg    input_unlock();
64435c4bbdfSmrg
64535c4bbdfSmrg    *client_out = ret;
64635c4bbdfSmrg    return Success;
64735c4bbdfSmrg
64835c4bbdfSmrg error:
64935c4bbdfSmrg    *client_out = NULL;
65035c4bbdfSmrg    FreePointerBarrierClient(ret);
65135c4bbdfSmrg    return err;
65235c4bbdfSmrg}
65335c4bbdfSmrg
65435c4bbdfSmrgstatic int
65535c4bbdfSmrgBarrierFreeBarrier(void *data, XID id)
65635c4bbdfSmrg{
65735c4bbdfSmrg    struct PointerBarrierClient *c;
65835c4bbdfSmrg    Time ms = GetTimeInMillis();
65935c4bbdfSmrg    DeviceIntPtr dev = NULL;
66035c4bbdfSmrg    ScreenPtr screen;
66135c4bbdfSmrg
66235c4bbdfSmrg    c = container_of(data, struct PointerBarrierClient, barrier);
66335c4bbdfSmrg    screen = c->screen;
66435c4bbdfSmrg
66535c4bbdfSmrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
66635c4bbdfSmrg        struct PointerBarrierDevice *pbd;
66735c4bbdfSmrg        int root_x, root_y;
66835c4bbdfSmrg        BarrierEvent ev = {
66935c4bbdfSmrg            .header = ET_Internal,
67035c4bbdfSmrg            .type = ET_BarrierLeave,
67135c4bbdfSmrg            .length = sizeof (BarrierEvent),
67235c4bbdfSmrg            .time = ms,
67335c4bbdfSmrg            /* .deviceid */
67435c4bbdfSmrg            .sourceid = 0,
67535c4bbdfSmrg            .barrierid = c->id,
67635c4bbdfSmrg            .window = c->window,
67735c4bbdfSmrg            .root = screen->root->drawable.id,
67835c4bbdfSmrg            .dx = 0,
67935c4bbdfSmrg            .dy = 0,
68035c4bbdfSmrg            /* .root_x */
68135c4bbdfSmrg            /* .root_y */
68235c4bbdfSmrg            /* .dt */
68335c4bbdfSmrg            /* .event_id */
68435c4bbdfSmrg            .flags = XIBarrierPointerReleased,
68535c4bbdfSmrg        };
68635c4bbdfSmrg
68735c4bbdfSmrg
68835c4bbdfSmrg        if (dev->type != MASTER_POINTER)
68935c4bbdfSmrg            continue;
69035c4bbdfSmrg
69135c4bbdfSmrg        pbd = GetBarrierDevice(c, dev->id);
692d566a54bSmrg        if (!pbd)
693d566a54bSmrg            continue;
694d566a54bSmrg
69535c4bbdfSmrg        if (!pbd->hit)
69635c4bbdfSmrg            continue;
69735c4bbdfSmrg
69835c4bbdfSmrg        ev.deviceid = dev->id;
69935c4bbdfSmrg        ev.event_id = pbd->barrier_event_id;
70035c4bbdfSmrg        ev.dt = ms - pbd->last_timestamp;
70135c4bbdfSmrg
70235c4bbdfSmrg        GetSpritePosition(dev, &root_x, &root_y);
70335c4bbdfSmrg        ev.root_x = root_x;
70435c4bbdfSmrg        ev.root_y = root_y;
70535c4bbdfSmrg
70635c4bbdfSmrg        mieqEnqueue(dev, (InternalEvent *) &ev);
70735c4bbdfSmrg    }
70835c4bbdfSmrg
709bf8e669cSmrg    input_lock();
71035c4bbdfSmrg    xorg_list_del(&c->entry);
711bf8e669cSmrg    input_unlock();
71235c4bbdfSmrg
71335c4bbdfSmrg    FreePointerBarrierClient(c);
71435c4bbdfSmrg    return Success;
71535c4bbdfSmrg}
71635c4bbdfSmrg
71735c4bbdfSmrgstatic void add_master_func(void *res, XID id, void *devid)
71835c4bbdfSmrg{
71935c4bbdfSmrg    struct PointerBarrier *b;
72035c4bbdfSmrg    struct PointerBarrierClient *barrier;
72135c4bbdfSmrg    struct PointerBarrierDevice *pbd;
72235c4bbdfSmrg    int *deviceid = devid;
72335c4bbdfSmrg
72435c4bbdfSmrg    b = res;
72535c4bbdfSmrg    barrier = container_of(b, struct PointerBarrierClient, barrier);
72635c4bbdfSmrg
72735c4bbdfSmrg
72835c4bbdfSmrg    pbd = AllocBarrierDevice();
72935c4bbdfSmrg    pbd->deviceid = *deviceid;
73035c4bbdfSmrg
731bf8e669cSmrg    input_lock();
73235c4bbdfSmrg    xorg_list_add(&pbd->entry, &barrier->per_device);
733bf8e669cSmrg    input_unlock();
73435c4bbdfSmrg}
73535c4bbdfSmrg
73635c4bbdfSmrgstatic void remove_master_func(void *res, XID id, void *devid)
73735c4bbdfSmrg{
73835c4bbdfSmrg    struct PointerBarrierDevice *pbd;
73935c4bbdfSmrg    struct PointerBarrierClient *barrier;
74035c4bbdfSmrg    struct PointerBarrier *b;
74135c4bbdfSmrg    DeviceIntPtr dev;
74235c4bbdfSmrg    int *deviceid = devid;
74335c4bbdfSmrg    int rc;
74435c4bbdfSmrg    Time ms = GetTimeInMillis();
74535c4bbdfSmrg
74635c4bbdfSmrg    rc = dixLookupDevice(&dev, *deviceid, serverClient, DixSendAccess);
74735c4bbdfSmrg    if (rc != Success)
74835c4bbdfSmrg        return;
74935c4bbdfSmrg
75035c4bbdfSmrg    b = res;
75135c4bbdfSmrg    barrier = container_of(b, struct PointerBarrierClient, barrier);
75235c4bbdfSmrg
75335c4bbdfSmrg    pbd = GetBarrierDevice(barrier, *deviceid);
754d566a54bSmrg    if (!pbd)
755d566a54bSmrg        return;
75635c4bbdfSmrg
75735c4bbdfSmrg    if (pbd->hit) {
75835c4bbdfSmrg        BarrierEvent ev = {
75935c4bbdfSmrg            .header = ET_Internal,
76035c4bbdfSmrg            .type =ET_BarrierLeave,
76135c4bbdfSmrg            .length = sizeof (BarrierEvent),
76235c4bbdfSmrg            .time = ms,
76335c4bbdfSmrg            .deviceid = *deviceid,
76435c4bbdfSmrg            .sourceid = 0,
76535c4bbdfSmrg            .dx = 0,
76635c4bbdfSmrg            .dy = 0,
76735c4bbdfSmrg            .root = barrier->screen->root->drawable.id,
76835c4bbdfSmrg            .window = barrier->window,
76935c4bbdfSmrg            .dt = ms - pbd->last_timestamp,
77035c4bbdfSmrg            .flags = XIBarrierPointerReleased,
77135c4bbdfSmrg            .event_id = pbd->barrier_event_id,
77235c4bbdfSmrg            .barrierid = barrier->id,
77335c4bbdfSmrg        };
77435c4bbdfSmrg
77535c4bbdfSmrg        mieqEnqueue(dev, (InternalEvent *) &ev);
77635c4bbdfSmrg    }
77735c4bbdfSmrg
778bf8e669cSmrg    input_lock();
77935c4bbdfSmrg    xorg_list_del(&pbd->entry);
780bf8e669cSmrg    input_unlock();
78135c4bbdfSmrg    free(pbd);
78235c4bbdfSmrg}
78335c4bbdfSmrg
78435c4bbdfSmrgvoid XIBarrierNewMasterDevice(ClientPtr client, int deviceid)
78535c4bbdfSmrg{
78635c4bbdfSmrg    FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid);
78735c4bbdfSmrg}
78835c4bbdfSmrg
78935c4bbdfSmrgvoid XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid)
79035c4bbdfSmrg{
79135c4bbdfSmrg    FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid);
79235c4bbdfSmrg}
79335c4bbdfSmrg
79435c4bbdfSmrgint
79535c4bbdfSmrgXICreatePointerBarrier(ClientPtr client,
79635c4bbdfSmrg                       xXFixesCreatePointerBarrierReq * stuff)
79735c4bbdfSmrg{
79835c4bbdfSmrg    int err;
79935c4bbdfSmrg    struct PointerBarrierClient *barrier;
80035c4bbdfSmrg    struct PointerBarrier b;
80135c4bbdfSmrg
80235c4bbdfSmrg    b.x1 = stuff->x1;
80335c4bbdfSmrg    b.x2 = stuff->x2;
80435c4bbdfSmrg    b.y1 = stuff->y1;
80535c4bbdfSmrg    b.y2 = stuff->y2;
80635c4bbdfSmrg
80735c4bbdfSmrg    if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
80835c4bbdfSmrg        return BadValue;
80935c4bbdfSmrg
81035c4bbdfSmrg    /* no 0-sized barriers */
81135c4bbdfSmrg    if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
81235c4bbdfSmrg        return BadValue;
81335c4bbdfSmrg
81435c4bbdfSmrg    /* no infinite barriers on the wrong axis */
81535c4bbdfSmrg    if (barrier_is_horizontal(&b) && (b.y1 < 0 || b.y2 < 0))
81635c4bbdfSmrg        return BadValue;
81735c4bbdfSmrg
81835c4bbdfSmrg    if (barrier_is_vertical(&b) && (b.x1 < 0 || b.x2 < 0))
81935c4bbdfSmrg        return BadValue;
82035c4bbdfSmrg
82135c4bbdfSmrg    if ((err = CreatePointerBarrierClient(client, stuff, &barrier)))
82235c4bbdfSmrg        return err;
82335c4bbdfSmrg
82435c4bbdfSmrg    if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
82535c4bbdfSmrg        return BadAlloc;
82635c4bbdfSmrg
82735c4bbdfSmrg    return Success;
82835c4bbdfSmrg}
82935c4bbdfSmrg
83035c4bbdfSmrgint
83135c4bbdfSmrgXIDestroyPointerBarrier(ClientPtr client,
83235c4bbdfSmrg                        xXFixesDestroyPointerBarrierReq * stuff)
83335c4bbdfSmrg{
83435c4bbdfSmrg    int err;
83535c4bbdfSmrg    void *barrier;
83635c4bbdfSmrg
83735c4bbdfSmrg    err = dixLookupResourceByType((void **) &barrier, stuff->barrier,
83835c4bbdfSmrg                                  PointerBarrierType, client, DixDestroyAccess);
83935c4bbdfSmrg    if (err != Success) {
84035c4bbdfSmrg        client->errorValue = stuff->barrier;
84135c4bbdfSmrg        return err;
84235c4bbdfSmrg    }
84335c4bbdfSmrg
84435c4bbdfSmrg    if (CLIENT_ID(stuff->barrier) != client->index)
84535c4bbdfSmrg        return BadAccess;
84635c4bbdfSmrg
84735c4bbdfSmrg    FreeResource(stuff->barrier, RT_NONE);
84835c4bbdfSmrg    return Success;
84935c4bbdfSmrg}
85035c4bbdfSmrg
8517e31ba66Smrgint _X_COLD
85235c4bbdfSmrgSProcXIBarrierReleasePointer(ClientPtr client)
85335c4bbdfSmrg{
85435c4bbdfSmrg    xXIBarrierReleasePointerInfo *info;
85535c4bbdfSmrg    REQUEST(xXIBarrierReleasePointerReq);
85635c4bbdfSmrg    int i;
85735c4bbdfSmrg
85835c4bbdfSmrg    swaps(&stuff->length);
8596e78d31fSmrg    REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq);
8606e78d31fSmrg
86135c4bbdfSmrg    swapl(&stuff->num_barriers);
8626e78d31fSmrg    if (stuff->num_barriers > UINT32_MAX / sizeof(xXIBarrierReleasePointerInfo))
8636e78d31fSmrg        return BadLength;
8646e78d31fSmrg    REQUEST_FIXED_SIZE(xXIBarrierReleasePointerReq, stuff->num_barriers * sizeof(xXIBarrierReleasePointerInfo));
8656e78d31fSmrg
8666e78d31fSmrg    info = (xXIBarrierReleasePointerInfo*) &stuff[1];
86735c4bbdfSmrg    for (i = 0; i < stuff->num_barriers; i++, info++) {
86835c4bbdfSmrg        swaps(&info->deviceid);
86935c4bbdfSmrg        swapl(&info->barrier);
87035c4bbdfSmrg        swapl(&info->eventid);
87135c4bbdfSmrg    }
87235c4bbdfSmrg
87335c4bbdfSmrg    return (ProcXIBarrierReleasePointer(client));
87435c4bbdfSmrg}
87535c4bbdfSmrg
87635c4bbdfSmrgint
87735c4bbdfSmrgProcXIBarrierReleasePointer(ClientPtr client)
87835c4bbdfSmrg{
87935c4bbdfSmrg    int i;
88035c4bbdfSmrg    int err;
88135c4bbdfSmrg    struct PointerBarrierClient *barrier;
88235c4bbdfSmrg    struct PointerBarrier *b;
88335c4bbdfSmrg    xXIBarrierReleasePointerInfo *info;
88435c4bbdfSmrg
88535c4bbdfSmrg    REQUEST(xXIBarrierReleasePointerReq);
88635c4bbdfSmrg    REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq);
8876e78d31fSmrg    if (stuff->num_barriers > UINT32_MAX / sizeof(xXIBarrierReleasePointerInfo))
8886e78d31fSmrg        return BadLength;
8896e78d31fSmrg    REQUEST_FIXED_SIZE(xXIBarrierReleasePointerReq, stuff->num_barriers * sizeof(xXIBarrierReleasePointerInfo));
89035c4bbdfSmrg
89135c4bbdfSmrg    info = (xXIBarrierReleasePointerInfo*) &stuff[1];
89235c4bbdfSmrg    for (i = 0; i < stuff->num_barriers; i++, info++) {
89335c4bbdfSmrg        struct PointerBarrierDevice *pbd;
89435c4bbdfSmrg        DeviceIntPtr dev;
89535c4bbdfSmrg        CARD32 barrier_id, event_id;
89635c4bbdfSmrg        _X_UNUSED CARD32 device_id;
89735c4bbdfSmrg
89835c4bbdfSmrg        barrier_id = info->barrier;
89935c4bbdfSmrg        event_id = info->eventid;
90035c4bbdfSmrg
90135c4bbdfSmrg        err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess);
90235c4bbdfSmrg        if (err != Success) {
90335c4bbdfSmrg            client->errorValue = BadDevice;
90435c4bbdfSmrg            return err;
90535c4bbdfSmrg        }
90635c4bbdfSmrg
90735c4bbdfSmrg        err = dixLookupResourceByType((void **) &b, barrier_id,
90835c4bbdfSmrg                                      PointerBarrierType, client, DixReadAccess);
90935c4bbdfSmrg        if (err != Success) {
91035c4bbdfSmrg            client->errorValue = barrier_id;
91135c4bbdfSmrg            return err;
91235c4bbdfSmrg        }
91335c4bbdfSmrg
91435c4bbdfSmrg        if (CLIENT_ID(barrier_id) != client->index)
91535c4bbdfSmrg            return BadAccess;
91635c4bbdfSmrg
91735c4bbdfSmrg
91835c4bbdfSmrg        barrier = container_of(b, struct PointerBarrierClient, barrier);
91935c4bbdfSmrg
92035c4bbdfSmrg        pbd = GetBarrierDevice(barrier, dev->id);
921d566a54bSmrg        if (!pbd) {
922d566a54bSmrg            client->errorValue = dev->id;
923d566a54bSmrg            return BadDevice;
924d566a54bSmrg        }
92535c4bbdfSmrg
92635c4bbdfSmrg        if (pbd->barrier_event_id == event_id)
92735c4bbdfSmrg            pbd->release_event_id = event_id;
92835c4bbdfSmrg    }
92935c4bbdfSmrg
93035c4bbdfSmrg    return Success;
93135c4bbdfSmrg}
93235c4bbdfSmrg
93335c4bbdfSmrgBool
93435c4bbdfSmrgXIBarrierInit(void)
93535c4bbdfSmrg{
93635c4bbdfSmrg    int i;
93735c4bbdfSmrg
93835c4bbdfSmrg    if (!dixRegisterPrivateKey(&BarrierScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
93935c4bbdfSmrg        return FALSE;
94035c4bbdfSmrg
94135c4bbdfSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
94235c4bbdfSmrg        ScreenPtr pScreen = screenInfo.screens[i];
94335c4bbdfSmrg        BarrierScreenPtr cs;
94435c4bbdfSmrg
94535c4bbdfSmrg        cs = (BarrierScreenPtr) calloc(1, sizeof(BarrierScreenRec));
94635c4bbdfSmrg        if (!cs)
94735c4bbdfSmrg            return FALSE;
94835c4bbdfSmrg        xorg_list_init(&cs->barriers);
94935c4bbdfSmrg        SetBarrierScreen(pScreen, cs);
95035c4bbdfSmrg    }
95135c4bbdfSmrg
95235c4bbdfSmrg    PointerBarrierType = CreateNewResourceType(BarrierFreeBarrier,
95335c4bbdfSmrg                                               "XIPointerBarrier");
95435c4bbdfSmrg
95535c4bbdfSmrg    return PointerBarrierType;
95635c4bbdfSmrg}
95735c4bbdfSmrg
95835c4bbdfSmrgvoid
95935c4bbdfSmrgXIBarrierReset(void)
96035c4bbdfSmrg{
96135c4bbdfSmrg    int i;
96235c4bbdfSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
96335c4bbdfSmrg        ScreenPtr pScreen = screenInfo.screens[i];
96435c4bbdfSmrg        BarrierScreenPtr cs = GetBarrierScreen(pScreen);
96535c4bbdfSmrg        free(cs);
96635c4bbdfSmrg        SetBarrierScreen(pScreen, NULL);
96735c4bbdfSmrg    }
96835c4bbdfSmrg}
969