xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

xibarriers.c (26790B)


      1 /*
      2  * Copyright 2012 Red Hat, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  *
     23  * Copyright © 2002 Keith Packard
     24  *
     25  * Permission to use, copy, modify, distribute, and sell this software and its
     26  * documentation for any purpose is hereby granted without fee, provided that
     27  * the above copyright notice appear in all copies and that both that
     28  * copyright notice and this permission notice appear in supporting
     29  * documentation, and that the name of Keith Packard not be used in
     30  * advertising or publicity pertaining to distribution of the software without
     31  * specific, written prior permission.  Keith Packard makes no
     32  * representations about the suitability of this software for any purpose.  It
     33  * is provided "as is" without express or implied warranty.
     34  *
     35  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     36  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     37  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     38  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     39  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     40  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     41  * PERFORMANCE OF THIS SOFTWARE.
     42  */
     43 
     44 #ifdef HAVE_DIX_CONFIG_H
     45 #include <dix-config.h>
     46 #endif
     47 
     48 #include "xibarriers.h"
     49 #include "scrnintstr.h"
     50 #include "cursorstr.h"
     51 #include "dixevents.h"
     52 #include "servermd.h"
     53 #include "mipointer.h"
     54 #include "inputstr.h"
     55 #include "windowstr.h"
     56 #include "xace.h"
     57 #include "list.h"
     58 #include "exglobals.h"
     59 #include "eventstr.h"
     60 #include "mi.h"
     61 
     62 RESTYPE PointerBarrierType;
     63 
     64 static DevPrivateKeyRec BarrierScreenPrivateKeyRec;
     65 
     66 #define BarrierScreenPrivateKey (&BarrierScreenPrivateKeyRec)
     67 
     68 typedef struct PointerBarrierClient *PointerBarrierClientPtr;
     69 
     70 struct PointerBarrierDevice {
     71     struct xorg_list entry;
     72     int deviceid;
     73     Time last_timestamp;
     74     int barrier_event_id;
     75     int release_event_id;
     76     Bool hit;
     77     Bool seen;
     78 };
     79 
     80 struct PointerBarrierClient {
     81     XID id;
     82     ScreenPtr screen;
     83     Window window;
     84     struct PointerBarrier barrier;
     85     struct xorg_list entry;
     86     /* num_devices/device_ids are devices the barrier applies to */
     87     int num_devices;
     88     int *device_ids; /* num_devices */
     89 
     90     /* per_device keeps track of devices actually blocked by barriers */
     91     struct xorg_list per_device;
     92 };
     93 
     94 typedef struct _BarrierScreen {
     95     struct xorg_list barriers;
     96 } BarrierScreenRec, *BarrierScreenPtr;
     97 
     98 #define GetBarrierScreen(s) ((BarrierScreenPtr)dixLookupPrivate(&(s)->devPrivates, BarrierScreenPrivateKey))
     99 #define GetBarrierScreenIfSet(s) GetBarrierScreen(s)
    100 #define SetBarrierScreen(s,p) dixSetPrivate(&(s)->devPrivates, BarrierScreenPrivateKey, p)
    101 
    102 static struct PointerBarrierDevice *AllocBarrierDevice(void)
    103 {
    104     struct PointerBarrierDevice *pbd = NULL;
    105 
    106     pbd = malloc(sizeof(struct PointerBarrierDevice));
    107     if (!pbd)
    108         return NULL;
    109 
    110     pbd->deviceid = -1; /* must be set by caller */
    111     pbd->barrier_event_id = 1;
    112     pbd->release_event_id = 0;
    113     pbd->hit = FALSE;
    114     pbd->seen = FALSE;
    115     xorg_list_init(&pbd->entry);
    116 
    117     return pbd;
    118 }
    119 
    120 static void FreePointerBarrierClient(struct PointerBarrierClient *c)
    121 {
    122     struct PointerBarrierDevice *pbd = NULL, *tmp = NULL;
    123 
    124     xorg_list_for_each_entry_safe(pbd, tmp, &c->per_device, entry) {
    125         free(pbd);
    126     }
    127     free(c);
    128 }
    129 
    130 static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid)
    131 {
    132     struct PointerBarrierDevice *pbd = NULL;
    133 
    134     xorg_list_for_each_entry(pbd, &c->per_device, entry) {
    135         if (pbd->deviceid == deviceid)
    136             break;
    137     }
    138 
    139     BUG_WARN(!pbd);
    140     return pbd;
    141 }
    142 
    143 static BOOL
    144 barrier_is_horizontal(const struct PointerBarrier *barrier)
    145 {
    146     return barrier->y1 == barrier->y2;
    147 }
    148 
    149 static BOOL
    150 barrier_is_vertical(const struct PointerBarrier *barrier)
    151 {
    152     return barrier->x1 == barrier->x2;
    153 }
    154 
    155 /**
    156  * @return The set of barrier movement directions the movement vector
    157  * x1/y1 → x2/y2 represents.
    158  */
    159 int
    160 barrier_get_direction(int x1, int y1, int x2, int y2)
    161 {
    162     int direction = 0;
    163 
    164     /* which way are we trying to go */
    165     if (x2 > x1)
    166         direction |= BarrierPositiveX;
    167     if (x2 < x1)
    168         direction |= BarrierNegativeX;
    169     if (y2 > y1)
    170         direction |= BarrierPositiveY;
    171     if (y2 < y1)
    172         direction |= BarrierNegativeY;
    173 
    174     return direction;
    175 }
    176 
    177 /**
    178  * Test if the barrier may block movement in the direction defined by
    179  * x1/y1 → x2/y2. This function only tests whether the directions could be
    180  * blocked, it does not test if the barrier actually blocks the movement.
    181  *
    182  * @return TRUE if the barrier blocks the direction of movement or FALSE
    183  * otherwise.
    184  */
    185 BOOL
    186 barrier_is_blocking_direction(const struct PointerBarrier * barrier,
    187                               int direction)
    188 {
    189     /* Barriers define which way is ok, not which way is blocking */
    190     return (barrier->directions & direction) != direction;
    191 }
    192 
    193 static BOOL
    194 inside_segment(int v, int v1, int v2)
    195 {
    196     if (v1 < 0 && v2 < 0) /* line */
    197         return TRUE;
    198     else if (v1 < 0)      /* ray */
    199         return v <= v2;
    200     else if (v2 < 0)      /* ray */
    201         return v >= v1;
    202     else                  /* line segment */
    203         return v >= v1 && v <= v2;
    204 }
    205 
    206 #define T(v, a, b) (((float)v) - (a)) / ((b) - (a))
    207 #define F(t, a, b) ((t) * ((a) - (b)) + (a))
    208 
    209 /**
    210  * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
    211  * barrier. A movement vector with the startpoint or endpoint adjacent to
    212  * the barrier itself counts as intersecting.
    213  *
    214  * @param x1 X start coordinate of movement vector
    215  * @param y1 Y start coordinate of movement vector
    216  * @param x2 X end coordinate of movement vector
    217  * @param y2 Y end coordinate of movement vector
    218  * @param[out] distance The distance between the start point and the
    219  * intersection with the barrier (if applicable).
    220  * @return TRUE if the barrier intersects with the given vector
    221  */
    222 BOOL
    223 barrier_is_blocking(const struct PointerBarrier * barrier,
    224                     int x1, int y1, int x2, int y2, double *distance)
    225 {
    226     if (barrier_is_vertical(barrier)) {
    227         float t, y;
    228         t = T(barrier->x1, x1, x2);
    229         if (t < 0 || t > 1)
    230             return FALSE;
    231 
    232         /* Edge case: moving away from barrier. */
    233         if (x2 > x1 && t == 0)
    234             return FALSE;
    235 
    236         y = F(t, y1, y2);
    237         if (!inside_segment(y, barrier->y1, barrier->y2))
    238             return FALSE;
    239 
    240         *distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2)));
    241         return TRUE;
    242     }
    243     else {
    244         float t, x;
    245         t = T(barrier->y1, y1, y2);
    246         if (t < 0 || t > 1)
    247             return FALSE;
    248 
    249         /* Edge case: moving away from barrier. */
    250         if (y2 > y1 && t == 0)
    251             return FALSE;
    252 
    253         x = F(t, x1, x2);
    254         if (!inside_segment(x, barrier->x1, barrier->x2))
    255             return FALSE;
    256 
    257         *distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2)));
    258         return TRUE;
    259     }
    260 }
    261 
    262 #define HIT_EDGE_EXTENTS 2
    263 static BOOL
    264 barrier_inside_hit_box(struct PointerBarrier *barrier, int x, int y)
    265 {
    266     int x1, x2, y1, y2;
    267     int dir;
    268 
    269     x1 = barrier->x1;
    270     x2 = barrier->x2;
    271     y1 = barrier->y1;
    272     y2 = barrier->y2;
    273     dir = ~(barrier->directions);
    274 
    275     if (barrier_is_vertical(barrier)) {
    276         if (dir & BarrierPositiveX)
    277             x1 -= HIT_EDGE_EXTENTS;
    278         if (dir & BarrierNegativeX)
    279             x2 += HIT_EDGE_EXTENTS;
    280     }
    281     if (barrier_is_horizontal(barrier)) {
    282         if (dir & BarrierPositiveY)
    283             y1 -= HIT_EDGE_EXTENTS;
    284         if (dir & BarrierNegativeY)
    285             y2 += HIT_EDGE_EXTENTS;
    286     }
    287 
    288     return x >= x1 && x <= x2 && y >= y1 && y <= y2;
    289 }
    290 
    291 static BOOL
    292 barrier_blocks_device(struct PointerBarrierClient *client,
    293                       DeviceIntPtr dev)
    294 {
    295     int i;
    296     int master_id;
    297 
    298     /* Clients with no devices are treated as
    299      * if they specified XIAllDevices. */
    300     if (client->num_devices == 0)
    301         return TRUE;
    302 
    303     master_id = GetMaster(dev, POINTER_OR_FLOAT)->id;
    304 
    305     for (i = 0; i < client->num_devices; i++) {
    306         int device_id = client->device_ids[i];
    307         if (device_id == XIAllDevices ||
    308             device_id == XIAllMasterDevices ||
    309             device_id == master_id)
    310             return TRUE;
    311     }
    312 
    313     return FALSE;
    314 }
    315 
    316 /**
    317  * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2.
    318  *
    319  * @param dir Only barriers blocking movement in direction dir are checked
    320  * @param x1 X start coordinate of movement vector
    321  * @param y1 Y start coordinate of movement vector
    322  * @param x2 X end coordinate of movement vector
    323  * @param y2 Y end coordinate of movement vector
    324  * @return The barrier nearest to the movement origin that blocks this movement.
    325  */
    326 static struct PointerBarrierClient *
    327 barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev,
    328                      int dir,
    329                      int x1, int y1, int x2, int y2)
    330 {
    331     struct PointerBarrierClient *c, *nearest = NULL;
    332     double min_distance = INT_MAX;      /* can't get higher than that in X anyway */
    333 
    334     xorg_list_for_each_entry(c, &cs->barriers, entry) {
    335         struct PointerBarrier *b = &c->barrier;
    336         struct PointerBarrierDevice *pbd;
    337         double distance;
    338 
    339         pbd = GetBarrierDevice(c, dev->id);
    340         if (pbd->seen)
    341             continue;
    342 
    343         if (!barrier_is_blocking_direction(b, dir))
    344             continue;
    345 
    346         if (!barrier_blocks_device(c, dev))
    347             continue;
    348 
    349         if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) {
    350             if (min_distance > distance) {
    351                 min_distance = distance;
    352                 nearest = c;
    353             }
    354         }
    355     }
    356 
    357     return nearest;
    358 }
    359 
    360 /**
    361  * Clamp to the given barrier given the movement direction specified in dir.
    362  *
    363  * @param barrier The barrier to clamp to
    364  * @param dir The movement direction
    365  * @param[out] x The clamped x coordinate.
    366  * @param[out] y The clamped x coordinate.
    367  */
    368 void
    369 barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
    370                          int *y)
    371 {
    372     if (barrier_is_vertical(barrier)) {
    373         if ((dir & BarrierNegativeX) & ~barrier->directions)
    374             *x = barrier->x1;
    375         if ((dir & BarrierPositiveX) & ~barrier->directions)
    376             *x = barrier->x1 - 1;
    377     }
    378     if (barrier_is_horizontal(barrier)) {
    379         if ((dir & BarrierNegativeY) & ~barrier->directions)
    380             *y = barrier->y1;
    381         if ((dir & BarrierPositiveY) & ~barrier->directions)
    382             *y = barrier->y1 - 1;
    383     }
    384 }
    385 
    386 void
    387 input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
    388                        int current_x, int current_y,
    389                        int dest_x, int dest_y,
    390                        int *out_x, int *out_y,
    391                        int *nevents, InternalEvent* events)
    392 {
    393     /* Clamped coordinates here refer to screen edge clamping. */
    394     BarrierScreenPtr cs = GetBarrierScreen(screen);
    395     int x = dest_x,
    396         y = dest_y;
    397     int dir;
    398     struct PointerBarrier *nearest = NULL;
    399     PointerBarrierClientPtr c;
    400     Time ms = GetTimeInMillis();
    401     BarrierEvent ev = {
    402         .header = ET_Internal,
    403         .type = 0,
    404         .length = sizeof (BarrierEvent),
    405         .time = ms,
    406         .deviceid = dev->id,
    407         .sourceid = dev->id,
    408         .dx = dest_x - current_x,
    409         .dy = dest_y - current_y,
    410         .root = screen->root->drawable.id,
    411     };
    412     InternalEvent *barrier_events = events;
    413     DeviceIntPtr master;
    414 
    415     if (nevents)
    416         *nevents = 0;
    417 
    418     if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev))
    419         goto out;
    420 
    421     /**
    422      * This function is only called for slave devices, but pointer-barriers
    423      * are for master-devices only. Flip the device to the master here,
    424      * continue with that.
    425      */
    426     master = GetMaster(dev, MASTER_POINTER);
    427 
    428     /* How this works:
    429      * Given the origin and the movement vector, get the nearest barrier
    430      * to the origin that is blocking the movement.
    431      * Clamp to that barrier.
    432      * Then, check from the clamped intersection to the original
    433      * destination, again finding the nearest barrier and clamping.
    434      */
    435     dir = barrier_get_direction(current_x, current_y, x, y);
    436 
    437     while (dir != 0) {
    438         int new_sequence;
    439         struct PointerBarrierDevice *pbd;
    440 
    441         c = barrier_find_nearest(cs, master, dir, current_x, current_y, x, y);
    442         if (!c)
    443             break;
    444 
    445         nearest = &c->barrier;
    446 
    447         pbd = GetBarrierDevice(c, master->id);
    448         new_sequence = !pbd->hit;
    449 
    450         pbd->seen = TRUE;
    451         pbd->hit = TRUE;
    452 
    453         if (pbd->barrier_event_id == pbd->release_event_id)
    454             continue;
    455 
    456         ev.type = ET_BarrierHit;
    457         barrier_clamp_to_barrier(nearest, dir, &x, &y);
    458 
    459         if (barrier_is_vertical(nearest)) {
    460             dir &= ~(BarrierNegativeX | BarrierPositiveX);
    461             current_x = x;
    462         }
    463         else if (barrier_is_horizontal(nearest)) {
    464             dir &= ~(BarrierNegativeY | BarrierPositiveY);
    465             current_y = y;
    466         }
    467 
    468         ev.flags = 0;
    469         ev.event_id = pbd->barrier_event_id;
    470         ev.barrierid = c->id;
    471 
    472         ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp;
    473         ev.window = c->window;
    474         pbd->last_timestamp = ms;
    475 
    476         /* root x/y is filled in later */
    477 
    478         barrier_events->barrier_event = ev;
    479         barrier_events++;
    480         *nevents += 1;
    481     }
    482 
    483     xorg_list_for_each_entry(c, &cs->barriers, entry) {
    484         struct PointerBarrierDevice *pbd;
    485         int flags = 0;
    486 
    487         pbd = GetBarrierDevice(c, master->id);
    488         pbd->seen = FALSE;
    489         if (!pbd->hit)
    490             continue;
    491 
    492         if (barrier_inside_hit_box(&c->barrier, x, y))
    493             continue;
    494 
    495         pbd->hit = FALSE;
    496 
    497         ev.type = ET_BarrierLeave;
    498 
    499         if (pbd->barrier_event_id == pbd->release_event_id)
    500             flags |= XIBarrierPointerReleased;
    501 
    502         ev.flags = flags;
    503         ev.event_id = pbd->barrier_event_id;
    504         ev.barrierid = c->id;
    505 
    506         ev.dt = ms - pbd->last_timestamp;
    507         ev.window = c->window;
    508         pbd->last_timestamp = ms;
    509 
    510         /* root x/y is filled in later */
    511 
    512         barrier_events->barrier_event = ev;
    513         barrier_events++;
    514         *nevents += 1;
    515 
    516         /* If we've left the hit box, this is the
    517          * start of a new event ID. */
    518         pbd->barrier_event_id++;
    519     }
    520 
    521  out:
    522     *out_x = x;
    523     *out_y = y;
    524 }
    525 
    526 static void
    527 sort_min_max(INT16 *a, INT16 *b)
    528 {
    529     INT16 A, B;
    530     if (*a < 0 || *b < 0)
    531         return;
    532     A = *a;
    533     B = *b;
    534     *a = min(A, B);
    535     *b = max(A, B);
    536 }
    537 
    538 static int
    539 CreatePointerBarrierClient(ClientPtr client,
    540                            xXFixesCreatePointerBarrierReq * stuff,
    541                            PointerBarrierClientPtr *client_out)
    542 {
    543     WindowPtr pWin;
    544     ScreenPtr screen;
    545     BarrierScreenPtr cs;
    546     int err;
    547     int size;
    548     int i;
    549     struct PointerBarrierClient *ret;
    550     CARD16 *in_devices;
    551     DeviceIntPtr dev;
    552 
    553     size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices;
    554     ret = malloc(size);
    555 
    556     if (!ret) {
    557         return BadAlloc;
    558     }
    559 
    560     xorg_list_init(&ret->per_device);
    561 
    562     err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
    563     if (err != Success) {
    564         client->errorValue = stuff->window;
    565         goto error;
    566     }
    567 
    568     screen = pWin->drawable.pScreen;
    569     cs = GetBarrierScreen(screen);
    570 
    571     ret->screen = screen;
    572     ret->window = stuff->window;
    573     ret->num_devices = stuff->num_devices;
    574     if (ret->num_devices > 0)
    575         ret->device_ids = (int*)&ret[1];
    576     else
    577         ret->device_ids = NULL;
    578 
    579     in_devices = (CARD16 *) &stuff[1];
    580     for (i = 0; i < stuff->num_devices; i++) {
    581         int device_id = in_devices[i];
    582         DeviceIntPtr device;
    583 
    584         if ((err = dixLookupDevice (&device, device_id,
    585                                     client, DixReadAccess))) {
    586             client->errorValue = device_id;
    587             goto error;
    588         }
    589 
    590         if (!IsMaster (device)) {
    591             client->errorValue = device_id;
    592             err = BadDevice;
    593             goto error;
    594         }
    595 
    596         ret->device_ids[i] = device_id;
    597     }
    598 
    599     /* Alloc one per master pointer, they're the ones that can be blocked */
    600     xorg_list_init(&ret->per_device);
    601     nt_list_for_each_entry(dev, inputInfo.devices, next) {
    602         struct PointerBarrierDevice *pbd;
    603 
    604         if (dev->type != MASTER_POINTER)
    605             continue;
    606 
    607         pbd = AllocBarrierDevice();
    608         if (!pbd) {
    609             err = BadAlloc;
    610             goto error;
    611         }
    612         pbd->deviceid = dev->id;
    613 
    614         input_lock();
    615         xorg_list_add(&pbd->entry, &ret->per_device);
    616         input_unlock();
    617     }
    618 
    619     ret->id = stuff->barrier;
    620     ret->barrier.x1 = stuff->x1;
    621     ret->barrier.x2 = stuff->x2;
    622     ret->barrier.y1 = stuff->y1;
    623     ret->barrier.y2 = stuff->y2;
    624     sort_min_max(&ret->barrier.x1, &ret->barrier.x2);
    625     sort_min_max(&ret->barrier.y1, &ret->barrier.y2);
    626     ret->barrier.directions = stuff->directions & 0x0f;
    627     if (barrier_is_horizontal(&ret->barrier))
    628         ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
    629     if (barrier_is_vertical(&ret->barrier))
    630         ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
    631     input_lock();
    632     xorg_list_add(&ret->entry, &cs->barriers);
    633     input_unlock();
    634 
    635     *client_out = ret;
    636     return Success;
    637 
    638  error:
    639     *client_out = NULL;
    640     FreePointerBarrierClient(ret);
    641     return err;
    642 }
    643 
    644 static int
    645 BarrierFreeBarrier(void *data, XID id)
    646 {
    647     struct PointerBarrierClient *c;
    648     Time ms = GetTimeInMillis();
    649     DeviceIntPtr dev = NULL;
    650     ScreenPtr screen;
    651 
    652     c = container_of(data, struct PointerBarrierClient, barrier);
    653     screen = c->screen;
    654 
    655     for (dev = inputInfo.devices; dev; dev = dev->next) {
    656         struct PointerBarrierDevice *pbd;
    657         int root_x, root_y;
    658         BarrierEvent ev = {
    659             .header = ET_Internal,
    660             .type = ET_BarrierLeave,
    661             .length = sizeof (BarrierEvent),
    662             .time = ms,
    663             /* .deviceid */
    664             .sourceid = 0,
    665             .barrierid = c->id,
    666             .window = c->window,
    667             .root = screen->root->drawable.id,
    668             .dx = 0,
    669             .dy = 0,
    670             /* .root_x */
    671             /* .root_y */
    672             /* .dt */
    673             /* .event_id */
    674             .flags = XIBarrierPointerReleased,
    675         };
    676 
    677 
    678         if (dev->type != MASTER_POINTER)
    679             continue;
    680 
    681         pbd = GetBarrierDevice(c, dev->id);
    682         if (!pbd->hit)
    683             continue;
    684 
    685         ev.deviceid = dev->id;
    686         ev.event_id = pbd->barrier_event_id;
    687         ev.dt = ms - pbd->last_timestamp;
    688 
    689         GetSpritePosition(dev, &root_x, &root_y);
    690         ev.root_x = root_x;
    691         ev.root_y = root_y;
    692 
    693         mieqEnqueue(dev, (InternalEvent *) &ev);
    694     }
    695 
    696     input_lock();
    697     xorg_list_del(&c->entry);
    698     input_unlock();
    699 
    700     FreePointerBarrierClient(c);
    701     return Success;
    702 }
    703 
    704 static void add_master_func(void *res, XID id, void *devid)
    705 {
    706     struct PointerBarrier *b;
    707     struct PointerBarrierClient *barrier;
    708     struct PointerBarrierDevice *pbd;
    709     int *deviceid = devid;
    710 
    711     b = res;
    712     barrier = container_of(b, struct PointerBarrierClient, barrier);
    713 
    714 
    715     pbd = AllocBarrierDevice();
    716     pbd->deviceid = *deviceid;
    717 
    718     input_lock();
    719     xorg_list_add(&pbd->entry, &barrier->per_device);
    720     input_unlock();
    721 }
    722 
    723 static void remove_master_func(void *res, XID id, void *devid)
    724 {
    725     struct PointerBarrierDevice *pbd;
    726     struct PointerBarrierClient *barrier;
    727     struct PointerBarrier *b;
    728     DeviceIntPtr dev;
    729     int *deviceid = devid;
    730     int rc;
    731     Time ms = GetTimeInMillis();
    732 
    733     rc = dixLookupDevice(&dev, *deviceid, serverClient, DixSendAccess);
    734     if (rc != Success)
    735         return;
    736 
    737     b = res;
    738     barrier = container_of(b, struct PointerBarrierClient, barrier);
    739 
    740     pbd = GetBarrierDevice(barrier, *deviceid);
    741 
    742     if (pbd->hit) {
    743         BarrierEvent ev = {
    744             .header = ET_Internal,
    745             .type =ET_BarrierLeave,
    746             .length = sizeof (BarrierEvent),
    747             .time = ms,
    748             .deviceid = *deviceid,
    749             .sourceid = 0,
    750             .dx = 0,
    751             .dy = 0,
    752             .root = barrier->screen->root->drawable.id,
    753             .window = barrier->window,
    754             .dt = ms - pbd->last_timestamp,
    755             .flags = XIBarrierPointerReleased,
    756             .event_id = pbd->barrier_event_id,
    757             .barrierid = barrier->id,
    758         };
    759 
    760         mieqEnqueue(dev, (InternalEvent *) &ev);
    761     }
    762 
    763     input_lock();
    764     xorg_list_del(&pbd->entry);
    765     input_unlock();
    766     free(pbd);
    767 }
    768 
    769 void XIBarrierNewMasterDevice(ClientPtr client, int deviceid)
    770 {
    771     FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid);
    772 }
    773 
    774 void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid)
    775 {
    776     FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid);
    777 }
    778 
    779 int
    780 XICreatePointerBarrier(ClientPtr client,
    781                        xXFixesCreatePointerBarrierReq * stuff)
    782 {
    783     int err;
    784     struct PointerBarrierClient *barrier;
    785     struct PointerBarrier b;
    786 
    787     b.x1 = stuff->x1;
    788     b.x2 = stuff->x2;
    789     b.y1 = stuff->y1;
    790     b.y2 = stuff->y2;
    791 
    792     if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
    793         return BadValue;
    794 
    795     /* no 0-sized barriers */
    796     if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
    797         return BadValue;
    798 
    799     /* no infinite barriers on the wrong axis */
    800     if (barrier_is_horizontal(&b) && (b.y1 < 0 || b.y2 < 0))
    801         return BadValue;
    802 
    803     if (barrier_is_vertical(&b) && (b.x1 < 0 || b.x2 < 0))
    804         return BadValue;
    805 
    806     if ((err = CreatePointerBarrierClient(client, stuff, &barrier)))
    807         return err;
    808 
    809     if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
    810         return BadAlloc;
    811 
    812     return Success;
    813 }
    814 
    815 int
    816 XIDestroyPointerBarrier(ClientPtr client,
    817                         xXFixesDestroyPointerBarrierReq * stuff)
    818 {
    819     int err;
    820     void *barrier;
    821 
    822     err = dixLookupResourceByType((void **) &barrier, stuff->barrier,
    823                                   PointerBarrierType, client, DixDestroyAccess);
    824     if (err != Success) {
    825         client->errorValue = stuff->barrier;
    826         return err;
    827     }
    828 
    829     if (CLIENT_ID(stuff->barrier) != client->index)
    830         return BadAccess;
    831 
    832     FreeResource(stuff->barrier, RT_NONE);
    833     return Success;
    834 }
    835 
    836 int _X_COLD
    837 SProcXIBarrierReleasePointer(ClientPtr client)
    838 {
    839     xXIBarrierReleasePointerInfo *info;
    840     REQUEST(xXIBarrierReleasePointerReq);
    841     int i;
    842 
    843     swaps(&stuff->length);
    844     REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq);
    845 
    846     swapl(&stuff->num_barriers);
    847     if (stuff->num_barriers > UINT32_MAX / sizeof(xXIBarrierReleasePointerInfo))
    848         return BadLength;
    849     REQUEST_FIXED_SIZE(xXIBarrierReleasePointerReq, stuff->num_barriers * sizeof(xXIBarrierReleasePointerInfo));
    850 
    851     info = (xXIBarrierReleasePointerInfo*) &stuff[1];
    852     for (i = 0; i < stuff->num_barriers; i++, info++) {
    853         swaps(&info->deviceid);
    854         swapl(&info->barrier);
    855         swapl(&info->eventid);
    856     }
    857 
    858     return (ProcXIBarrierReleasePointer(client));
    859 }
    860 
    861 int
    862 ProcXIBarrierReleasePointer(ClientPtr client)
    863 {
    864     int i;
    865     int err;
    866     struct PointerBarrierClient *barrier;
    867     struct PointerBarrier *b;
    868     xXIBarrierReleasePointerInfo *info;
    869 
    870     REQUEST(xXIBarrierReleasePointerReq);
    871     REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq);
    872     if (stuff->num_barriers > UINT32_MAX / sizeof(xXIBarrierReleasePointerInfo))
    873         return BadLength;
    874     REQUEST_FIXED_SIZE(xXIBarrierReleasePointerReq, stuff->num_barriers * sizeof(xXIBarrierReleasePointerInfo));
    875 
    876     info = (xXIBarrierReleasePointerInfo*) &stuff[1];
    877     for (i = 0; i < stuff->num_barriers; i++, info++) {
    878         struct PointerBarrierDevice *pbd;
    879         DeviceIntPtr dev;
    880         CARD32 barrier_id, event_id;
    881         _X_UNUSED CARD32 device_id;
    882 
    883         barrier_id = info->barrier;
    884         event_id = info->eventid;
    885 
    886         err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess);
    887         if (err != Success) {
    888             client->errorValue = BadDevice;
    889             return err;
    890         }
    891 
    892         err = dixLookupResourceByType((void **) &b, barrier_id,
    893                                       PointerBarrierType, client, DixReadAccess);
    894         if (err != Success) {
    895             client->errorValue = barrier_id;
    896             return err;
    897         }
    898 
    899         if (CLIENT_ID(barrier_id) != client->index)
    900             return BadAccess;
    901 
    902 
    903         barrier = container_of(b, struct PointerBarrierClient, barrier);
    904 
    905         pbd = GetBarrierDevice(barrier, dev->id);
    906 
    907         if (pbd->barrier_event_id == event_id)
    908             pbd->release_event_id = event_id;
    909     }
    910 
    911     return Success;
    912 }
    913 
    914 Bool
    915 XIBarrierInit(void)
    916 {
    917     int i;
    918 
    919     if (!dixRegisterPrivateKey(&BarrierScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
    920         return FALSE;
    921 
    922     for (i = 0; i < screenInfo.numScreens; i++) {
    923         ScreenPtr pScreen = screenInfo.screens[i];
    924         BarrierScreenPtr cs;
    925 
    926         cs = (BarrierScreenPtr) calloc(1, sizeof(BarrierScreenRec));
    927         if (!cs)
    928             return FALSE;
    929         xorg_list_init(&cs->barriers);
    930         SetBarrierScreen(pScreen, cs);
    931     }
    932 
    933     PointerBarrierType = CreateNewResourceType(BarrierFreeBarrier,
    934                                                "XIPointerBarrier");
    935 
    936     return PointerBarrierType;
    937 }
    938 
    939 void
    940 XIBarrierReset(void)
    941 {
    942     int i;
    943     for (i = 0; i < screenInfo.numScreens; i++) {
    944         ScreenPtr pScreen = screenInfo.screens[i];
    945         BarrierScreenPtr cs = GetBarrierScreen(pScreen);
    946         free(cs);
    947         SetBarrierScreen(pScreen, NULL);
    948     }
    949 }