xibarriers.c revision 35c4bbdf
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{ 13235c4bbdfSmrg struct PointerBarrierDevice *pbd = NULL; 13335c4bbdfSmrg 13435c4bbdfSmrg xorg_list_for_each_entry(pbd, &c->per_device, entry) { 13535c4bbdfSmrg if (pbd->deviceid == deviceid) 13635c4bbdfSmrg break; 13735c4bbdfSmrg } 13835c4bbdfSmrg 13935c4bbdfSmrg BUG_WARN(!pbd); 14035c4bbdfSmrg return pbd; 14135c4bbdfSmrg} 14235c4bbdfSmrg 14335c4bbdfSmrgstatic BOOL 14435c4bbdfSmrgbarrier_is_horizontal(const struct PointerBarrier *barrier) 14535c4bbdfSmrg{ 14635c4bbdfSmrg return barrier->y1 == barrier->y2; 14735c4bbdfSmrg} 14835c4bbdfSmrg 14935c4bbdfSmrgstatic BOOL 15035c4bbdfSmrgbarrier_is_vertical(const struct PointerBarrier *barrier) 15135c4bbdfSmrg{ 15235c4bbdfSmrg return barrier->x1 == barrier->x2; 15335c4bbdfSmrg} 15435c4bbdfSmrg 15535c4bbdfSmrg/** 15635c4bbdfSmrg * @return The set of barrier movement directions the movement vector 15735c4bbdfSmrg * x1/y1 → x2/y2 represents. 15835c4bbdfSmrg */ 15935c4bbdfSmrgint 16035c4bbdfSmrgbarrier_get_direction(int x1, int y1, int x2, int y2) 16135c4bbdfSmrg{ 16235c4bbdfSmrg int direction = 0; 16335c4bbdfSmrg 16435c4bbdfSmrg /* which way are we trying to go */ 16535c4bbdfSmrg if (x2 > x1) 16635c4bbdfSmrg direction |= BarrierPositiveX; 16735c4bbdfSmrg if (x2 < x1) 16835c4bbdfSmrg direction |= BarrierNegativeX; 16935c4bbdfSmrg if (y2 > y1) 17035c4bbdfSmrg direction |= BarrierPositiveY; 17135c4bbdfSmrg if (y2 < y1) 17235c4bbdfSmrg direction |= BarrierNegativeY; 17335c4bbdfSmrg 17435c4bbdfSmrg return direction; 17535c4bbdfSmrg} 17635c4bbdfSmrg 17735c4bbdfSmrg/** 17835c4bbdfSmrg * Test if the barrier may block movement in the direction defined by 17935c4bbdfSmrg * x1/y1 → x2/y2. This function only tests whether the directions could be 18035c4bbdfSmrg * blocked, it does not test if the barrier actually blocks the movement. 18135c4bbdfSmrg * 18235c4bbdfSmrg * @return TRUE if the barrier blocks the direction of movement or FALSE 18335c4bbdfSmrg * otherwise. 18435c4bbdfSmrg */ 18535c4bbdfSmrgBOOL 18635c4bbdfSmrgbarrier_is_blocking_direction(const struct PointerBarrier * barrier, 18735c4bbdfSmrg int direction) 18835c4bbdfSmrg{ 18935c4bbdfSmrg /* Barriers define which way is ok, not which way is blocking */ 19035c4bbdfSmrg return (barrier->directions & direction) != direction; 19135c4bbdfSmrg} 19235c4bbdfSmrg 19335c4bbdfSmrgstatic BOOL 19435c4bbdfSmrginside_segment(int v, int v1, int v2) 19535c4bbdfSmrg{ 19635c4bbdfSmrg if (v1 < 0 && v2 < 0) /* line */ 19735c4bbdfSmrg return TRUE; 19835c4bbdfSmrg else if (v1 < 0) /* ray */ 19935c4bbdfSmrg return v <= v2; 20035c4bbdfSmrg else if (v2 < 0) /* ray */ 20135c4bbdfSmrg return v >= v1; 20235c4bbdfSmrg else /* line segment */ 20335c4bbdfSmrg return v >= v1 && v <= v2; 20435c4bbdfSmrg} 20535c4bbdfSmrg 20635c4bbdfSmrg#define T(v, a, b) (((float)v) - (a)) / ((b) - (a)) 20735c4bbdfSmrg#define F(t, a, b) ((t) * ((a) - (b)) + (a)) 20835c4bbdfSmrg 20935c4bbdfSmrg/** 21035c4bbdfSmrg * Test if the movement vector x1/y1 → x2/y2 is intersecting with the 21135c4bbdfSmrg * barrier. A movement vector with the startpoint or endpoint adjacent to 21235c4bbdfSmrg * the barrier itself counts as intersecting. 21335c4bbdfSmrg * 21435c4bbdfSmrg * @param x1 X start coordinate of movement vector 21535c4bbdfSmrg * @param y1 Y start coordinate of movement vector 21635c4bbdfSmrg * @param x2 X end coordinate of movement vector 21735c4bbdfSmrg * @param y2 Y end coordinate of movement vector 21835c4bbdfSmrg * @param[out] distance The distance between the start point and the 21935c4bbdfSmrg * intersection with the barrier (if applicable). 22035c4bbdfSmrg * @return TRUE if the barrier intersects with the given vector 22135c4bbdfSmrg */ 22235c4bbdfSmrgBOOL 22335c4bbdfSmrgbarrier_is_blocking(const struct PointerBarrier * barrier, 22435c4bbdfSmrg int x1, int y1, int x2, int y2, double *distance) 22535c4bbdfSmrg{ 22635c4bbdfSmrg if (barrier_is_vertical(barrier)) { 22735c4bbdfSmrg float t, y; 22835c4bbdfSmrg t = T(barrier->x1, x1, x2); 22935c4bbdfSmrg if (t < 0 || t > 1) 23035c4bbdfSmrg return FALSE; 23135c4bbdfSmrg 23235c4bbdfSmrg /* Edge case: moving away from barrier. */ 23335c4bbdfSmrg if (x2 > x1 && t == 0) 23435c4bbdfSmrg return FALSE; 23535c4bbdfSmrg 23635c4bbdfSmrg y = F(t, y1, y2); 23735c4bbdfSmrg if (!inside_segment(y, barrier->y1, barrier->y2)) 23835c4bbdfSmrg return FALSE; 23935c4bbdfSmrg 24035c4bbdfSmrg *distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2))); 24135c4bbdfSmrg return TRUE; 24235c4bbdfSmrg } 24335c4bbdfSmrg else { 24435c4bbdfSmrg float t, x; 24535c4bbdfSmrg t = T(barrier->y1, y1, y2); 24635c4bbdfSmrg if (t < 0 || t > 1) 24735c4bbdfSmrg return FALSE; 24835c4bbdfSmrg 24935c4bbdfSmrg /* Edge case: moving away from barrier. */ 25035c4bbdfSmrg if (y2 > y1 && t == 0) 25135c4bbdfSmrg return FALSE; 25235c4bbdfSmrg 25335c4bbdfSmrg x = F(t, x1, x2); 25435c4bbdfSmrg if (!inside_segment(x, barrier->x1, barrier->x2)) 25535c4bbdfSmrg return FALSE; 25635c4bbdfSmrg 25735c4bbdfSmrg *distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2))); 25835c4bbdfSmrg return TRUE; 25935c4bbdfSmrg } 26035c4bbdfSmrg} 26135c4bbdfSmrg 26235c4bbdfSmrg#define HIT_EDGE_EXTENTS 2 26335c4bbdfSmrgstatic BOOL 26435c4bbdfSmrgbarrier_inside_hit_box(struct PointerBarrier *barrier, int x, int y) 26535c4bbdfSmrg{ 26635c4bbdfSmrg int x1, x2, y1, y2; 26735c4bbdfSmrg int dir; 26835c4bbdfSmrg 26935c4bbdfSmrg x1 = barrier->x1; 27035c4bbdfSmrg x2 = barrier->x2; 27135c4bbdfSmrg y1 = barrier->y1; 27235c4bbdfSmrg y2 = barrier->y2; 27335c4bbdfSmrg dir = ~(barrier->directions); 27435c4bbdfSmrg 27535c4bbdfSmrg if (barrier_is_vertical(barrier)) { 27635c4bbdfSmrg if (dir & BarrierPositiveX) 27735c4bbdfSmrg x1 -= HIT_EDGE_EXTENTS; 27835c4bbdfSmrg if (dir & BarrierNegativeX) 27935c4bbdfSmrg x2 += HIT_EDGE_EXTENTS; 28035c4bbdfSmrg } 28135c4bbdfSmrg if (barrier_is_horizontal(barrier)) { 28235c4bbdfSmrg if (dir & BarrierPositiveY) 28335c4bbdfSmrg y1 -= HIT_EDGE_EXTENTS; 28435c4bbdfSmrg if (dir & BarrierNegativeY) 28535c4bbdfSmrg y2 += HIT_EDGE_EXTENTS; 28635c4bbdfSmrg } 28735c4bbdfSmrg 28835c4bbdfSmrg return x >= x1 && x <= x2 && y >= y1 && y <= y2; 28935c4bbdfSmrg} 29035c4bbdfSmrg 29135c4bbdfSmrgstatic BOOL 29235c4bbdfSmrgbarrier_blocks_device(struct PointerBarrierClient *client, 29335c4bbdfSmrg DeviceIntPtr dev) 29435c4bbdfSmrg{ 29535c4bbdfSmrg int i; 29635c4bbdfSmrg int master_id; 29735c4bbdfSmrg 29835c4bbdfSmrg /* Clients with no devices are treated as 29935c4bbdfSmrg * if they specified XIAllDevices. */ 30035c4bbdfSmrg if (client->num_devices == 0) 30135c4bbdfSmrg return TRUE; 30235c4bbdfSmrg 30335c4bbdfSmrg master_id = GetMaster(dev, POINTER_OR_FLOAT)->id; 30435c4bbdfSmrg 30535c4bbdfSmrg for (i = 0; i < client->num_devices; i++) { 30635c4bbdfSmrg int device_id = client->device_ids[i]; 30735c4bbdfSmrg if (device_id == XIAllDevices || 30835c4bbdfSmrg device_id == XIAllMasterDevices || 30935c4bbdfSmrg device_id == master_id) 31035c4bbdfSmrg return TRUE; 31135c4bbdfSmrg } 31235c4bbdfSmrg 31335c4bbdfSmrg return FALSE; 31435c4bbdfSmrg} 31535c4bbdfSmrg 31635c4bbdfSmrg/** 31735c4bbdfSmrg * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2. 31835c4bbdfSmrg * 31935c4bbdfSmrg * @param dir Only barriers blocking movement in direction dir are checked 32035c4bbdfSmrg * @param x1 X start coordinate of movement vector 32135c4bbdfSmrg * @param y1 Y start coordinate of movement vector 32235c4bbdfSmrg * @param x2 X end coordinate of movement vector 32335c4bbdfSmrg * @param y2 Y end coordinate of movement vector 32435c4bbdfSmrg * @return The barrier nearest to the movement origin that blocks this movement. 32535c4bbdfSmrg */ 32635c4bbdfSmrgstatic struct PointerBarrierClient * 32735c4bbdfSmrgbarrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev, 32835c4bbdfSmrg int dir, 32935c4bbdfSmrg int x1, int y1, int x2, int y2) 33035c4bbdfSmrg{ 33135c4bbdfSmrg struct PointerBarrierClient *c, *nearest = NULL; 33235c4bbdfSmrg double min_distance = INT_MAX; /* can't get higher than that in X anyway */ 33335c4bbdfSmrg 33435c4bbdfSmrg xorg_list_for_each_entry(c, &cs->barriers, entry) { 33535c4bbdfSmrg struct PointerBarrier *b = &c->barrier; 33635c4bbdfSmrg struct PointerBarrierDevice *pbd; 33735c4bbdfSmrg double distance; 33835c4bbdfSmrg 33935c4bbdfSmrg pbd = GetBarrierDevice(c, dev->id); 34035c4bbdfSmrg if (pbd->seen) 34135c4bbdfSmrg continue; 34235c4bbdfSmrg 34335c4bbdfSmrg if (!barrier_is_blocking_direction(b, dir)) 34435c4bbdfSmrg continue; 34535c4bbdfSmrg 34635c4bbdfSmrg if (!barrier_blocks_device(c, dev)) 34735c4bbdfSmrg continue; 34835c4bbdfSmrg 34935c4bbdfSmrg if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) { 35035c4bbdfSmrg if (min_distance > distance) { 35135c4bbdfSmrg min_distance = distance; 35235c4bbdfSmrg nearest = c; 35335c4bbdfSmrg } 35435c4bbdfSmrg } 35535c4bbdfSmrg } 35635c4bbdfSmrg 35735c4bbdfSmrg return nearest; 35835c4bbdfSmrg} 35935c4bbdfSmrg 36035c4bbdfSmrg/** 36135c4bbdfSmrg * Clamp to the given barrier given the movement direction specified in dir. 36235c4bbdfSmrg * 36335c4bbdfSmrg * @param barrier The barrier to clamp to 36435c4bbdfSmrg * @param dir The movement direction 36535c4bbdfSmrg * @param[out] x The clamped x coordinate. 36635c4bbdfSmrg * @param[out] y The clamped x coordinate. 36735c4bbdfSmrg */ 36835c4bbdfSmrgvoid 36935c4bbdfSmrgbarrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, 37035c4bbdfSmrg int *y) 37135c4bbdfSmrg{ 37235c4bbdfSmrg if (barrier_is_vertical(barrier)) { 37335c4bbdfSmrg if ((dir & BarrierNegativeX) & ~barrier->directions) 37435c4bbdfSmrg *x = barrier->x1; 37535c4bbdfSmrg if ((dir & BarrierPositiveX) & ~barrier->directions) 37635c4bbdfSmrg *x = barrier->x1 - 1; 37735c4bbdfSmrg } 37835c4bbdfSmrg if (barrier_is_horizontal(barrier)) { 37935c4bbdfSmrg if ((dir & BarrierNegativeY) & ~barrier->directions) 38035c4bbdfSmrg *y = barrier->y1; 38135c4bbdfSmrg if ((dir & BarrierPositiveY) & ~barrier->directions) 38235c4bbdfSmrg *y = barrier->y1 - 1; 38335c4bbdfSmrg } 38435c4bbdfSmrg} 38535c4bbdfSmrg 38635c4bbdfSmrgvoid 38735c4bbdfSmrginput_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen, 38835c4bbdfSmrg int current_x, int current_y, 38935c4bbdfSmrg int dest_x, int dest_y, 39035c4bbdfSmrg int *out_x, int *out_y, 39135c4bbdfSmrg int *nevents, InternalEvent* events) 39235c4bbdfSmrg{ 39335c4bbdfSmrg /* Clamped coordinates here refer to screen edge clamping. */ 39435c4bbdfSmrg BarrierScreenPtr cs = GetBarrierScreen(screen); 39535c4bbdfSmrg int x = dest_x, 39635c4bbdfSmrg y = dest_y; 39735c4bbdfSmrg int dir; 39835c4bbdfSmrg struct PointerBarrier *nearest = NULL; 39935c4bbdfSmrg PointerBarrierClientPtr c; 40035c4bbdfSmrg Time ms = GetTimeInMillis(); 40135c4bbdfSmrg BarrierEvent ev = { 40235c4bbdfSmrg .header = ET_Internal, 40335c4bbdfSmrg .type = 0, 40435c4bbdfSmrg .length = sizeof (BarrierEvent), 40535c4bbdfSmrg .time = ms, 40635c4bbdfSmrg .deviceid = dev->id, 40735c4bbdfSmrg .sourceid = dev->id, 40835c4bbdfSmrg .dx = dest_x - current_x, 40935c4bbdfSmrg .dy = dest_y - current_y, 41035c4bbdfSmrg .root = screen->root->drawable.id, 41135c4bbdfSmrg }; 41235c4bbdfSmrg InternalEvent *barrier_events = events; 41335c4bbdfSmrg DeviceIntPtr master; 41435c4bbdfSmrg 41535c4bbdfSmrg if (nevents) 41635c4bbdfSmrg *nevents = 0; 41735c4bbdfSmrg 41835c4bbdfSmrg if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev)) 41935c4bbdfSmrg goto out; 42035c4bbdfSmrg 42135c4bbdfSmrg /** 42235c4bbdfSmrg * This function is only called for slave devices, but pointer-barriers 42335c4bbdfSmrg * are for master-devices only. Flip the device to the master here, 42435c4bbdfSmrg * continue with that. 42535c4bbdfSmrg */ 42635c4bbdfSmrg master = GetMaster(dev, MASTER_POINTER); 42735c4bbdfSmrg 42835c4bbdfSmrg /* How this works: 42935c4bbdfSmrg * Given the origin and the movement vector, get the nearest barrier 43035c4bbdfSmrg * to the origin that is blocking the movement. 43135c4bbdfSmrg * Clamp to that barrier. 43235c4bbdfSmrg * Then, check from the clamped intersection to the original 43335c4bbdfSmrg * destination, again finding the nearest barrier and clamping. 43435c4bbdfSmrg */ 43535c4bbdfSmrg dir = barrier_get_direction(current_x, current_y, x, y); 43635c4bbdfSmrg 43735c4bbdfSmrg while (dir != 0) { 43835c4bbdfSmrg int new_sequence; 43935c4bbdfSmrg struct PointerBarrierDevice *pbd; 44035c4bbdfSmrg 44135c4bbdfSmrg c = barrier_find_nearest(cs, master, dir, current_x, current_y, x, y); 44235c4bbdfSmrg if (!c) 44335c4bbdfSmrg break; 44435c4bbdfSmrg 44535c4bbdfSmrg nearest = &c->barrier; 44635c4bbdfSmrg 44735c4bbdfSmrg pbd = GetBarrierDevice(c, master->id); 44835c4bbdfSmrg new_sequence = !pbd->hit; 44935c4bbdfSmrg 45035c4bbdfSmrg pbd->seen = TRUE; 45135c4bbdfSmrg pbd->hit = TRUE; 45235c4bbdfSmrg 45335c4bbdfSmrg if (pbd->barrier_event_id == pbd->release_event_id) 45435c4bbdfSmrg continue; 45535c4bbdfSmrg 45635c4bbdfSmrg ev.type = ET_BarrierHit; 45735c4bbdfSmrg barrier_clamp_to_barrier(nearest, dir, &x, &y); 45835c4bbdfSmrg 45935c4bbdfSmrg if (barrier_is_vertical(nearest)) { 46035c4bbdfSmrg dir &= ~(BarrierNegativeX | BarrierPositiveX); 46135c4bbdfSmrg current_x = x; 46235c4bbdfSmrg } 46335c4bbdfSmrg else if (barrier_is_horizontal(nearest)) { 46435c4bbdfSmrg dir &= ~(BarrierNegativeY | BarrierPositiveY); 46535c4bbdfSmrg current_y = y; 46635c4bbdfSmrg } 46735c4bbdfSmrg 46835c4bbdfSmrg ev.flags = 0; 46935c4bbdfSmrg ev.event_id = pbd->barrier_event_id; 47035c4bbdfSmrg ev.barrierid = c->id; 47135c4bbdfSmrg 47235c4bbdfSmrg ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp; 47335c4bbdfSmrg ev.window = c->window; 47435c4bbdfSmrg pbd->last_timestamp = ms; 47535c4bbdfSmrg 47635c4bbdfSmrg /* root x/y is filled in later */ 47735c4bbdfSmrg 47835c4bbdfSmrg barrier_events->barrier_event = ev; 47935c4bbdfSmrg barrier_events++; 48035c4bbdfSmrg *nevents += 1; 48135c4bbdfSmrg } 48235c4bbdfSmrg 48335c4bbdfSmrg xorg_list_for_each_entry(c, &cs->barriers, entry) { 48435c4bbdfSmrg struct PointerBarrierDevice *pbd; 48535c4bbdfSmrg int flags = 0; 48635c4bbdfSmrg 48735c4bbdfSmrg pbd = GetBarrierDevice(c, master->id); 48835c4bbdfSmrg pbd->seen = FALSE; 48935c4bbdfSmrg if (!pbd->hit) 49035c4bbdfSmrg continue; 49135c4bbdfSmrg 49235c4bbdfSmrg if (barrier_inside_hit_box(&c->barrier, x, y)) 49335c4bbdfSmrg continue; 49435c4bbdfSmrg 49535c4bbdfSmrg pbd->hit = FALSE; 49635c4bbdfSmrg 49735c4bbdfSmrg ev.type = ET_BarrierLeave; 49835c4bbdfSmrg 49935c4bbdfSmrg if (pbd->barrier_event_id == pbd->release_event_id) 50035c4bbdfSmrg flags |= XIBarrierPointerReleased; 50135c4bbdfSmrg 50235c4bbdfSmrg ev.flags = flags; 50335c4bbdfSmrg ev.event_id = pbd->barrier_event_id; 50435c4bbdfSmrg ev.barrierid = c->id; 50535c4bbdfSmrg 50635c4bbdfSmrg ev.dt = ms - pbd->last_timestamp; 50735c4bbdfSmrg ev.window = c->window; 50835c4bbdfSmrg pbd->last_timestamp = ms; 50935c4bbdfSmrg 51035c4bbdfSmrg /* root x/y is filled in later */ 51135c4bbdfSmrg 51235c4bbdfSmrg barrier_events->barrier_event = ev; 51335c4bbdfSmrg barrier_events++; 51435c4bbdfSmrg *nevents += 1; 51535c4bbdfSmrg 51635c4bbdfSmrg /* If we've left the hit box, this is the 51735c4bbdfSmrg * start of a new event ID. */ 51835c4bbdfSmrg pbd->barrier_event_id++; 51935c4bbdfSmrg } 52035c4bbdfSmrg 52135c4bbdfSmrg out: 52235c4bbdfSmrg *out_x = x; 52335c4bbdfSmrg *out_y = y; 52435c4bbdfSmrg} 52535c4bbdfSmrg 52635c4bbdfSmrgstatic void 52735c4bbdfSmrgsort_min_max(INT16 *a, INT16 *b) 52835c4bbdfSmrg{ 52935c4bbdfSmrg INT16 A, B; 53035c4bbdfSmrg if (*a < 0 || *b < 0) 53135c4bbdfSmrg return; 53235c4bbdfSmrg A = *a; 53335c4bbdfSmrg B = *b; 53435c4bbdfSmrg *a = min(A, B); 53535c4bbdfSmrg *b = max(A, B); 53635c4bbdfSmrg} 53735c4bbdfSmrg 53835c4bbdfSmrgstatic int 53935c4bbdfSmrgCreatePointerBarrierClient(ClientPtr client, 54035c4bbdfSmrg xXFixesCreatePointerBarrierReq * stuff, 54135c4bbdfSmrg PointerBarrierClientPtr *client_out) 54235c4bbdfSmrg{ 54335c4bbdfSmrg WindowPtr pWin; 54435c4bbdfSmrg ScreenPtr screen; 54535c4bbdfSmrg BarrierScreenPtr cs; 54635c4bbdfSmrg int err; 54735c4bbdfSmrg int size; 54835c4bbdfSmrg int i; 54935c4bbdfSmrg struct PointerBarrierClient *ret; 55035c4bbdfSmrg CARD16 *in_devices; 55135c4bbdfSmrg DeviceIntPtr dev; 55235c4bbdfSmrg 55335c4bbdfSmrg size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices; 55435c4bbdfSmrg ret = malloc(size); 55535c4bbdfSmrg 55635c4bbdfSmrg if (!ret) { 55735c4bbdfSmrg return BadAlloc; 55835c4bbdfSmrg } 55935c4bbdfSmrg 56035c4bbdfSmrg xorg_list_init(&ret->per_device); 56135c4bbdfSmrg 56235c4bbdfSmrg err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); 56335c4bbdfSmrg if (err != Success) { 56435c4bbdfSmrg client->errorValue = stuff->window; 56535c4bbdfSmrg goto error; 56635c4bbdfSmrg } 56735c4bbdfSmrg 56835c4bbdfSmrg screen = pWin->drawable.pScreen; 56935c4bbdfSmrg cs = GetBarrierScreen(screen); 57035c4bbdfSmrg 57135c4bbdfSmrg ret->screen = screen; 57235c4bbdfSmrg ret->window = stuff->window; 57335c4bbdfSmrg ret->num_devices = stuff->num_devices; 57435c4bbdfSmrg if (ret->num_devices > 0) 57535c4bbdfSmrg ret->device_ids = (int*)&ret[1]; 57635c4bbdfSmrg else 57735c4bbdfSmrg ret->device_ids = NULL; 57835c4bbdfSmrg 57935c4bbdfSmrg in_devices = (CARD16 *) &stuff[1]; 58035c4bbdfSmrg for (i = 0; i < stuff->num_devices; i++) { 58135c4bbdfSmrg int device_id = in_devices[i]; 58235c4bbdfSmrg DeviceIntPtr device; 58335c4bbdfSmrg 58435c4bbdfSmrg if ((err = dixLookupDevice (&device, device_id, 58535c4bbdfSmrg client, DixReadAccess))) { 58635c4bbdfSmrg client->errorValue = device_id; 58735c4bbdfSmrg goto error; 58835c4bbdfSmrg } 58935c4bbdfSmrg 59035c4bbdfSmrg if (!IsMaster (device)) { 59135c4bbdfSmrg client->errorValue = device_id; 59235c4bbdfSmrg err = BadDevice; 59335c4bbdfSmrg goto error; 59435c4bbdfSmrg } 59535c4bbdfSmrg 59635c4bbdfSmrg ret->device_ids[i] = device_id; 59735c4bbdfSmrg } 59835c4bbdfSmrg 59935c4bbdfSmrg /* Alloc one per master pointer, they're the ones that can be blocked */ 60035c4bbdfSmrg xorg_list_init(&ret->per_device); 60135c4bbdfSmrg nt_list_for_each_entry(dev, inputInfo.devices, next) { 60235c4bbdfSmrg struct PointerBarrierDevice *pbd; 60335c4bbdfSmrg 60435c4bbdfSmrg if (dev->type != MASTER_POINTER) 60535c4bbdfSmrg continue; 60635c4bbdfSmrg 60735c4bbdfSmrg pbd = AllocBarrierDevice(); 60835c4bbdfSmrg if (!pbd) { 60935c4bbdfSmrg err = BadAlloc; 61035c4bbdfSmrg goto error; 61135c4bbdfSmrg } 61235c4bbdfSmrg pbd->deviceid = dev->id; 61335c4bbdfSmrg 61435c4bbdfSmrg xorg_list_add(&pbd->entry, &ret->per_device); 61535c4bbdfSmrg } 61635c4bbdfSmrg 61735c4bbdfSmrg ret->id = stuff->barrier; 61835c4bbdfSmrg ret->barrier.x1 = stuff->x1; 61935c4bbdfSmrg ret->barrier.x2 = stuff->x2; 62035c4bbdfSmrg ret->barrier.y1 = stuff->y1; 62135c4bbdfSmrg ret->barrier.y2 = stuff->y2; 62235c4bbdfSmrg sort_min_max(&ret->barrier.x1, &ret->barrier.x2); 62335c4bbdfSmrg sort_min_max(&ret->barrier.y1, &ret->barrier.y2); 62435c4bbdfSmrg ret->barrier.directions = stuff->directions & 0x0f; 62535c4bbdfSmrg if (barrier_is_horizontal(&ret->barrier)) 62635c4bbdfSmrg ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX); 62735c4bbdfSmrg if (barrier_is_vertical(&ret->barrier)) 62835c4bbdfSmrg ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY); 62935c4bbdfSmrg xorg_list_add(&ret->entry, &cs->barriers); 63035c4bbdfSmrg 63135c4bbdfSmrg *client_out = ret; 63235c4bbdfSmrg return Success; 63335c4bbdfSmrg 63435c4bbdfSmrg error: 63535c4bbdfSmrg *client_out = NULL; 63635c4bbdfSmrg FreePointerBarrierClient(ret); 63735c4bbdfSmrg return err; 63835c4bbdfSmrg} 63935c4bbdfSmrg 64035c4bbdfSmrgstatic int 64135c4bbdfSmrgBarrierFreeBarrier(void *data, XID id) 64235c4bbdfSmrg{ 64335c4bbdfSmrg struct PointerBarrierClient *c; 64435c4bbdfSmrg Time ms = GetTimeInMillis(); 64535c4bbdfSmrg DeviceIntPtr dev = NULL; 64635c4bbdfSmrg ScreenPtr screen; 64735c4bbdfSmrg 64835c4bbdfSmrg c = container_of(data, struct PointerBarrierClient, barrier); 64935c4bbdfSmrg screen = c->screen; 65035c4bbdfSmrg 65135c4bbdfSmrg for (dev = inputInfo.devices; dev; dev = dev->next) { 65235c4bbdfSmrg struct PointerBarrierDevice *pbd; 65335c4bbdfSmrg int root_x, root_y; 65435c4bbdfSmrg BarrierEvent ev = { 65535c4bbdfSmrg .header = ET_Internal, 65635c4bbdfSmrg .type = ET_BarrierLeave, 65735c4bbdfSmrg .length = sizeof (BarrierEvent), 65835c4bbdfSmrg .time = ms, 65935c4bbdfSmrg /* .deviceid */ 66035c4bbdfSmrg .sourceid = 0, 66135c4bbdfSmrg .barrierid = c->id, 66235c4bbdfSmrg .window = c->window, 66335c4bbdfSmrg .root = screen->root->drawable.id, 66435c4bbdfSmrg .dx = 0, 66535c4bbdfSmrg .dy = 0, 66635c4bbdfSmrg /* .root_x */ 66735c4bbdfSmrg /* .root_y */ 66835c4bbdfSmrg /* .dt */ 66935c4bbdfSmrg /* .event_id */ 67035c4bbdfSmrg .flags = XIBarrierPointerReleased, 67135c4bbdfSmrg }; 67235c4bbdfSmrg 67335c4bbdfSmrg 67435c4bbdfSmrg if (dev->type != MASTER_POINTER) 67535c4bbdfSmrg continue; 67635c4bbdfSmrg 67735c4bbdfSmrg pbd = GetBarrierDevice(c, dev->id); 67835c4bbdfSmrg if (!pbd->hit) 67935c4bbdfSmrg continue; 68035c4bbdfSmrg 68135c4bbdfSmrg ev.deviceid = dev->id; 68235c4bbdfSmrg ev.event_id = pbd->barrier_event_id; 68335c4bbdfSmrg ev.dt = ms - pbd->last_timestamp; 68435c4bbdfSmrg 68535c4bbdfSmrg GetSpritePosition(dev, &root_x, &root_y); 68635c4bbdfSmrg ev.root_x = root_x; 68735c4bbdfSmrg ev.root_y = root_y; 68835c4bbdfSmrg 68935c4bbdfSmrg mieqEnqueue(dev, (InternalEvent *) &ev); 69035c4bbdfSmrg } 69135c4bbdfSmrg 69235c4bbdfSmrg xorg_list_del(&c->entry); 69335c4bbdfSmrg 69435c4bbdfSmrg FreePointerBarrierClient(c); 69535c4bbdfSmrg return Success; 69635c4bbdfSmrg} 69735c4bbdfSmrg 69835c4bbdfSmrgstatic void add_master_func(void *res, XID id, void *devid) 69935c4bbdfSmrg{ 70035c4bbdfSmrg struct PointerBarrier *b; 70135c4bbdfSmrg struct PointerBarrierClient *barrier; 70235c4bbdfSmrg struct PointerBarrierDevice *pbd; 70335c4bbdfSmrg int *deviceid = devid; 70435c4bbdfSmrg 70535c4bbdfSmrg b = res; 70635c4bbdfSmrg barrier = container_of(b, struct PointerBarrierClient, barrier); 70735c4bbdfSmrg 70835c4bbdfSmrg 70935c4bbdfSmrg pbd = AllocBarrierDevice(); 71035c4bbdfSmrg pbd->deviceid = *deviceid; 71135c4bbdfSmrg 71235c4bbdfSmrg xorg_list_add(&pbd->entry, &barrier->per_device); 71335c4bbdfSmrg} 71435c4bbdfSmrg 71535c4bbdfSmrgstatic void remove_master_func(void *res, XID id, void *devid) 71635c4bbdfSmrg{ 71735c4bbdfSmrg struct PointerBarrierDevice *pbd; 71835c4bbdfSmrg struct PointerBarrierClient *barrier; 71935c4bbdfSmrg struct PointerBarrier *b; 72035c4bbdfSmrg DeviceIntPtr dev; 72135c4bbdfSmrg int *deviceid = devid; 72235c4bbdfSmrg int rc; 72335c4bbdfSmrg Time ms = GetTimeInMillis(); 72435c4bbdfSmrg 72535c4bbdfSmrg rc = dixLookupDevice(&dev, *deviceid, serverClient, DixSendAccess); 72635c4bbdfSmrg if (rc != Success) 72735c4bbdfSmrg return; 72835c4bbdfSmrg 72935c4bbdfSmrg b = res; 73035c4bbdfSmrg barrier = container_of(b, struct PointerBarrierClient, barrier); 73135c4bbdfSmrg 73235c4bbdfSmrg pbd = GetBarrierDevice(barrier, *deviceid); 73335c4bbdfSmrg 73435c4bbdfSmrg if (pbd->hit) { 73535c4bbdfSmrg BarrierEvent ev = { 73635c4bbdfSmrg .header = ET_Internal, 73735c4bbdfSmrg .type =ET_BarrierLeave, 73835c4bbdfSmrg .length = sizeof (BarrierEvent), 73935c4bbdfSmrg .time = ms, 74035c4bbdfSmrg .deviceid = *deviceid, 74135c4bbdfSmrg .sourceid = 0, 74235c4bbdfSmrg .dx = 0, 74335c4bbdfSmrg .dy = 0, 74435c4bbdfSmrg .root = barrier->screen->root->drawable.id, 74535c4bbdfSmrg .window = barrier->window, 74635c4bbdfSmrg .dt = ms - pbd->last_timestamp, 74735c4bbdfSmrg .flags = XIBarrierPointerReleased, 74835c4bbdfSmrg .event_id = pbd->barrier_event_id, 74935c4bbdfSmrg .barrierid = barrier->id, 75035c4bbdfSmrg }; 75135c4bbdfSmrg 75235c4bbdfSmrg mieqEnqueue(dev, (InternalEvent *) &ev); 75335c4bbdfSmrg } 75435c4bbdfSmrg 75535c4bbdfSmrg xorg_list_del(&pbd->entry); 75635c4bbdfSmrg free(pbd); 75735c4bbdfSmrg} 75835c4bbdfSmrg 75935c4bbdfSmrgvoid XIBarrierNewMasterDevice(ClientPtr client, int deviceid) 76035c4bbdfSmrg{ 76135c4bbdfSmrg FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid); 76235c4bbdfSmrg} 76335c4bbdfSmrg 76435c4bbdfSmrgvoid XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid) 76535c4bbdfSmrg{ 76635c4bbdfSmrg FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid); 76735c4bbdfSmrg} 76835c4bbdfSmrg 76935c4bbdfSmrgint 77035c4bbdfSmrgXICreatePointerBarrier(ClientPtr client, 77135c4bbdfSmrg xXFixesCreatePointerBarrierReq * stuff) 77235c4bbdfSmrg{ 77335c4bbdfSmrg int err; 77435c4bbdfSmrg struct PointerBarrierClient *barrier; 77535c4bbdfSmrg struct PointerBarrier b; 77635c4bbdfSmrg 77735c4bbdfSmrg b.x1 = stuff->x1; 77835c4bbdfSmrg b.x2 = stuff->x2; 77935c4bbdfSmrg b.y1 = stuff->y1; 78035c4bbdfSmrg b.y2 = stuff->y2; 78135c4bbdfSmrg 78235c4bbdfSmrg if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b)) 78335c4bbdfSmrg return BadValue; 78435c4bbdfSmrg 78535c4bbdfSmrg /* no 0-sized barriers */ 78635c4bbdfSmrg if (barrier_is_horizontal(&b) && barrier_is_vertical(&b)) 78735c4bbdfSmrg return BadValue; 78835c4bbdfSmrg 78935c4bbdfSmrg /* no infinite barriers on the wrong axis */ 79035c4bbdfSmrg if (barrier_is_horizontal(&b) && (b.y1 < 0 || b.y2 < 0)) 79135c4bbdfSmrg return BadValue; 79235c4bbdfSmrg 79335c4bbdfSmrg if (barrier_is_vertical(&b) && (b.x1 < 0 || b.x2 < 0)) 79435c4bbdfSmrg return BadValue; 79535c4bbdfSmrg 79635c4bbdfSmrg if ((err = CreatePointerBarrierClient(client, stuff, &barrier))) 79735c4bbdfSmrg return err; 79835c4bbdfSmrg 79935c4bbdfSmrg if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier)) 80035c4bbdfSmrg return BadAlloc; 80135c4bbdfSmrg 80235c4bbdfSmrg return Success; 80335c4bbdfSmrg} 80435c4bbdfSmrg 80535c4bbdfSmrgint 80635c4bbdfSmrgXIDestroyPointerBarrier(ClientPtr client, 80735c4bbdfSmrg xXFixesDestroyPointerBarrierReq * stuff) 80835c4bbdfSmrg{ 80935c4bbdfSmrg int err; 81035c4bbdfSmrg void *barrier; 81135c4bbdfSmrg 81235c4bbdfSmrg err = dixLookupResourceByType((void **) &barrier, stuff->barrier, 81335c4bbdfSmrg PointerBarrierType, client, DixDestroyAccess); 81435c4bbdfSmrg if (err != Success) { 81535c4bbdfSmrg client->errorValue = stuff->barrier; 81635c4bbdfSmrg return err; 81735c4bbdfSmrg } 81835c4bbdfSmrg 81935c4bbdfSmrg if (CLIENT_ID(stuff->barrier) != client->index) 82035c4bbdfSmrg return BadAccess; 82135c4bbdfSmrg 82235c4bbdfSmrg FreeResource(stuff->barrier, RT_NONE); 82335c4bbdfSmrg return Success; 82435c4bbdfSmrg} 82535c4bbdfSmrg 82635c4bbdfSmrgint 82735c4bbdfSmrgSProcXIBarrierReleasePointer(ClientPtr client) 82835c4bbdfSmrg{ 82935c4bbdfSmrg xXIBarrierReleasePointerInfo *info; 83035c4bbdfSmrg REQUEST(xXIBarrierReleasePointerReq); 83135c4bbdfSmrg int i; 83235c4bbdfSmrg 83335c4bbdfSmrg info = (xXIBarrierReleasePointerInfo*) &stuff[1]; 83435c4bbdfSmrg 83535c4bbdfSmrg swaps(&stuff->length); 83635c4bbdfSmrg swapl(&stuff->num_barriers); 83735c4bbdfSmrg for (i = 0; i < stuff->num_barriers; i++, info++) { 83835c4bbdfSmrg swaps(&info->deviceid); 83935c4bbdfSmrg swapl(&info->barrier); 84035c4bbdfSmrg swapl(&info->eventid); 84135c4bbdfSmrg } 84235c4bbdfSmrg 84335c4bbdfSmrg return (ProcXIBarrierReleasePointer(client)); 84435c4bbdfSmrg} 84535c4bbdfSmrg 84635c4bbdfSmrgint 84735c4bbdfSmrgProcXIBarrierReleasePointer(ClientPtr client) 84835c4bbdfSmrg{ 84935c4bbdfSmrg int i; 85035c4bbdfSmrg int err; 85135c4bbdfSmrg struct PointerBarrierClient *barrier; 85235c4bbdfSmrg struct PointerBarrier *b; 85335c4bbdfSmrg xXIBarrierReleasePointerInfo *info; 85435c4bbdfSmrg 85535c4bbdfSmrg REQUEST(xXIBarrierReleasePointerReq); 85635c4bbdfSmrg REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq); 85735c4bbdfSmrg 85835c4bbdfSmrg info = (xXIBarrierReleasePointerInfo*) &stuff[1]; 85935c4bbdfSmrg for (i = 0; i < stuff->num_barriers; i++, info++) { 86035c4bbdfSmrg struct PointerBarrierDevice *pbd; 86135c4bbdfSmrg DeviceIntPtr dev; 86235c4bbdfSmrg CARD32 barrier_id, event_id; 86335c4bbdfSmrg _X_UNUSED CARD32 device_id; 86435c4bbdfSmrg 86535c4bbdfSmrg barrier_id = info->barrier; 86635c4bbdfSmrg event_id = info->eventid; 86735c4bbdfSmrg 86835c4bbdfSmrg err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess); 86935c4bbdfSmrg if (err != Success) { 87035c4bbdfSmrg client->errorValue = BadDevice; 87135c4bbdfSmrg return err; 87235c4bbdfSmrg } 87335c4bbdfSmrg 87435c4bbdfSmrg err = dixLookupResourceByType((void **) &b, barrier_id, 87535c4bbdfSmrg PointerBarrierType, client, DixReadAccess); 87635c4bbdfSmrg if (err != Success) { 87735c4bbdfSmrg client->errorValue = barrier_id; 87835c4bbdfSmrg return err; 87935c4bbdfSmrg } 88035c4bbdfSmrg 88135c4bbdfSmrg if (CLIENT_ID(barrier_id) != client->index) 88235c4bbdfSmrg return BadAccess; 88335c4bbdfSmrg 88435c4bbdfSmrg 88535c4bbdfSmrg barrier = container_of(b, struct PointerBarrierClient, barrier); 88635c4bbdfSmrg 88735c4bbdfSmrg pbd = GetBarrierDevice(barrier, dev->id); 88835c4bbdfSmrg 88935c4bbdfSmrg if (pbd->barrier_event_id == event_id) 89035c4bbdfSmrg pbd->release_event_id = event_id; 89135c4bbdfSmrg } 89235c4bbdfSmrg 89335c4bbdfSmrg return Success; 89435c4bbdfSmrg} 89535c4bbdfSmrg 89635c4bbdfSmrgBool 89735c4bbdfSmrgXIBarrierInit(void) 89835c4bbdfSmrg{ 89935c4bbdfSmrg int i; 90035c4bbdfSmrg 90135c4bbdfSmrg if (!dixRegisterPrivateKey(&BarrierScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 90235c4bbdfSmrg return FALSE; 90335c4bbdfSmrg 90435c4bbdfSmrg for (i = 0; i < screenInfo.numScreens; i++) { 90535c4bbdfSmrg ScreenPtr pScreen = screenInfo.screens[i]; 90635c4bbdfSmrg BarrierScreenPtr cs; 90735c4bbdfSmrg 90835c4bbdfSmrg cs = (BarrierScreenPtr) calloc(1, sizeof(BarrierScreenRec)); 90935c4bbdfSmrg if (!cs) 91035c4bbdfSmrg return FALSE; 91135c4bbdfSmrg xorg_list_init(&cs->barriers); 91235c4bbdfSmrg SetBarrierScreen(pScreen, cs); 91335c4bbdfSmrg } 91435c4bbdfSmrg 91535c4bbdfSmrg PointerBarrierType = CreateNewResourceType(BarrierFreeBarrier, 91635c4bbdfSmrg "XIPointerBarrier"); 91735c4bbdfSmrg 91835c4bbdfSmrg return PointerBarrierType; 91935c4bbdfSmrg} 92035c4bbdfSmrg 92135c4bbdfSmrgvoid 92235c4bbdfSmrgXIBarrierReset(void) 92335c4bbdfSmrg{ 92435c4bbdfSmrg int i; 92535c4bbdfSmrg for (i = 0; i < screenInfo.numScreens; i++) { 92635c4bbdfSmrg ScreenPtr pScreen = screenInfo.screens[i]; 92735c4bbdfSmrg BarrierScreenPtr cs = GetBarrierScreen(pScreen); 92835c4bbdfSmrg free(cs); 92935c4bbdfSmrg SetBarrierScreen(pScreen, NULL); 93035c4bbdfSmrg } 93135c4bbdfSmrg} 932