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