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