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