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/y1 → x2/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/y1 → x2/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/y1 → x2/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